MODX. Объекты xPDO и часто используемые конструкции

xPDO — технология лежащая в основе API MODX. Подробнее о различиях PDO и xPDO можно узнать в статье «xPDO, сравнение с PDO и PHP»

Официальный справочник API MODX

Объекты xPDO и часто используемые конструкции

Текущий ресурс / пользователь

$currentResource = $modx->resource;
$currentUser = $modx->user; 

Если пользователь не авторизован, он будет обозначен как “anonymous”.

Поля ресурсов доступны при помощи методов get() или getContent()

$UserID = $modx->user->get('id');
$intro = $modx->resource->get('introtext');
$content = $modx->resource->getContent();

В тексте полученном с помощью get('content') или getContent() теги или любой другой код обработан не будет. 

Текущий ресурс всегда доступен как $modx->resource, но не стоит это использовать для модификации, т.к. это лишь его копия.

Поиск объектов

В MODX Revo все объекты можно получить с помощью метода $modx->getObject():

$modx->getObject($className, $criteria, $cacheFlag)
  • $className — имя объекта;
  • $criteria (не обязательный) — критерий;
  • $cacheFlag (не обязательный) — флаг, отвечающий за кэширование (по умолчанию true).

Примеры использования:

/* Получение объекта по имени */
$object = $modx->getObject('objectClassName',array('name' => 'objectName' ));

/* По ID номеру */
$object = $modx->getObject('objectClassName',$objectId);

/* Получение чанка */
$chunk = $modx->getObject('modChunk',array('name' => 'chunkName' ));

/* Получение чанка по ID */
$chunk = $modx->getObject('modChunk',$chunkId);

Первый параметр objectClassName — название класса. Список классов:

  • modResource — обращение к ресурсу (также с его помощью можно получить отдельные ресурсы, такие как: документ, ссылки и статичные ресурсы);
  • modChunk — обращение к чанку;
  • modSnippet — обращение к сниппету;
  • modPlugin — обращение к плагину;
  • modTemplate — обращение к шаблону;
  • modTemplateVar — обращение к дополнительному полю;
  • modTemplateVarResource — обращение к дополнительному полю.
  • Подробнее о дополнительных полях.

    Таблица modx_site_tmplvar_contentvalues . Доступные поля:
    • tmplvarid — числовое поле, содержащее id дополнительного поля (TV).
    • contentid — числовое поле, содержащее id ресурса к которому привязано данное значение поля.
    • value — текстовое поле, содержащее значение поля.
    Агрегатные связи:
    • modTemplateVar (псевдоним TemplateVar). Связь объектов записывается в поля tmplvarid и id.
    • modResource (псевдоним Resource). Связь объектов записывается в поля contentid и id.
  • modCategory — обращение к категории;
  • modDocument — обращение к документу;
  • modWeblink — обращение к ссылке;
  • modSymlink — обращение к симлинку на ресурс;
  • modStaticResource — обращение к статичному ресурсу.

Объектная модель MODX от Ильи Уткина

Второй параметр — идентификатор объекта, или заданный критерий.

Получить один объект с заданными параметрами можно так 

$document = $modx->getObject('modResource',array(
    'published' => 1,
    'pagetitle' => 'Хитрый заголовок'
));

Обратите внимание, что для получения названия ресурса используется pagetitle, а для получения названия чанка или сниппета — name.

Удобочитаемая запись того же действия

$name = 'modResource';
$criteria = array(
    'published' => 1,
    'pagetitle' => 'Хитрый заголовок'
)
$document = $modx->getObject($name,$criteria)

Для получения списка объектов используется метод getCollection() 

$docArray = $modx->getCollection('modResource',array(
    'published' => 1,
    'searchable' => 1
));

getCollection() возвращает не PHP массив, а массив объектов, чтобы получить PHP массив, надо воспользоваться методом toArray() 

$phpArray = $object->toArray();

Также можно использовать метод объекта get(), чтобы получить отдельное поле

$resource->get('pagetitle');

Так же как и с getObject() можно использовать запросы в критериях методов getCollection() и getMany()

$tvCollection = $modx->getCollection('modTemplateVar', 
"`name` IN ('" . implode("','", array('footer', 'header')) . "')");

