/**
  * Получить список сущностей по фильтру
  *
  * @param array $aFilter Фильтр
  * @param string|null $sEntityFull Название класса сущности
  * @return array
  */
 public function GetItemsByFilter($aFilter = array(), $sEntityFull = null)
 {
     if (is_null($aFilter)) {
         $aFilter = array();
     }
     $sEntityFull = $this->_NormalizeEntityRootName($sEntityFull);
     $aFilter = $this->_applyScopes($sEntityFull, $aFilter);
     /**
      * Хук для возможности изменения фильтра
      */
     $this->RunBehaviorHook('module_orm_GetItemsByFilter_before', array('aFilter' => &$aFilter, 'sEntityFull' => $sEntityFull), true);
     // Если параметр #cache указан и пуст, значит игнорируем кэширование для запроса
     if (array_key_exists('#cache', $aFilter) && !$aFilter['#cache']) {
         $aEntities = $this->oMapperORM->GetItemsByFilter($aFilter, $sEntityFull);
     } else {
         $aFilterCache = $aFilter;
         unset($aFilterCache['#with']);
         $sCacheKey = $sEntityFull . '_items_by_filter_' . serialize($aFilterCache);
         $aCacheTags = array($sEntityFull . '_save', $sEntityFull . '_delete');
         $iCacheTime = 60 * 60 * 24;
         // скорее лучше хранить в свойстве сущности, для возможности выборочного переопределения
         // переопределяем из параметров
         if (isset($aFilter['#cache'][0])) {
             $sCacheKey = $aFilter['#cache'][0];
         }
         if (isset($aFilter['#cache'][1])) {
             $aCacheTags = $aFilter['#cache'][1];
         }
         if (isset($aFilter['#cache'][2])) {
             $iCacheTime = $aFilter['#cache'][2];
         }
         if (false === ($aEntities = $this->Cache_Get($sCacheKey))) {
             $aEntities = $this->oMapperORM->GetItemsByFilter($aFilter, $sEntityFull);
             $this->Cache_Set($aEntities, $sCacheKey, $aCacheTags, $iCacheTime);
         }
     }
     /**
      * Если необходимо подцепить связанные данные
      */
     if (count($aEntities) and isset($aFilter['#with'])) {
         if (!is_array($aFilter['#with'])) {
             $aFilter['#with'] = array($aFilter['#with']);
         }
         /**
          * Приводим значение к единой форме ассоциативного массива: array('user'=>array(), 'topic'=>array('blog_id'=>123) )
          */
         func_array_simpleflip($aFilter['#with'], array());
         /**
          * Формируем список примари ключей
          */
         $aEntityPrimaryKeys = array();
         foreach ($aEntities as $oEntity) {
             $aEntityPrimaryKeys[] = $oEntity->_getPrimaryKeyValue();
         }
         $oEntityEmpty = Engine::GetEntity($sEntityFull);
         $aRelations = $oEntityEmpty->_getRelations();
         foreach ($aFilter['#with'] as $sRelationName => $aRelationFilter) {
             if (!isset($aRelations[$sRelationName])) {
                 continue;
             }
             /**
              * Если нужна дополнительная обработка через коллбек
              * Параметр в обработчике должен приниматься по ссылке
              */
             if (isset($aRelationFilter['#callback-filter']) and $aRelationFilter['#callback-filter'] instanceof Closure) {
                 $callback = $aRelationFilter['#callback-filter'];
                 $callback($aEntities, $aRelationFilter);
             }
             /**
              * Если необходимо, то выставляем сразу нужное значение и не делаем никаких запросов
              */
             if (isset($aRelationFilter['#value-set'])) {
                 foreach ($aEntities as $oEntity) {
                     $oEntity->_setData(array($sRelationName => $aRelationFilter['#value-set']));
                 }
                 continue;
             }
             /**
              * Чистим фильтр от коллбека, иначе он может пройти дальше по цепочке вызовов
              */
             unset($aRelationFilter['#callback-filter']);
             $sRelType = $aRelations[$sRelationName]['type'];
             $sRelEntity = $this->Plugin_GetRootDelegater('entity', $aRelations[$sRelationName]['rel_entity']);
             // получаем корневую сущность, без учета наследников
             $sRelKey = $aRelations[$sRelationName]['rel_key'];
             if (!array_key_exists($sRelationName, $aRelations) or !in_array($sRelType, array(EntityORM::RELATION_TYPE_BELONGS_TO, EntityORM::RELATION_TYPE_HAS_ONE, EntityORM::RELATION_TYPE_HAS_MANY, EntityORM::RELATION_TYPE_MANY_TO_MANY))) {
                 throw new Exception("The entity <{$sEntityFull}> not have relation <{$sRelationName}>");
             }
             /**
              * Делаем общий запрос по всем ключам
              */
             $oRelEntityEmpty = Engine::GetEntity($sRelEntity);
             $sRelModuleName = Engine::GetModuleName($sRelEntity);
             $sRelEntityName = Engine::GetEntityName($sRelEntity);
             $sRelPluginPrefix = Engine::GetPluginPrefix($sRelEntity);
             $sRelPrimaryKey = method_exists($oRelEntityEmpty, '_getPrimaryKey') ? $oRelEntityEmpty->_getPrimaryKey() : 'id';
             if ($sRelType == EntityORM::RELATION_TYPE_BELONGS_TO) {
                 /**
                  * Формируем список ключей
                  */
                 $aEntityKeyValues = array();
                 foreach ($aEntities as $oEntity) {
                     $aEntityKeyValues[] = $oEntity->_getDataOne($sRelKey);
                 }
                 $aEntityKeyValues = array_unique($aEntityKeyValues);
                 $sKeyTo = $aRelations[$sRelationName]['rel_key_to'] ?: $sRelPrimaryKey;
                 $aFilterRel = array($sKeyTo . ' in' => $aEntityKeyValues, '#index-from' => $sKeyTo);
                 $aFilterRel = array_merge($aFilterRel, $aRelationFilter);
                 $aRelData = Engine::GetInstance()->_CallModule("{$sRelPluginPrefix}{$sRelModuleName}_get{$sRelEntityName}ItemsByFilter", array($aFilterRel));
             } elseif ($sRelType == EntityORM::RELATION_TYPE_HAS_ONE) {
                 $aFilterRel = array($sRelKey . ' in' => $aEntityPrimaryKeys, '#index-from' => $sRelKey);
                 $aFilterRel = array_merge($aFilterRel, $aRelationFilter, $aRelations[$sRelationName]['filter']);
                 $aRelData = Engine::GetInstance()->_CallModule("{$sRelPluginPrefix}{$sRelModuleName}_get{$sRelEntityName}ItemsByFilter", array($aFilterRel));
             } elseif ($sRelType == EntityORM::RELATION_TYPE_HAS_MANY) {
                 if ($aRelations[$sRelationName]['key_from']) {
                     /**
                      * Формируем список ключей
                      */
                     $aEntityKeyValues = array();
                     foreach ($aEntities as $oEntity) {
                         $aEntityKeyValues[] = $oEntity->_getDataOne($aRelations[$sRelationName]['key_from']);
                     }
                     $aEntityKeyValues = array_unique($aEntityKeyValues);
                 }
                 $aFilterRel = array($sRelKey . ' in' => $aRelations[$sRelationName]['key_from'] ? $aEntityKeyValues : $aEntityPrimaryKeys, '#index-group' => $sRelKey);
                 $aFilterRel = array_merge($aFilterRel, $aRelationFilter, $aRelations[$sRelationName]['filter']);
                 $aRelData = Engine::GetInstance()->_CallModule("{$sRelPluginPrefix}{$sRelModuleName}_get{$sRelEntityName}ItemsByFilter", array($aFilterRel));
             } elseif ($sRelType == EntityORM::RELATION_TYPE_MANY_TO_MANY) {
                 $sEntityJoin = $aRelations[$sRelationName]['join_entity'];
                 $sKeyJoin = $aRelations[$sRelationName]['join_key'];
                 $aFilterAdd = $aRelations[$sRelationName]['filter'];
                 if (!array_key_exists('#value-default', $aRelationFilter)) {
                     $aRelationFilter['#value-default'] = array();
                 }
                 $aFilterRel = array_merge($aFilterAdd, $aRelationFilter);
                 $aRelData = Engine::GetInstance()->_CallModule("{$sRelPluginPrefix}{$sRelModuleName}_get{$sRelEntityName}ItemsByJoinEntity", array($sEntityJoin, $sKeyJoin, $sRelKey, $aEntityPrimaryKeys, $aFilterRel));
                 $aRelData = $this->_setIndexesGroupJoinField($aRelData, $sKeyJoin);
             }
             /**
              * Собираем набор
              */
             foreach ($aEntities as $oEntity) {
                 if ($sRelType == EntityORM::RELATION_TYPE_BELONGS_TO) {
                     $sKeyData = $oEntity->_getDataOne($sRelKey);
                 } elseif (in_array($sRelType, array(EntityORM::RELATION_TYPE_HAS_ONE, EntityORM::RELATION_TYPE_HAS_MANY, EntityORM::RELATION_TYPE_MANY_TO_MANY))) {
                     $sKeyData = $oEntity->_getPrimaryKeyValue();
                 } else {
                     break;
                 }
                 if ($sRelType == EntityORM::RELATION_TYPE_HAS_MANY and $aRelations[$sRelationName]['key_from']) {
                     $sKeyData = $oEntity->_getDataOne($aRelations[$sRelationName]['key_from']);
                 }
                 if (isset($aRelData[$sKeyData])) {
                     $oEntity->_setData(array($sRelationName => $aRelData[$sKeyData]));
                 } elseif (isset($aRelationFilter['#value-default'])) {
                     $oEntity->_setData(array($sRelationName => $aRelationFilter['#value-default']));
                 }
                 if ($sRelType == EntityORM::RELATION_TYPE_MANY_TO_MANY) {
                     // Создаём объекты-обёртки для связей MANY_TO_MANY
                     $oEntity->_setManyToManyRelations(new ORMRelationManyToMany($oEntity->_getRelationsData($sRelationName)), $sRelationName);
                 }
             }
         }
     }
     /**
      * Returns assotiative array, indexed by PRIMARY KEY or another field.
      */
     if (in_array('#index-from-primary', $aFilter, true) || !empty($aFilter['#index-from'])) {
         $aEntities = $this->_setIndexesFromField($aEntities, $aFilter);
     }
     /**
      * Группирует результирующий массив по ключам необходимого поля
      */
     if (!empty($aFilter['#index-group'])) {
         $aEntities = $this->_setIndexesGroupField($aEntities, $aFilter);
     }
     /**
      * Хук для возможности кастомной обработки результата
      */
     $this->RunBehaviorHook('module_orm_GetItemsByFilter_after', array('aEntities' => $aEntities, 'aFilter' => $aFilter, 'sEntityFull' => $sEntityFull), true);
     /**
      * Если запрашиваем постраничный список, то возвращаем сам список и общее количество записей
      */
     if (isset($aFilter['#page'])) {
         if (isset($aFilter['#cache'][0])) {
             /**
              * Задан собственный ключ для хранения кеша, поэтому нужно его сменить для передачи в GetCount*
              * Добавляем префикс 'count_'
              */
             $aFilter['#cache'][0] = 'count_' . $aFilter['#cache'][0];
         }
         return array('collection' => $aEntities, 'count' => $this->GetCountItemsByFilter($aFilter, $sEntityFull));
     }
     return $aEntities;
 }
