В этой статье познакомимся с методами xPDO MODX Revolution getObjectGraph и getCollectionGraph. Эти методы преследуют такую же цель, какую имеют getObject и getCollection. Но, в отличие от них, они позволяют получить целую совокупность связанных между собой объектов.


В MODX Revolution получить объекты, связанные между собой некоторыми отношениями, можно следующими способами:

  • getObject (получаем объект) -> getOne или getMany (получаем один или несколько связанных с ним объектов) -> getOne или getMany -> ...
  • getCollection (получаем коллекцию объектов) -> getOne или getMany (получаем один или несколько связанных с каждым из них объектов) -> getOne или getMany -> ...

Но эти действия в MODX Revolution также можно выполнить другим способом, с помощью метода getObjectGraph и getCollectionGraph. Эти методы в отличие от вышепредставленных способов позволяют выполнить все эти операции за один запрос.

Граф и его структура

Методы getCollectionGraph и getObjectGraph отличаются от getCollection и getObject только тем, что они имеют дополнительный параметр (граф). Данный параметр используется для того, чтобы описать, как связанные объекты относятся к базовому классу (задаётся в качестве значения 1 аргумента метода). Указывать граф можно как посредством массива, так в формате JSON.

Структура графа:

// в формате массива
array(
  'псевдонимСвязи'=>array(
    'подПсевдонимСвязи'=>array(),
    'подПсевдонимСвязи'=>array(),
    ...
  ),
  'псевдонимСвязи'=>array(
    'подПсевдонимСвязи'=>array(),
    ...
  ),
  ...
)
// в формате JSON
{"псевдонимСвязи":
  {
    "подПсевдонимСвязи":{},
    "подПсевдонимСвязи":{},
    ...
  },
  {
    "подПсевдонимСвязи":{},
    ...
  },
  ...
}  

Синтаксис метода getCollectionGraph

Метод getCollectionGraph имеет следующий синтаксис:

getCollectionGraph($className, $graph, $criteria, $cacheFlag)

// $className - имя базового класса (объекта)
// $graph - граф, в формате JSON или в виде массива. Задаёт связи между объектами относительно базового класса.
// $criteria (не обязательный) - критерий, который может быть задан посредством значения первичного ключа базового объекта, массива или в формате xPDOCriteria.
// $cacheFlag (не обязательный) - указывает, следует ли кэшировать результат. Кроме true или false принимает также числовое значение (количество секунд, на которые результат необходимо сохранить в кэш).

В качестве результата xPDO метод getCollectionGraph возвращает коллекцию связанных объектов или пустой массив (в случае не удачи).

После получения данных, доступ к связанным объектам, указанных в $graph осуществляется с помощью оператора ->. Кроме использования оператора "добраться" до связанных объектов можно также с помощью метода getOne или getMany (выбор метода зависит от мощности отношения). При этом данные методы не создают никакие дополнительные запросы, т.к. данные объекты уже загружены getCollectionGraph.

Данное условие конечно выполняется только для тех связанных объектов, которые вы указали в графе метода getCollectionGraph.

Также обратите своё внимание на то, что в методе getCollectionGraph основной объект должен быть определён именем класса, а связанные с ним объекты (в графе $graph) - посредством названий отношений.

Критерий ($criteria) в методе getCollectionGraph является не обязательным аргументом. Если его не указать, то метод getCollectionGraph возвратит вам не только полную коллекцию базовых объектов, но и все другие, связанные с ними объекты, в соответствии с указанным графом. Если вам этого не нужно, то обязательно задавайте критерий, т.е. ограничивайте выборку только получением необходимых объектов.

Пример использования метода getCollectionGraph

Рассмотрим пример использования xPDO метода getCollectionGraph для выбора связанных объектов.

Например, выберем ресурсы (modResource) и связанные с ними объекты (modUser, modUserProfile, modTemplateVarResource и modTemplateVar).

Перед тем как создавать граф связей между объектами, необходимо определиться с базовым классом. В этом примере в качестве базы будет выступать класс modResource.

Изображение графа, который будем использовать для выбора связанных объектов:

Пример графа связанных объектов для xPDO метода getCollectionGraph
Пример графа связанных объектов для xPDO метода getCollectionGraph
  • 1->2 - PublishedBy - пользователь , который опубликовал ресурс (объект modUser).
  • 2->3 - Profile - профиль пользователя, который опубликовал ресурс (объект modUserProfile).
  • 1->4 - TemplateVarResources - значения TV-переменных ресурса (объект modTemplateVarResource).
  • 4->5 - TemplateVar - имя TV-переменной (объект modTemplateVar).
<?php
// получим ресурсы и связанные с ними объекты c Dig or Die
$resources = $modx->getCollectionGraph('modResource', '{
  "TemplateVarResources":{ "TemplateVar":{} },
  "PublishedBy":{ "Profile":{} } }');
// переменная, для хранения результата
$output = '';
// переберём все ресурсы
foreach ($resources as $recource) {
  if (is_object($recource)) {
    // получим заголовок ресурса
    $output .= $recource->get('pagetitle');
    // получим имя (username) пользователя
    if ($recource->PublishedBy) {
      $username = $recource->PublishedBy->get('username');
      if ($recource->PublishedBy->Profile) {
        // получим полное имя пользователя          
        $fullname = $recource->PublishedBy->Profile->get('fullname');
      }
    }
    // добавим к выводу данные о пользователе, который опубликовал ресурс
    $output .= '<br>Ресурс опубликовал: '.$username.'('.$fullname.')';
    $output .= '<ul>';
    // переберём все TV поля ресурса
    foreach ($recource->TemplateVarResources as $tv) {
      // получим имя tv-поля у объекта, связанного с modTemplateVarResource отношением TemplateVar
      $nametv = $tv->TemplateVar->get('name');
      // получим значение TV-переменной ресурса
      $valuetv = $tv->get('value');
      $output .= '<li>'.$nametv.' = '.$valuetv.'</li>';
    }
    $output .= '</ul>';
  }
  $output .= '<hr>';
}
return $output;

Синтаксис метода getObjectGraph

Метод getObjectGraph в плане синтаксиса ни чем не отличается от метода getCollectionGraph за исключением того, что он возвращает не коллекцию базовых объектов, а один объект. Если метод getObjectGraph не может получить объект, то он возвращает значение null.

Пример использования метода getObjectGraph

Рассмотрим задачу, в которой определим все ресурсы, который опубликова пользователь с некоторым id. Кроме этого, эти ресурсы ещё должны иметь в качестве родителя ресурс с id, равным 19.

<?php
// id пользователя
$iduser = 1;
// id родительского ресурса
$parent = 19;

// создание условия для выборки записей
$criteria = $modx->newQuery('modUser');
$criteria->bindGraph('{"PublishedResources":{"Parent":{}},"Profile":{}}');
$criteria->where(array(
  'modUser.id:=' => $iduser,
  'PublishedResources.parent:=' => $parent
));
// получение объекта modUser и связанных с ним других объектов
$user = $modx->getObjectGraph('modUser', '{"PublishedResources":{"Parent":{}},"Profile":{}}',$criteria);
// переменная, для хранения результата ,  "Parent":{}  "Profile":{} 
$output = '';
// если результат является объектом, то...
if (is_object($user)) {
  
  if ($user->Profile) {
    foreach($user->PublishedResources as $resource) {
      $output .= 'Ресурсы опубликованные пользователем '.$user->Profile->get('fullname').' и расположенные в каталоге '. $resource->Parent->get('pagetitle').':<br>';
      break;
    } 
  }
  // переберём все ресурсы
  foreach ($user->PublishedResources as $resource) {
    // получим заголовок ресурса
    $output .= $resource->get('pagetitle').'<br>';
  }
}
return $output;

Внимание: При создании критерия, связанные объекты были добавлены в запрос с помощью метода bindGraph.

Рассмотрим ещё один способ получения связанных объектов. Для этого в вышепредставленном сниппете изменим способ получения объектов, а заменим оператор -> на метод getOne или getMany (в зависимости от мощности отношения):

//...
if ($user->getOne('Profile')) {
  foreach($user->getMany('PublishedResources') as $resource) {
    $output .= 'Ресурсы опубликованные пользователем '.$user->getOne('Profile')->get('fullname').' и расположенные в каталоге '. $resource->getOne('Parent')->get('pagetitle').':<br>';
    break;
  } 
}
// переберём все ресурсы
foreach ($user->getMany('PublishedResources') as $resource) {
  // получим заголовок ресурса
  $output .= $resource->get('pagetitle').'<br>';
}