Для получения родственных объектов связанных с одним конкретным объектом можно использовать метод getMany() 

$tvs = $template->resource->getMany('TemplateVars');

Также, можно получить потомков 

$children = $resource->getMany('Children');

getObject() и getOne() вернут null если запрошенный объект не будет найден, а getMany() и getCollection() вернут пустой массив. 

Получение полей объекта

После получения ресурса можно извлечь одно из его полей, используя имя поля

$resource = $modx->getObject('modResource',12);
$longTitle = $resource->get('longtitle');

Если надо вывести поле, можно воспользоваться следующим фрагментом кода

return $resource->get('pagetitle');

Создание отдельных запросов

Полученный при помощи getObgect() объект занимает много памяти. Это оправданно если в коде будут использоваться различные данные из объекта. Если же надо получить данные из небольшого количества столбцов, лучше использовать метод newQuery().

$modx->newQuery($class, $criteria, $cacheFlag)
// $class — имя класса, для которого необходимо создать запрос.
// $criteria (необязательный) — используется для указания критерия.
// $cacheFlag — указывает, надо ли кэшировать этот запрос.

Запрос на получение pagetitle из ресурса родителя:

$parentObj = $modx->newQuery('modResource', array('id' => $parentID));
$parentObj->select('pagetitle');
if ($parentObj->prepare() && $parentObj->stmt->execute()) {
   $parentTitle = $parentObj->stmt->fetchAll(PDO::FETCH_ASSOC);
   $parentTitle = $TVvalue[0][value];
} 

Также есть такой метод, но использование $modx->getValue замедляет работу скрипта, в отличие от выборки через fetchAll:

$parentObj = $modx->newQuery('modResource', array('id' => $parentID));
$parentObj->select('pagetitle');
$parentTitle = $modx->getValue($parentObj->prepare());

Запрос на получение значения из связанного с ресурсом MIGX TV поля:

$currObj = $modx->newQuery('modTemplateVarResource', array('tmplvarid' => 11, 'contentid' => $parentID));
$currObj->select('value');
if ($currObj->prepare() && $currObj->stmt->execute()) {
    $output = $currObj->stmt->fetchAll(PDO::FETCH_ASSOC);
    $output = $modx->fromJSON($output[0][value]);
} 

или

$currObj = $modx->newQuery('modTemplateVarResource', array('tmplvarid' => 11, 'contentid' => $parentID));
$currObj->select('value');
$output = $modx->fromJSON($modx->getValue($currObj->prepare()));

Можно запросить данные из нескольких столбцов:

$parentObj = $modx->newQuery('modResource', array('id' => $parentID));
$parentObj->select('pagetitle,alias');
if ($parentObj->prepare() && $parentObj->stmt->execute()) {
   $resOptions = $parentObj->stmt->fetchAll(PDO::FETCH_ASSOC);
   $parentTitle = $resOptions[0][pagetitle];
   $parentAlias = $resOptions[0][alias];
} 

Увидеть SQL запрос который генерирует query можно при помощи команды toSql: 

$query->prepare();
$sqlString = $query->toSql();

Получение коллекции объектов

Для получения коллекции (массива) объектов используется метод getCollection, он принимает те же аргументы, что и метод getObject.

$modx->getCollection($className, $criteria, $cacheFlag)
  • $className — имя объекта;

  • $criteria (не обязательный) — критерий;

  • $cacheFlag (не обязательный) — флаг, отвечающий за кэширование (по умолчанию true).

Получение системных настроек

$setting = $modx->getOption('site_start');

Может применяться для определения сниппета листинга, через который надо выводить элементы при написании другого сниппета:

// Получаем название сниппета через который надо выводить ресурсы
$getResourcesSnippet = $modx->getOption('getResourcesSnippet', $scriptProperties, 'pdoResources');

// Проверяем существование этого сниппета
$getResourcesExists = $modx->getCount('modSnippet', array('name' => $getResourcesSnippet));
if ($getResourcesExists == 0) return 'getResources not found';

// возвращаем результат с использованием сниппета
return $modx->runSnippet($getResourcesSnippet, $properties);

Работа с плейсхолдерами

// установка обычного плейсхолдера строкой
$value = $modx->setPlaceholder('name', 'value');
// установка обычного плейсхолдера переменной
$value = $modx->setPlaceholder('name', $value);