Beispiel #2
0
 /**
  * Получить список сущностей по фильтру
  *
  * @param array       $aFilter        Фильтр
  * @param string|null $sEntityFull    Название класса сущности
  *
  * @return array
  * @throws Exception
  */
 public function GetItemsByFilter($aFilter = array(), $sEntityFull = null)
 {
     if (is_null($aFilter)) {
         $aFilter = array();
     }
     if (is_null($sEntityFull)) {
         $sEntityFull = E::GetPluginPrefix($this) . 'Module' . E::GetModuleName($this) . '_Entity' . E::GetModuleName(get_class($this));
     } elseif (!substr_count($sEntityFull, '_')) {
         $sEntityFull = E::GetPluginPrefix($this) . 'Module' . E::GetModuleName($this) . '_Entity' . $sEntityFull;
     } elseif (strpos($sEntityFull, '_') && strpos($sEntityFull, 'Module') !== 0 && !strpos($sEntityFull, '_Entity')) {
         if (substr_count($sEntityFull, '_') == 1) {
             list($sModule, $sEntity) = explode('_', $sEntityFull);
             $sEntityFull = E::GetPluginPrefix($this) . 'Module' . $sModule . '_Entity' . $sEntity;
         }
     }
     // Если параметр #cache указан и пуст, значит игнорируем кэширование для запроса
     if (array_key_exists('#cache', $aFilter) && !$aFilter['#cache']) {
         $aEntities = $this->oMapper->GetItemsByFilter($aFilter, $sEntityFull);
     } else {
         $sEntityFullRoot = E::ModulePlugin()->GetRootDelegater('entity', $sEntityFull);
         $sCacheKey = $sEntityFullRoot . '_items_by_filter_' . serialize($aFilter);
         $aCacheTags = array($sEntityFullRoot . '_save', $sEntityFullRoot . '_delete');
         $iCacheTime = 60 * 60 * 24;
         // скорее лучше хранить в свойстве сущности, для возможности выборочного переопределения
         // переопределяем из параметров
         if (isset($aFilter['#cache'][0])) {
             $sCacheKey = $aFilter['#cache'][0];
         }
         if (isset($aFilter['#cache'][1])) {
             $aCacheTags = $aFilter['#cache'][1];
         }
         if (isset($aFilter['#cache'][2])) {
             $iCacheTime = $aFilter['#cache'][2];
         }
         if (false === ($aEntities = E::ModuleCache()->Get($sCacheKey))) {
             $aEntities = $this->oMapper->GetItemsByFilter($aFilter, $sEntityFull);
             E::ModuleCache()->Set($aEntities, $sCacheKey, $aCacheTags, $iCacheTime);
         }
     }
     /**
      * Если необходимо подцепить связанные данные
      */
     if (count($aEntities) && isset($aFilter['#with'])) {
         if (!is_array($aFilter['#with'])) {
             $aFilter['#with'] = array($aFilter['#with']);
         }
         $oEntityEmpty = E::GetEntity($sEntityFull);
         $aRelations = $oEntityEmpty->_getRelations();
         $aEntityKeys = array();
         foreach ($aFilter['#with'] as $sRelationName) {
             $sRelType = $aRelations[$sRelationName][0];
             // получаем корневую сущность, без учета наследников
             $sRelEntity = E::ModulePlugin()->GetRootDelegater('entity', $aRelations[$sRelationName][1]);
             $sRelKey = $aRelations[$sRelationName][2];
             if (!array_key_exists($sRelationName, $aRelations) || !in_array($sRelType, array(EntityORM::RELATION_TYPE_BELONGS_TO, EntityORM::RELATION_TYPE_HAS_ONE))) {
                 throw new Exception("The entity <{$sEntityFull}> not have relation <{$sRelationName}>");
             }
             /**
              * Формируем список ключей
              */
             foreach ($aEntities as $oEntity) {
                 $aEntityKeys[$sRelKey][] = $oEntity->getProp($sRelKey);
             }
             $aEntityKeys[$sRelKey] = array_unique($aEntityKeys[$sRelKey]);
             /**
              * Делаем общий запрос по всем ключам
              */
             $oRelEntityEmpty = E::GetEntity($sRelEntity);
             $sRelModuleName = E::GetModuleName($sRelEntity);
             $sRelEntityName = E::GetEntityName($sRelEntity);
             $sRelPluginPrefix = E::GetPluginPrefix($sRelEntity);
             $sRelPrimaryKey = method_exists($oRelEntityEmpty, '_getPrimaryKey') ? F::StrCamelize($oRelEntityEmpty->_getPrimaryKey()) : 'Id';
             $aCallParams = array($aEntityKeys[$sRelKey]);
             $aRelData = E::GetInstance()->_CallModule("{$sRelPluginPrefix}{$sRelModuleName}_get{$sRelEntityName}ItemsByArray{$sRelPrimaryKey}", $aCallParams);
             /**
              * Собираем набор
              */
             foreach ($aEntities as $oEntity) {
                 if (isset($aRelData[$oEntity->getProp($sRelKey)])) {
                     $oEntity->_setData(array($sRelationName => $aRelData[$oEntity->getProp($sRelKey)]));
                 }
             }
         }
     }
     /**
      * Returns assotiative array, indexed by PRIMARY KEY or another field.
      */
     if (in_array('#index-from-primary', $aFilter) || !empty($aFilter['#index-from'])) {
         $aEntities = $this->_setIndexesFromField($aEntities, $aFilter);
     }
     /**
      * Если запрашиваем постраничный список, то возвращаем сам список и общее количество записей
      */
     if (isset($aFilter['#page'])) {
         return array('collection' => $aEntities, 'count' => $this->GetCountItemsByFilter($aFilter, $sEntityFull));
     }
     return $aEntities;
 }