diff --git a/engine/classes/EntityORM.class.php b/engine/classes/EntityORM.class.php index 3cd9f1af..14bc6b27 100644 --- a/engine/classes/EntityORM.class.php +++ b/engine/classes/EntityORM.class.php @@ -25,6 +25,7 @@ abstract class EntityORM extends Entity { const RELATION_TYPE_HAS_MANY='has_many'; const RELATION_TYPE_HAS_ONE='has_one'; const RELATION_TYPE_MANY_TO_MANY='many_to_many'; + const RELATION_TYPE_TREE='tree'; protected $aRelations=array(); protected $aRelationsData=array(); @@ -77,6 +78,70 @@ abstract class EntityORM extends Entity { public function Reload() { return $this->_Method(__FUNCTION__); } + + public function getChildren() { + if(in_array(self::RELATION_TYPE_TREE,$this->aRelations)) { + return $this->_Method(__FUNCTION__ .'Of'); + } + return $this->__call(__FUNCTION__); + } + + public function getDescendants() { + if(in_array(self::RELATION_TYPE_TREE,$this->aRelations)) { + return $this->_Method(__FUNCTION__ .'Of'); + } + return $this->__call(__FUNCTION__); + } + + public function getParent() { + if(in_array(self::RELATION_TYPE_TREE,$this->aRelations)) { + return $this->_Method(__FUNCTION__ .'Of'); + } + return $this->__call(__FUNCTION__); + } + + public function getAncestors() { + if(in_array(self::RELATION_TYPE_TREE,$this->aRelations)) { + return $this->_Method(__FUNCTION__ .'Of'); + } + return $this->__call(__FUNCTION__); + } + + public function setChildren($aChildren=array()) { + if(in_array(self::RELATION_TYPE_TREE,$this->aRelations)) { + $this->aRelationsData['children'] = $aChildren; + } else { + $aArgs = func_get_args(); + return $this->__call(__FUNCTION__,$aArgs); + } + } + + public function setDescendants($aDescendants=array()) { + if(in_array(self::RELATION_TYPE_TREE,$this->aRelations)) { + $this->aRelationsData['descendants'] = $aDescendants; + } else { + $aArgs = func_get_args(); + return $this->__call(__FUNCTION__,$aArgs); + } + } + + public function setParent($oParent=null) { + if(in_array(self::RELATION_TYPE_TREE,$this->aRelations)) { + $this->aRelationsData['parent'] = $oParent; + } else { + $aArgs = func_get_args(); + return $this->__call(__FUNCTION__,$aArgs); + } + } + + public function setAncestors($oParent=null) { + if(in_array(self::RELATION_TYPE_TREE,$this->aRelations)) { + $this->aRelationsData['ancestors'] = $oParent; + } else { + $aArgs = func_get_args(); + return $this->__call(__FUNCTION__,$aArgs); + } + } protected function _Method($sName) { $sModuleName=Engine::GetModuleName($this); @@ -85,10 +150,7 @@ abstract class EntityORM extends Entity { return Engine::GetInstance()->_CallModule("{$sPluginPrefix}{$sModuleName}_{$sName}{$sEntityName}",array($this)); } - - public function _getRelations() { - return $this->aRelations; - } + public function _setData($aData) { if(is_array($aData)) { @@ -102,6 +164,18 @@ abstract class EntityORM extends Entity { } } + public function _getRelations() { + return $this->aRelations; + } + + public function _getRelationsData() { + return $this->aRelationsData; + } + + public function _setRelationsData($aData) { + $this->aRelationsData=$aData; + } + public function __call($sName,$aArgs) { $sType=substr($sName,0,strpos(func_underscore($sName),'_')); if (!strpos($sName,'_') and in_array($sType,array('get','set','reload'))) { diff --git a/engine/classes/ModuleORM.class.php b/engine/classes/ModuleORM.class.php index e29e10ba..fa7f4bc3 100644 --- a/engine/classes/ModuleORM.class.php +++ b/engine/classes/ModuleORM.class.php @@ -81,13 +81,141 @@ abstract class ModuleORM extends Module { if($sPrimaryKeyValue=$oEntity->_getDataOne($sPrimaryKey)) { if($oEntityNew=$this->GetByFilter(array($sPrimaryKey=>$sPrimaryKeyValue),Engine::GetEntityName($oEntity))) { $oEntity->_setData($oEntityNew->_getData()); + $oEntity->_setRelationsData(array()); return $oEntity; } } } return false; } + + protected function _GetChildrenOfEntity($oEntity) { + if(in_array(EntityORM::RELATION_TYPE_TREE,$oEntity->_getRelations())) { + $aRelationsData=$oEntity->_getRelationsData(); + if(array_key_exists('children',$aRelationsData)) { + $aChildren=$aRelationsData['children']; + } else { + $aChildren=array(); + if($sPrimaryKey=$oEntity->_getPrimaryKey()) { + if($sPrimaryKeyValue=$oEntity->_getDataOne($sPrimaryKey)) { + $aChildren=$this->GetItemsByFilter(array('parent_id'=>$sPrimaryKeyValue),Engine::GetEntityName($oEntity)); + } + } + } + if(is_array($aChildren)) { + $oEntity->setChildren($aChildren); + return $aChildren; + } + } + return false; + } + + + protected function _GetParentOfEntity($oEntity) { + if(in_array(EntityORM::RELATION_TYPE_TREE,$oEntity->_getRelations())) { + $aRelationsData=$oEntity->_getRelationsData(); + if(array_key_exists('parent',$aRelationsData)) { + $oParent=$aRelationsData['parent']; + } else { + $oParent='%%NULL_PARENT%%'; + if($sPrimaryKey=$oEntity->_getPrimaryKey()) { + if($sParentId=$oEntity->getParentId()) { + $oParent=$this->GetByFilter(array($sPrimaryKey=>$sParentId),Engine::GetEntityName($oEntity)); + } + } + } + if(!is_null($oParent)) { + $oEntity->setParent($oParent); + return $oParent; + } + } + return false; + } + + + protected function _GetAncestorsOfEntity($oEntity) { + if(in_array(EntityORM::RELATION_TYPE_TREE,$oEntity->_getRelations())) { + $aRelationsData=$oEntity->_getRelationsData(); + if(array_key_exists('ancestors',$aRelationsData)) { + $aAncestors=$aRelationsData['ancestors']; + } else { + $aAncestors=array(); + $sParentId=$oEntity->getParentId(); + while($sParentId > 0) { + $oEntity=$oEntity->getParent(); + $aAncestors[]=$oEntity; + $sParentId=$oEntity->getParentId(); + } + } + if(is_array($aAncestors)) { + $oEntity->setAncestors($aAncestors); + return $aAncestors; + } + } + return false; + } + + + protected function _GetDescendantsOfEntity($oEntity) { + if(in_array(EntityORM::RELATION_TYPE_TREE,$oEntity->_getRelations())) { + $aRelationsData=$oEntity->_getRelationsData(); + if(array_key_exists('descendants',$aRelationsData)) { + $aDescendants=$aRelationsData['descendants']; + } else { + $aDescendants=array(); + if($aChildren=$oEntity->getChildren()) { + $aDescendants=$aChildren; + $aTree=self::buildTree($aChildren); + foreach($aTree as $aItem) { + $aDescendants[] = $aItem['entity']; + } + } + } + if(is_array($aDescendants)) { + $oEntity->setDescendants($aDescendants); + return $aDescendants; + } + } + return false; + } + + + public function LoadTree($sEntityFull=null) { + if (is_null($sEntityFull)) { + $sEntityFull=Engine::GetPluginPrefix($this).'Module'.Engine::GetModuleName($this).'_Entity'.Engine::GetModuleName(get_class($this)); + } elseif (!substr_count($sEntityFull,'_')) { + $sEntityFull=Engine::GetPluginPrefix($this).'Module'.Engine::GetModuleName($this).'_Entity'.$sEntityFull; + } + if($oEntityDefault=Engine::GetEntity($sEntityFull)) { + if(in_array(EntityORM::RELATION_TYPE_TREE,$oEntityDefault->_getRelations())) { + if($sPrimaryKey=$oEntityDefault->_getPrimaryKey()) { + if($aItems=$this->GetItemsByFilter(array(),$sEntityFull)) { + $aItemsById = array(); + $aItemsByParentId = array(); + foreach($aItems as $oEntity) { + $oEntity->setChildren(array()); + $aItemsById[$oEntity->_getDataOne($sPrimaryKey)] = $oEntity; + if(empty($aItemsByParentId[$oEntity->getParentId()])) { + $aItemsByParentId[$oEntity->getParentId()] = array(); + } + $aItemsByParentId[$oEntity->getParentId()][] = $oEntity; + } + foreach($aItemsByParentId as $iParentId=>$aItems) { + if($iParentId > 0) { + $aItemsById[$iParentId]->setChildren($aItems); + foreach($aItems as $oEntity) { + $oEntity->setParent($aItemsById[$iParentId]); + } + } + } + return $aItemsByParentId[0]; + } + } + } + } + return false; + } public function GetByFilter($aFilter=array(),$sEntityFull=null) { if (is_null($sEntityFull)) { @@ -225,6 +353,27 @@ abstract class ModuleORM extends Module { if (preg_match("@^reload([\w]+)$@i",$sName,$aMatch)) { return $this->_ReloadEntity($aArgs[0]); } + + if (preg_match("@^getchildrenof([\w]+)$@i",$sName,$aMatch)) { + return $this->_GetChildrenOfEntity($aArgs[0]); + } + + if (preg_match("@^getparentof([\w]+)$@i",$sName,$aMatch)) { + return $this->_GetParentOfEntity($aArgs[0]); + } + + if (preg_match("@^getdescendantsof([\w]+)$@i",$sName,$aMatch)) { + return $this->_GetDescendantsOfEntity($aArgs[0]); + } + + if (preg_match("@^getancestorsof([\w]+)$@i",$sName,$aMatch)) { + return $this->_GetAncestorsOfEntity($aArgs[0]); + } + + if (preg_match("@^loadtreeof([\w]+)$@i",$sName,$aMatch)) { + $sEntityFull = array_key_exists(1,$aMatch) ? $aMatch[1] : null; + return $this->LoadTree($sEntityFull); + } $sNameUnderscore=func_underscore($sName); $iEntityPosEnd=strlen($sNameUnderscore)-1; @@ -287,5 +436,22 @@ abstract class ModuleORM extends Module { return $this->oEngine->_CallModule($sName,$aArgs); } + static function buildTree($aItems,$aList=array(),$iLevel=0) { + foreach($aItems as $oEntity) { + $aChildren=$oEntity->getChildren(); + $bHasChildren = !empty($aChildren); + $sEntityId = $oEntity->_getDataOne($oEntity->_getPrimaryKey()); + $aList[$sEntityId] = array( + 'entity' => $oEntity, + 'parent_id' => $oEntity->getParentId(), + 'children_count' => $bHasChildren ? count($aChildren) : 0, + 'level' => $iLevel, + ); + if($bHasChildren) { + $aList=self::buildTree($aChildren,$aList,$iLevel+1); + } + } + return $aList; + } } ?> \ No newline at end of file