// установка плейсхолдера в качестве массива
$modx->toPlaceholder('name', 'value', ['prefix'], ['separator'], [restore.]); 

// установка коллекции плейсхолдеров хранящихся в качестве массива
toPlaceholders(array/object $placeholders, ['prefix'], ['separator'], [restore])

// получение обычного плейсхолдера
$value = $modx->getPlaceholder('name');

// получение плейсхолдера в виде массива
$val = $modx->getPlaceholder('restore.name');

// удаление плейсхолдера
$modx->unsetPlaceholder('goodies.berry');

// множественное удаление плейсхолдеров
// можно указывать 1 плейсхолдер
$modx->unsetPlaceholders('restore.name');

// можно указывать элементы массива
$modx->unsetPlaceholders(
   array('restore.name1','restore.name2')
);

// можно указывать пространство имен 'restore.'
$modx->unsetPlaceholders('restore.');

Подробнее о плейсхолдерах.

Загрузка экземпляра класса

$modx->getService('error', 'error.modError');

Использование $object->getOne() и $object->getMany() 

Объекты связанные со структурой MODX можно вывести используя методы getOne() и getMany(). В то время как функция get() будет извлекать определенное поле объекта, функция getOne() вернет весь объект. getMany(), соответственно, вернет массив объектов.

Получение родительского ресурса как объекта

$parentResource = $resource->getOne('Parent');

Получение полей объекта User, вывод значений профиля пользователя

Для получения объекта «user» используется та же конструкция

$user = $resource->getOne('CreatedBy');

или, для текущего ресурса 

$user = $modx->resource->getOne('CreatedBy');

Объект «user» содержит только поля ID, Имя и хеш пароля. Для получения остальных полей, надо извлечь объект modUserProfile связанный с этим пользователем

$user->getOne('Profile');

После получения профиля, можно использовать его с помощью метода get() для получения любого поля ресурса 

$profile->get('fullname');

Дополнительные поля (Template Variables, TV)

Подробнее о дополнительных полях (переменных шаблона).

Получить значение TV поля текущего ресурса можно с помощью метода getTVValue() :

$val = $modx->resource->getTVValue('name_of_tv');
$val = $modx->resource->getTVValue($id); // ID TV поля, не документа

или так, если нужно значение конкретной страницы: 

$resource = $modx->getObject('modResource',array('pagetitle'=>'SomePage'));
$val = $resource->getTVValue('name_of_tv');
$val = $resource->getTVValue($id); // ID TV поля, не документа

Получение значения поля с помощью getObject:

/* Получаем TV */
$tv = $modx->getObject('modTemplateVar',array('name'=>'MyTV'));

/* Получаем строку содержимого TV */
$rawValue = $tv->getValue($id);

/* Получаем обработанное содержимое TV */
$processedValue = $tv->renderOutput($id);

Получение html из чанка с помощью getChunk()

Метод getChunk() помогает получить html информацию из заранее созданного чанка. Это необходимо для избежания ситуаций когда php код используется совместно с html вставками. Синтаксис метода:

string getChunk (string $chunkName, [array $properties = array ()])

// $properties обычно представляет собой стандартный ассоциативный массив, например
$properties = array('key' => 'value');

// значение может быть переменной
$properties = array('key' => $value);

// получить данные внутри чанка можно с помощью установленного плейсхолдера 
// [[+key]]

$properties также может быть более глубоко вложенным массивом:

$properties = array(
    'user' => array('id' => 1),
    'document' => array('id' => 27)
);
// или:
$properties['user']['id'] = 1;
$properties['document']['id'] = 27;

// Получатся следующие плейсхолдеры:
// [[+user.id]]
// [[+document.id]]

Использование toArray() с getChunk()

В MODX легко разделять отображаемую информацию. Один из наиболее простых способов — создать плейсхолдер в чанке, а затем отправить его, вызовом getChunk().

Метод toArray() работает с любыми объектами MODX, но чаще всего используется с ресурсами и пользователями. Он создаёт ассоциативный PHP массив из полей объекта. В последствии, этот массив может быть использован как второй аргумент для $modx->getChunk(), для замены любых плейсхолдеров в чанке на соответствующие значения

