public static function load($parent, $childs, $keyField, array $ids, $foreignKey = null)
 {
     self::parseItemStatement($parent, $parentItemName, $parentFields);
     Lms_Item::initStructure(Lms_Item::getClassName($parentItemName));
     $struct = Lms_Item::getStruct($parentItemName);
     if (count($parentFields)) {
         if ($foreignKey && !in_array($foreignKey, $parentFields)) {
             array_unshift($parentFields, $foreignKey);
         }
         foreach ($struct->getPk() as $fieldName) {
             if (!in_array($fieldName, $parentFields)) {
                 array_unshift($parentFields, $fieldName);
             }
         }
     }
     if (!$foreignKey && $struct->hasIndex($keyField)) {
         $foreignKey = $keyField;
     }
     $newScalarPKs = self::_exec($parentItemName, $parentFields, $keyField, $ids, $foreignKey);
     foreach ($childs as $child) {
         self::parseItemStatement($child, $childItemName, $childFields);
         Lms_Item::initStructure(Lms_Item::getClassName($childItemName));
         $relation = Lms_Item_Relations::get($parentItemName, $childItemName);
         if (!$relation) {
             $linkatorItemName = Lms_Item::getLinkator($parentItemName, $childItemName);
             $subRelation = Lms_Item_Relations::get($parentItemName, $linkatorItemName);
             $newKeys = array_unique(Lms_Item_Store::getAllFieldValues($newScalarPKs, Lms_Item::getTableName($parentItemName), $subRelation['parent_key']));
             self::load($linkatorItemName, array($child), $subRelation['foreign_key'], $newKeys, $subRelation['foreign_key']);
         } else {
             if (count($childFields)) {
                 if ($relation && !in_array($relation['foreign_key'], $childFields)) {
                     array_unshift($childFields, $relation['foreign_key']);
                 }
                 $struct = Lms_Item::getStruct($childItemName);
                 foreach ($struct->getPk() as $fieldName) {
                     if (!in_array($fieldName, $childFields)) {
                         array_unshift($childFields, $fieldName);
                     }
                 }
             }
             $newKeys = array_unique(Lms_Item_Store::getAllFieldValues($newScalarPKs, Lms_Item::getTableName($parentItemName), $relation['parent_key']));
             self::_exec($childItemName, $childFields, $relation['foreign_key'], $newKeys, $relation['foreign_key']);
         }
     }
 }
 /**
  * Возвращает элементы/аттрибуты указанные в пути xpath
  * 
  * @param string $xpath
  * @return mixed
  */
 public function getChilds($xpath)
 {
     if (!$xpath) {
         return $this;
     }
     //разбор запроса
     $xpaths = explode("/", $xpath, 2);
     $xpathCurrentStep = array_shift($xpaths);
     $xpathNextStep = count($xpaths) ? array_shift($xpaths) : null;
     $predicat = array();
     if (preg_match('{^(.*?)\\[(.*?)\\]$}', $xpathCurrentStep, $matches)) {
         $xpathCurrentStep = $matches[1];
         $predicat[] = $matches[2];
     }
     //запрашивается поле
     if (0 === strpos($xpathCurrentStep, '@')) {
         $xpathCurrentStep = substr($xpathCurrentStep, 1);
         return call_user_func(array($this, "get{$xpathCurrentStep}"));
     }
     //запрашивается зависимый объект подразумевая использование линкатора
     $thisItemName = Lms_Item::getItemName($this);
     $relation = Lms_Item_Relations::get($thisItemName, $xpathCurrentStep);
     if (!$relation) {
         $linkator = Lms_Item::getLinkator($thisItemName, $xpathCurrentStep);
         return $this->getChilds("{$linkator}/{$xpath}");
     }
     //запрашивается зависимый объект имеющий прямую связь
     $subTableName = Lms_Item::getTableName($xpathCurrentStep);
     $foreignKey = $relation['foreign_key'];
     $parentKeyValue = $this->__getValue($relation['parent_key']);
     Lms_Item::initStructure(Lms_Item::getClassName($xpathCurrentStep));
     if (Lms_Item_Relations::ONE == $relation['type']) {
         //связь 1 к 1
         if (Lms_Item::getSimplePk($xpathCurrentStep) == $foreignKey) {
             try {
                 $item = Lms_Item::create($xpathCurrentStep, $parentKeyValue);
                 return $item->getChilds($xpathNextStep);
             } catch (Lms_Item_RecordNotExistsException $e) {
                 return null;
             }
         } else {
             $this->completeIndexValues($xpathCurrentStep, $foreignKey, $parentKeyValue);
             $subPkValues = Lms_Item_Store::getIndexedValues($subTableName, $foreignKey, $parentKeyValue);
             if (count($subPkValues)) {
                 $subPkValue = reset($subPkValues);
                 try {
                     $item = Lms_Item::create($xpathCurrentStep, $subPkValue);
                     return $item->getChilds($xpathNextStep);
                 } catch (Lms_Item_RecordNotExistsException $e) {
                     return null;
                 }
             }
         }
     } else {
         //связь 1 ко многим
         $this->completeIndexValues($xpathCurrentStep, $foreignKey, $parentKeyValue);
         $result = array();
         $subPkValues = Lms_Item_Store::getIndexedValues($subTableName, $foreignKey, $parentKeyValue);
         foreach ($subPkValues as $subPkValue) {
             $item = Lms_Item::create($xpathCurrentStep, $subPkValue);
             $result[] = $item->getChilds($xpathNextStep);
         }
         $this->performHandlers($result, $predicat);
         return $result;
     }
 }
 public static function getLinkator()
 {
     $items = func_get_args();
     if (count($items) == 1 && is_array($items[0])) {
         //входящие параметры переданы массивом
         $items = $items[0];
     }
     $relations = array();
     foreach ($items as $key => $item) {
         $itemName = self::getItemName($item);
         $items[$key] = $itemName;
         self::initStructure(self::getClassName($itemName));
         $relations[] = array_keys(Lms_Item_Relations::getAll($itemName));
     }
     //Находим место пересечения связей
     $intersection = call_user_func_array('array_intersect', $relations);
     if (count($intersection) == 0) {
         throw new Lms_Item_Exception("Relation between " . implode(', ', $items) . " not found");
     }
     if (count($intersection) > 1) {
         throw new Lms_Item_Exception("Ambiguity relations between " . implode(', ', $items));
     }
     //Получаем имя линкатора
     $linkatorName = reset($intersection);
     return $linkatorName;
 }