$resource = $modx->getObject('modResource',array('pagetitle'=>'MyDocument'));
$fields = $resource->toArray();
return $modx->getChunk('ShowResource',$fields);

В последней строчке мы вызываем чанк с шаблоном 

<div class="ShowResource">
    <p>Заголовок страницы: [[+pagetitle]]</p>
    <p>Длинный заголовок: [[+longtitle]]</p>
    <p>Псевдоним: [[+alias]]</p>
    <p>Аннотация: [[+introtext]]</p>
</div>

Вывод снипета [[ShowFields]] отобразит данный чанк на странице, подставив нужные аргументы.

Сокращенная запись снипета [[ShowFields]]

$resource = $modx->getObject('modResource',array('pagetitle'=>'MyDocument'));
return $modx->getChunk('ShowResource',$resource->toArray());

Если нужно вывести поля текущего ресурса, запись может быть еще компактнее

return $modx->getChunk('ShowResource',$modx->resource->toArray());

Обработка сниппета

Если надо запустить сниппет используется метод runSnippet. Пример с листингом ресурсов через pdoResources, с получением текущего ID ресурса:

$runSnippet = 'pdoResources';
$properties = array(
   'parents' => $modx->resource->id,
   'limit' => 0,
   'tpl' => 'tpl.list.item',
); 
return $modx->runSnippet($runSnippet, $properties);

Наборы параметров

Наборы параметров — это MODX объекты, которые содержат ассоциативный массив ключей и значений (схожих с Системными настройками). Они могут быть прикреплены к любому элементу с одноименной вкладки (чанку, сниппету, шаблону, плагину). Прикрепление параметра делает его доступным для элемента, но для использования параметра надо использовать специальный тег, примерно так

[[SnippetName@PropertySetName]]
[[$ChunkName@PropertySetName]]

Если «набор параметров» прикреплен к сниппету, он будет перезаписывать установленные по умолчанию параметры сниппета. 

Если «набор параметров» прикреплен к чанку или оставшимся элементам, значения из «набора» будет перезаписывать в элементе плейсхолдер соответствующий ключу. 

Получение обработанного значения объекта

В некоторых случаях может понадобиться вывод уже обработанного значения какого-либо элемента. В этом случае могут помочь функции runSnippet() и getChunk(). 

/* $props – массив, который содержит параметры сниппета */
$modx->runsnippet($snippetName, $props);
$modx->getChunk($chunkName);

Если выполнить сниппет с помощью runSnippet('SnippetName'), то будут использованы параметры по-умолчанию. 

Если выполнить сниппет используя runSnippet('SnippetName',$properties), будут доступны оба набора параметров.

В случае обработки чанка методом getChunk() набор параметров может иметь одинаковые ключи, и нужный параметр надо указывать используя имя

$setName = 'desiredPropertySetName';
$chunkName = 'desiredChunkName';

$object = $modx->getObject('modChunk',array(
        'name' =>$chunkName));

$propSet = $modx->getObject('modPropertySet',array(
        'name' =>$setName));

return($modx->GetChunk($chunkName, $propSet->getProperties() ));

Следует понимать разницу между «Наборами параметров» и параметрами по умолчанию. Параметры по умолчанию, технически, не является «Набором параметров». Параметры по умолчанию равнозначны свойствам «Набора параметров». Метод getProperties() получит свойства каждого

/* получаем значение по умолчанию установленные в снипете или другом элементе */
$snippet = $modx->getObject('modSnippet',array('name'=>'SnippetName'));
$properties = $snippet->getProperties();

/* получаем свойства конкретного набора параметров */
$propSet = $modx->getObject('modPropertySet',array('name'=>'PropertySetName'));
$properties = $propSet->getProperties();

Когда чанк получают с помощью метода getChunk() параметры по-умолчанию доступны для плейсхолдеров в чанке, для их перезаписи в вызове getChunk('ChunkName', $properties) надо отправить любой параметр с таким же именем.

Схожий процесс необходим, если вы хотите послать набор параметров установленный в вызове для runSnippet(). Свойства в «Наборе параметров» будут доступны в сниппете, если они введены как параметры при вызове сниппета. Для перезаписи параметров по-умолчанию надо снова, послать нужные значения с похожим именем.

Для других элементов, после того, как вы получили элемент с помощью $modx->getObject(), можно получить обработанный вывод используя $element->process(). Это работает и для чанков и сниппетов (на самом деле, оба метода вызывают process(). 

$element->process($properties) также доступен и параметры по-умолчанию перезаписываются заданными при вызове.

Посылать параметры по-умолчанию в вызовах getChunk(), runSnippet() или process() не имеет смысла, т.к. они используются автоматически.

Если нужен именно «Набор параметров», то следует при вызове уточнять какой, поскольку элементы могут иметь множество «Наборов».

Метод process() работает и для ресурсов. После получения объекта ресурса через $modx->getObject(), вывод обработанного контента можно организовать через $resource->process(), но будьте осторожны, не пишите вызов текущего ресурса в сниппете содержащемся в текущем ресурсе, с целью избегания цикла.

Модификация объектов

После получения ссылки на объект с помощью $modx->getObject(), можно менять значение его полей 

$object->set('FieldName', 'Value');
$object->save();

Для изменения или создания основного поля с содержимым ресурса или элемента (например, поле «контента» ресурсов, контент чанков, код сниппетов), лучше использовать setContent() 

$object->setContent('Value');
$object->save();

Следует отметить, что ссылка на текущий загруженный ресурс доступна через $modx->resource, но не стоит это использовать для изменения ресурса, т.к. это лишь копия ресурса. Всегда получайте ссылку через $modx->getObject() перед попыткой изменения объекта.

Создание новых объектов

$object = $modx->newObject('modChunk');
$object->set('name', 'ChunkName');
$object->setContent('Это будет содержимое нового чанка.');
$object->set('description', 'Я создал этот чанк через сниппет);
$object->set('category', 'MyChunks');
$object->save(); 

Каждый описанный здесь объект имеет ID и может быть найден по нему, но никогда не стоит устанавливать set() ID самостоятельно. Также при изменении или создании объектов, стоит убедиться, что используемые переменные правильного типа (того же типа, что и поле устанавливаемое поле). 

Работа с родительскими и дочерними элементами

Для получения всех потомков каталога можно использовать метод getChildIds:

// Синтаксис
$childs = $modx->getChildIds(id родителя, глубина, указание контекста); 

// Сокращенный пример
$childs = $modx->getChildIds(4);

// Полный пример 
$childs = $modx->getChildIds(4,1,array('context' => 'web'));

При использовании метода getChildIds в панели менеджера необходимо обязательно определить контекст с помощью третьего параметра, так как по умолчанию он будет соответствовать текущему контексту, соответственно контексту mgr.

Глубина по умолчанию = 10.

Простейший сниппет getChildren для получения id потомков:

$parent = $modx->getOption('parent',$scriptProperties);
$where = array(
    'context' => 'web'
);
$ids = $modx->getChildIds($parent,1, $where);
$ids = implode(',', $ids);
return $ids;

Вывод:

{'getChildren' | snippet : ['parent' => 4]}

Для получения родителей ресурса можно использовать метод getParentIds:

// Синтаксис
$parents = $modx->getParentIds(id документа, уровень вложенности, указание контекста);

// Сокращенный пример
$parents = $modx->getParentIds(23);

// Полный пример 
$childs = $modx->getChildIds(23,10,array('context' => 'web'));

При использовании метода getParentIds в панели менеджера необходимо обязательно определить контекст с помощью третьего параметра, так как по умолчанию он будет соответствовать текущему контексту, соответственно контексту mgr.

Уровень вложенности по умолчанию = 10.

Еще немного примеров

Получение pagetitle главной страницы

$res = $modx->getObject('modResource',1);
$output = $res->get('pagetitle');
print $output;

Получение детей документа, отсортированных по полю Title

$criteria = $modx->newQuery('modResource');
$criteria->where(array(
   'parent' => $modx->resource->get('id'),
));
$criteria->sortby('pagetitle','ASC');
$children = $modx->resource->getMany('Children',$criteria);

Поиск ресурса по его алиасу

$alias = 'res_alias';
$resource =  $modx->getObject('modResource',array(   
      'alias' => $alias 
  ));   
return $resource->get('id');