MODX (xPDO) - Получение объектов

Александр Мальцев
Александр Мальцев
25K
41
Содержание:
  1. Что такое xPDO
  2. Методы xPDO для получения объектов
  3. Вывод данных посредством PDO
  4. Комментарии

Статья, в которой рассмотрим, что такое xPDO и как его использовать при написании сниппетов и плагинов для системы CMS MODX Revolution. Разберём основные методы xPDO, применяемые для получения объектов (getObject, getCollection, getIterator, getOne и getMany) и метод newQuery, который используется для составления запроса. Кроме этого рассмотрим способ получения данных из базы CMS MODX Revolution без создания объектов, т.е. с помощью PDO.

Что такое xPDO

xPDO (eXtension PDO) - это объектно-реляционный мост (ORB), положенный в основу системы CMS MODX Revolution. xPDO представляет собой библиотеку, построенную на основе PDO. Основная цель этой библиотеки – это предоставить разработчикам объектно-ориентированный программный интерфейс (API), который позволит более просто и эффективно создавать сложные веб-приложения. В основу xPDO положены объектные модели для различных платформ баз данных. Представляет из себя объектная модель xPDO обычный XML-файл. Например, для СУБД MySQL, данный файл называется modx.mysql.schema.xml. Найти его в системе CMS MODX Revolution можно по следующему пути: /core/model/schema/. Если данный файл открыть, то можно увидеть, что он состоит из объектов (классов). Каждый объект (класс) представляет собой некоторую таблицу, а свойства этого объекта – его столбцы.

Объектов (таблиц) в MODX Revolution достаточно много, но наиболее часто используются при написании снипетов и плагинов следующие: modResource (ресурсы), modChunk (чанки), modUser (пользователи), modUserProfile (профиль пользователя), modTemplateVarResource (значение дополнительных полей), modTemplateVar (дополнительные поля).

Отношение между объектами (классами) CMS MODX Revolution

Примечание: в скобках на вышеприведённой схеме указаны названия таблиц без префикса. Каждая таблица представляет собой в xPDO модели тот или иной объект.

Как уже было отмечено выше, каждый объект (класс) имеет свойства (поля). Свойство - это столбец таблицы. Например, объект modResource (ресурс) состоит из свойств id (первичный ключ ресурса), pagetitle (заголовок), description (описание), content (содержимое ресурса), publishedby (id пользователя, который опубликовал ресурс) и т.д.

Кроме этого, каждый объект может иметь связи (alias) с другими объектами. Некоторые из них приведены на схеме. Например, если вам нужно получить имя пользователя, который опубликовал ресурс, то необходимо воспользоваться отношением, имеющим alias PublishedBy. Данное отношение определяет то, как данные представленные объектом modResource связаны с данными объекта modUser посредством локального (publishedby) и внешнего ключа (id). Каждое отношение имеет мощность. Например, у отношения с псевдонимом PublishedBy мощность равна 1. Это означает то, что отношение PublishedBy связвает объект modResource только с одним объектом modUser.

Методы xPDO для получения объектов

В xPDO получение объектов осуществляются в основном с помощью следующих методов: getObject, getCollection, getIterator.

Метод getObject предназначен для получения одного объекта. Объект - это экземпляр класса xPDOObject. Представить себе данный объект можно как строку в таблице базы данных.

Метод getCollection предназначен для получения коллекции объектов. Коллекция - это массив объектов xPDOObject. Представить себе данную коллекцию можно как список строк в таблице.

Метод Iterator предназначен для получения коллекции специального вида. Эта коллекция отличается от getCollection тем, что она не предоставляет доступ сразу ко всем её элементам (объектам xPDOObject), обращение к ним осуществляется последовательно.

Метод getObject

getObject - это метод, который позволяет получить объект, удовлетворяющий указанному критерию.

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

Метод getObject может принимать 3 аргумента: $className, $criteria, и $cacheFlag. Первый аргумент - это имя класса (название объекта), который вы хотите получить. Второй аргумент - это критерий, на основании которого будет осуществляться поиск элемента. Третий (последний) аргумент определяет, необходимо ли кэшировать полученный объект.

Если последний аргумент ($cacheFlag) имеет целое значение, то он будет определять время, на которое объект необходимо поместить в кэш. Если же аргумент $cacheFlag имеет значение false, то он не будет помещён в кэш. А если аргумент $cacheFlag равен true, то полученный объект будет помещён в кэш на неопределенный срок.

Аргумент $criteria может принимать одно из 3 значений:

  • значение первичного ключа;
  • массив, содержащий одно или несколько условий;
  • объект xPDOCriteria или его производные.

Например, напишем сниппет, который будет возвращать название (заголовок) ресурса, который имеет id = 5:

// получим ресурс (в качестве критерия используем id ресурса)
$resource = $modx->getObject('modResource',5);
// если ресурс не найден, то тогда вернём соответствующий ответ
if ($resource == null) {
  return 'Ресурс с id = 5 не найден!';
} 
// получим значения поля pagetitle у ресурса и вернём его
return $resource->get('pagetitle');

Если метод getObject не может получить объект, удовлетворяющий указанному критерию, то он возвращает в качестве ответа значение null.

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

// получим ресурс (в качестве критерия используем массив)
$resource = $modx->getObject('modResource',array('id'=>5));

Вы также можете осуществить поиск указанного объекта (например, ресурса) по нескольким полям:

// получим ресурс, который имеет статус опубликованного (published==1) и расположен в ресурсе с id = 19
// 1. Составляем критерий:
$criteria = array(
  'published'=>1,
  'parent'=>19
);
// 2. Получаем объект, указав критерий
$resource = $modx->getObject('modResource',$criteria);
// 3. Если объект найден, то возвращаем его заголовок
if ($resource) {
  return $resource->get('pagetitle');
}
//4. Если объект не найден, то соответственного ничего возвращаем 
return;

Если указанному критерию соответствуют несколько объектов, то метод getObject вернёт только первый из них.

Вы также можете создавать более сложные критерии для выбора элементов, используя xPDO запрос:

// новый запрос для объекта modResource
$query = $modx->newQuery('modResource');
// условие запроса
$query->where( array('parent' => 19) );
// получим объект, используя в качестве параметра запрос
$resource = $modx->getObject('modResource', $query);
// переменная для хранения результата
$output = '';
// если ресурс найден, то...
if ($resource) {
  // получим у найденного ресурса заголовок
  $output = $resource->get('pagetitle');
}
return $output;

Метод getCollection

getCollection - это метод, который возвращает коллекцию (массив) найденных объектов xPDOObjects, удовлетворяющих указанному условию.

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

Метод getCollection принимает те же три аргумента, что и метод getObject.

Например, создадим сниппет, который будет выводить заголовки всех ресурсов, который опубликовал пользователь с id = 1:

// получить коллекцию объектов modResource, удовлетворяющих указанному критерию
$resourses = $modx->getCollection('modResource',array(
   'publishedby' => 7
));
// переменная, в которую будем сохранять результат
$output = '';
// осуществим перебор массива объектов
foreach ($resourses as $resourse) {
  // добавим к значению переменной поле pagetitle ресурса
  $output .= $resourse->get('pagetitle').'<br>';
}
return $output;

Ключом массива, который возвращает метод getCollection, выступает первичный ключ полученных объектов.

Попробуем, получим объект из коллекции, полученной методом getCollection по его id:

// получим массив пользователей 
$users = $modx->getCollection('modUser');
// получим имя пользователя из коллекции по id (например, 1)
$id = 1;
if ($users[$id]) {
  return $users[$id]->get('username');
} 
return 'Пользователя с id = '.$id.' не существует!';

Например, выведем имена всех пользователей CMS MODX Revolution:

// получить массив пользователей 
$users = $modx->getCollection('modUser');
// выведим информацию о количестве пользователей
$output = 'Всего пользователей: '.count($users).'<br>';
// переберём массив пользователей
foreach ($users as $user) {
  // добавить к значению $output имя пользователя
  $output .= $user->get('username').'<br>';
}
// вернуть список пользователей
return $output;

Вторым параметром может быть не только массив, но и объект xPDOQuery:

// Например, получим 5 ресурсов, у которых id больше 10
// 1. Создадим запрос на выборку объектов modResource, у которых id > 10
$query = $modx->newQuery('modResource', array('id:>' => 10));
// 2. Ограничим выбору 5 элементами
$query->limit(5);
// 3. Получим объекты, указав запрос в качестве 2 параметра
$resources = $modx->getCollection('modResource', $query);
// 4. Переменная, в которую будем записывать результат
$output = '';
// 5. Переберём с помощью foreach полученный массив
foreach ($resources as $resource) {
  // 6. Поместим в переменную $output заголовок ресурса
  $output .= $resource->get('pagetitle').'<br>';
}
// 7. Вернём результат (значение переменной $output)
return $output;

Метод getIterator

xPDO метод getIterator идентичен методу getCollection за исключением того, что он позволяет обратиться в определённый момент времени только к одному объекту xPDOObject из коллекции строк. С точки зрения использования памяти метод getIterator является более эффективным, чем метод getCollection и поэтому лучше использовать именно его. Исключение составляет только те моменты, когда вам необходимо иметь доступ сразу ко всем объектам (строкам) коллекции.

Например, получим ресурсы, опубликованные пользователем с именем "admin" и имеющие заголовок, в котором присутствует слово "Ubuntu":

// 1. Создаём новый запрос для объекта modResource
$query = $modx->newQuery('modResource');
// 2. Присоединяем к объекту modResource объект modUser с помощью связи "PublishedBy"
$query->leftJoin('modUser','PublishedBy');
// 3. Задаём условие
$query->where(array(
  'modResource.pagetitle:LIKE' => '%Ubuntu%',
  'PublishedBy.username' => 'admin',
));
// 4. Получаем коллекцию объектов с помощью метода getIterator, отвечающих запросу
$resources = $modx->getIterator('modResource',$query);
// 5. Создаём переменную, в которую будем записывать ответ
$output = '';
// 6. Перебираем массив объектов
foreach ($resources as $resource) {
  $output .= $resource->get('pagetitle').'<br>';
}
// 7. Возвращаем ответ
return $output;

Внимание: При итерации в качестве индекса объекта выступает не первичный ключ.

Метод get

Метод get предназначен для того, чтобы получить значение указанного свойства (поля) объекта xPDOObject (строки таблицы).

/* синтаксис */
get($k)  
// $k - название поля (массив полей)

// Например, получим значение поля pagetitle у объекта $object
$pagetitle = $object->get('pagetitle');

// Например, получим значения полей id и pagetitle у объекта $object
$row = $object->get(array('id','pagetitle'));
$id = $row['id'];
$pagetitle = $row['pagetitle'];

Метод newQuery

newQuery – это метод, который позволяет строить сложные SQL запросы в объектно-ориентированном виде. Создание запроса осуществляется всегда относительно какого-то класса, указанного в качестве первого параметра. Другими словами, метод newQuery создаёт новый xPDOQuery для указанного класса xPDOObject. Составленные запросы, например, можно передать в качестве аргумента $criteria в метод getObject или getCollection.

Функция newQuery создает объект xPDOQuery. Она принимает 3 параметра:

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

Для конструирования запроса можно использовать следующие методы:

  • xPDOQuery.leftJoin - добавляет в запрос предложение LEFT JOIN. Операция LEFT JOIN выполняет внешнее левое соединение 2 таблиц так, что в результирующий набор попадут не только те соединения строк, которые удовлетворяют условию on, но и все остальные строки из первой (левой) таблицы. При этом отсутствующие значения столбцов из второй (правой) таблицы будут заменены значениями NULL.
    /* синтаксис leftJoin */
    // leftJoin ($class, $alias, $conditions)
    //   $class - название класса (объекта) из модели xPDO
    //   $alias (не обязательный аргумент) - название связи
    //   $conditions (не обязательный аргумент) - условие соединения таблиц   (если используете название связи из модели xPDO, то условие можно не указывать)
    
    // Например, выберем все ресурсы и имена пользователей, которые их создали.
    $query = $modx->newQuery('modResource');
    $query->select(array(
      'modResource.id as id',
      'modResource.pagetitle as pagetitle',
      'CreatedBy.username as username'
    ));
    // присоединяем объект modUser c помощью связи CreatedBy
    // (соединение связи не указываем, т.к. она описана в модели xPDO)
    $query->leftJoin('modUser','CreatedBy');
    $resources = $modx->getCollection('modResource',$query);
    $output = '';
    foreach ($resources as $resource) {
      $output .= $resource->get('username').' : '.$resource->get('pagetitle').'<br>';
    }
    return $output;
    
  • xPDOQuery.innerJoin - добавляет предложение INNER JOIN в запрос. Операция INNER JOIN выполняет внутреннее соединение 2 таблиц так, что в результирующий набор попадают только те соединения строк таблиц, которые отвечают условию on.
    /* синтаксис innerJoin */
    // innerJoin ($class, $alias, $conditions)
    //   $class - название класса (объекта) из модели xPDO
    //   $alias (не обязательный аргумент) - название связи
    //   $conditions (не обязательный аргумент) - условие соединения таблиц   (если используете название связи из модели xPDO, то условие можно не указывать)
    
    // Например, получим ресурсы, опубликованные пользователем "marry":
    $query = $modx->newQuery('modResource');
    // 1 параметр - имя класса (объекта)
    // 2 параметр - название связи 
    // 3 параметр - условие соединения (для связей, описанных в модели xPDO можно не указывать)
    $query->innerJoin('modUser','modUser','modUser.id=modResource.publishedby');
    $query->where(array('modUser' => 'marry'));
    $resources = $modx->getCollection('modResource',$query);
    
  • xPDOQuery.rightJoin - добавляет в запрос предложение RIGHT JOIN. Соединение RIGHT JOIN (правое внешнее соединение) обратно соединению LEFT JOIN. Это означает то, что в результирующий набор из второй (правой) таблицы попадут все строки. А из первой (левой) таблицы только те, для которых будет выполняться условие соединения on.
    /* синтаксис rightJoin */
    // rightJoin ($class, $alias, $conditions)
    //   $class - название класса (объекта) из модели xPDO
    //   $alias (не обязательный аргумент) - название связи
    //   $conditions (не обязательный аргумент) - условие соединения таблиц   (если используете название связи из модели xPDO, то условие можно не указывать)
    
    // Перепишем пример приведённый для метода leftJoin с помощью метода rightJoin
    $query = $modx->newQuery('modUser');
    $query->select(array(
      'modUser.id as id',
      'modUser.username as username',
      'CreatedResources.pagetitle as pagetitle'
    ));
    // присоединяем с помощью RIGHT JOIN таблицу (объект modResource) c помощью связи CreatedResources
    $query->rightJoin('modResource','CreatedResources');
    $resources = $modx->getCollection('modUser',$query);
    $output = '';
    foreach ($resources as $resource) {
      $output .= $resource->get('username').' : '.$resource->get('pagetitle').'<br>';
    }
    return $output;
    
  • xPDOQuery.where - добавляет в запрос предложение WHERE.
    $query = $modx->newQuery('modResource');
    
    /* синтаксис where
    array('attribute:operator' => 'value')
    */
    // по умолчанию все условия в массиве соединяются между собой посредством AND
    $query->where(array(
      'name' => 'Тимофей', /* равно (по умолчанию) */
      'name:=' => 'Тимофей', /* равно */
      'name:!=' => 'Тимур', /* не равно */
      'age:>' => '26', /* больше */
      'age:>=' => '26', /* больше или равно */
      'age:<' => '26', /* меньше чем */
      'age:<=' => '26', /* меньше или равно */
      'search:LIKE' => '%сайт%', /* инструкция LIKE */
      'field' => null, /* проверка на NULL */
      'ids:IN' => array(1,2,3), /* инструкция IN */
    ));
    
    /* LIKE (условие, выбирающее записи, у которых значение поля attribute соответствует указанной маске value). Для создания маски можно использовать специальные символы % (любое количество символов) и _ (один символ). */
    /* NOT LIKE (исключает из выборки записи, у которых значение поля  attribute соответствует указанной маске value). $query->where(array('pagetitle:NOT LIKE' => '%сайт%')). */
    /* IN (условие, выбирающие записи, у которых значения поля совпадает со значением в списке). */
    /* NOT IN (условие, выбирающее записи, у которых значение поля не совпадает ни с одним значением в списке). $query->where(array('parent:IN' => array(15,20))); */
    
    /* Как правило, элементы массива в предложении where соединяются с помощью SQL оператора "AND". Но вы также можете соединить условия и с помощью оператора "OR". Для этого его необходимо указать его в качестве префикса к необходимым именам столбцов. */
    // Например, создадим условие, которое будет выбирать только те ресурсы, у которых в заголовке встречается фраза MODX или HTML 
    $query->where(array(
      'pagetitle:LIKE' => '%MODX%',
      'OR:pagetitle:LIKE' => '%HTML%'
    ));  
    
    /* Обратите внимание на то, что необходимо обязательно указывать операнд =, если вы указываете в условии ключ, содержащий подобную строку 'OR:disabled:=' => true. */
    
  • xPDOQuery.andCondition - добавляет условие AND в предложение WHERE. Метод andCondition может быть использован только после метода where.
    // Например, получим ресурсы, отвечающие одновременно 2 условиям:
    // - имеющие шаблон с id = 6
    // - у которых родительский ресурс имеет id = 19
    $query = $modx->newQuery('modResource');
    $query->where(array('parent' => 19));
    $query->andCondition(array('template' => 6));
    $resources = $modx->getCollection('modResource',$query);
    
  • xPDOQuery.orCondition - добавляет условие OR в предложение WHERE. Метод orCondition может быть использован только после метода where.
    // Например, получим ресурсы, отвечающие одному из условий:
    // - имеющие шаблон с id = 6 
    // - у которых в качестве родителя выступает ресурс с id = 19
    $query = $modx->newQuery('modResource');
    $query->where(array('parent' => 19));
    $query->orCondition(array('template' => 6));
    $resources = $modx->getCollection('modResource',$query);
    
  • xPDOQuery.limit - добавляет в запрос предложение LIMIT/OFFSET.
    /* limit ($limit, $offset) */
    // $limit - число, ограничивающее количество записей
    // $offset (не обязательный аргумент) - число, задающее смещение (т.е. какое количество записей необходимо пропустить сначала)
    
    // Например, пропустим первые 5 записей и выведем позиции с 6 по 10:
    $query = $modx->newQuery('modResource');
    $query->limit(5,5);
    $resources = $modx->getCollection('modResource',$query);
    
  • xPDOQuery.sortby - добавляет в запрос предложение ORDER BY.
    /* синтаксис sortby */
    // sortby($column, $direction)
    // $column - имя столбца
    // $direction (необязательный аргумент) - порядок сортировки (по умолчанию 'ASC')
    // направление сортировки (например, 'ASC' (в порядке возрастания), 'DESC' (в порядке убывания), 'RAND()' (в случайном порядке) и др.
    
    // Например, получить всех пользователей отсортированных по полю username:
    $query = $modx->newQuery('modUser');
    $query->sortby('username','ASC');
    $users = $modx->getCollection('modUser',$query);
    
    // Вы также можете отсортировать записи в случайном порядке с помощью функции RAND():
    $query = $modx->newQuery('modResource');
    $query->sortby('RAND()');
    $resources = $modx->getCollection('modResource',$query);
    
    // Если вы хотите отсортировать результат в определённом порядке, то можете использовать функцию FIELD():
    $query = $modx->newQuery('modResource');
    $query->sortby('FIELD(id,1,7,3,4)');
    $query->where(array('id:IN' => array(1,7,3,4)));
    $resources = $modx->getCollection('modResource',$query);
    
  • xPDOQuery.select - указывает столбцы, которые необходимо вернуть из SQL запроса. Функция select работает как с массивом столбцов, так и со строкой (имена столбцов в строке указываются через запятую).
    /* синтаксис select */
    select ($columns)
    // $columns - строка (по умолчанию *) или массив
    
    // Например, получить коллекцию объектов modUser, содержащих только поля id и username.
    $query = $modx->newQuery('modUser');
    $query->select('id,username');
    $users = $modx->getCollection('modUser',$query);
    
    // Кроме этого в функцию select можно передать имена столбцов с помощью метода getSelectColumns.
    // getSelectColumns($className, $tableAlias, $columnPrefix, $columns)
    // $className - имя класса (объекта) в модели xPDO
    // $tableAlias (не обязательный) - псевдоним (по умолчанию '')
    // $columnPrefix (не обязательный) - префикс для столбцов (по умолчанию '')
    // $columns (не обязательный) - массив, содержащий имена столбцов
    
    // С использованием метода getSelectColumns:
    $query->select($modx->getSelectColumns('modUser','modUser','',array('id','username')));
    
  • xPDOQuery.groupby - добавляет в запрос предложение GROUP BY. Предложение GROUP BY обычно используется в сочетании с агрегатными функциями COUNT, MIN, MAX, AVG и SUM.
    // Например, выведем количество ресурсов, опубликованных каждым пользователем:
    
    $query = $modx->newQuery('modUser');
    $query->leftJoin('modResource','PublishedResources');
    $query->groupby('PublishedResources.publishedby');
    $query->select(array(
      'COUNT(PublishedResources.id) as count',
      'modUser.id as id',
      'modUser.username as username'
    ));
    $users = $modx->getCollection('modUser',$query);
    $output = '';
    foreach ($users as $user) {
      $output .= 'Пользователь '.$user->get('username').' опубликовал '.$user->get('count').' ресурсов <br>';
    }
    return $output;
    
  • xPDOQuery.setClassAlias - устанавливает SQL псевдоним для таблицы, представляющий собой основной класс (объект).
    /* синтаксис setClassAlias */
    // setClassAlias ($alias)
    // $alias (не обязательный аргумент) - устанавливает псевдоним классу (по умолчанию равен '')
    
    // Получим все объекты modResource, удовлетворяющие некоторому условию.
    // Для удобства чтения кода установим классу modResource псевдоним "Resource".
    $query = $modx->newQuery('modResource');
    $query->setClassAlias('Resource');
    $query->where(array('Resource.pagetitle:LIKE' => '%MODX%',));
    $resources = $modx->getCollection('modResource',$query);
    

Например, создадим сниппет, который будет выводить на экран ресурсы и связанное с каждым из них значение TV поля с id = 3.

Требования к написанию выборки:

  • обязательное наличие TV поля, у которого id = 3;
  • родительский ресурс должен иметь id, равное 19, 24 или 25;
  • сортировку ресурсов выполнить по дате публикации.
$query = $modx->newQuery('modResource');
$query->select(array(
  'modResource.id as id',
  'modResource.pagetitle as pagetitle',
  'TemplateVarResources.value as value'
));
$query->innerJoin('modTemplateVarResource','TemplateVarResources'); 
$query->where(array(
  'TemplateVarResources.tmplvarid:=' => '3',
  'parent:IN' => array(19,24,25)
));
$query->sortby('modResource.publishedon','ASC');
$query->limit(5);
$resources = $modx->getCollection('modResource',$query);

$output = '';
foreach ($resources as $resource) {
  $output .= $resource->get('pagetitle').'('.$resource->get('value').')<br>';
}
return $output;

Отладка

Увидеть запрос, который был создан методом newQuery, можно так:

 $query = $modx->newQuery('modResource');
// ... составление запроса
// подготовка запроса к выполнению (в качестве результата получаем объект, связанный с этим запросом
$query->prepare();
// возвращение подготовенного SQL запроса 
return $query->toSQL();

// Например, SQL запрос вышеприведённого примера будет иметь вид:
/* SELECT modResource.id as id, modResource.pagetitle as pagetitle, TemplateVarResources.value as value FROM `modx_site_content` AS `modResource` JOIN `modx_site_tmplvar_contentvalues` `TemplateVarResources` ON `modResource`.`id` = `TemplateVarResources`.`contentid` WHERE ( `TemplateVarResources`.`tmplvarid` = '3' AND `modResource`.`parent` IN (19,24,25) ) ORDER BY modResource.publishedon ASC LIMIT 5 */

Методы getOne и getMany

Для работы со связанными объектами в xPDO используются методы getOne и getMany (в зависимости от мощности отношения).

getOne – это метод, который получает объект, связанный с текущим отношением, имеющим мощность 1:? (1:0 или 1:1) или 1:1.

getOne($alias, $criteria, $cacheFlag)
// $alias - псевдоним отношения
// $criteria (не обязательный) - критерий (объект)
// $cacheFlag (не обязательный) - флаг, отвечающий за кэширование (по умолчанию true)

Например, рассмотрим, как получить объект modUser, связанный с объектом modResource отношением "PublishedBy", имеющим мощность 1.

// 1. Получим ресурс с id = 5
$resource = $modx->getObject('modResource',5);
// 2. Присоединим к ресурсу объект modUser связанный с ним отношением "PublishedBy"
$user = $resource->getOne('PublishedBy');
// 3. Получаем имя пользователя, опубликовавшего этот ресурс
$username = $user->get('username');
// 4. Возвращаем ответ
return $username;

getMany – это метод, который позволяет получить коллекцию объектов, связанных с текущим отношением 1:* (один ко многим).

getMany($alias, $criteria, $cacheFlag)
// $alias - псевдоним отношения
// $criteria (не обязательный) - критерий (объект)
// $cacheFlag (не обязательный) - флаг, отвечающий за кэширование (по умолчанию true)

Например, разберём, как получить все ресурсы, созданные некоторым пользователем:

// 1. Получим пользователя по имени admin
$user = $modx->getObject('modUser',array('username' => 'admin'));
// 2. Получим ресурсы, созданные пользователем admin
$resources = $user->getMany('CreatedResources');
// 3. Создадим переменную $output
$output = '';
// 4. Переберём все ресурсы, созданные пользователем admin
foreach ($resources as $resource) {
   $output .= $resource->get('pagetitle').'<br>';
}
// 5. Возвратим ответ
return $output;

Например, получим все чанки расположенные в некоторой категории:

// 1. Получим категорию с именем Tickets
$category = $modx->getObject('modCategory',array('category' => 'Tickets'));
// 2. Получим чанки, находящиеся в этой категории
$chunks = $category->getMany('Chunks');
// 3. Создадим переменную $output
$output = '';
// 4. Переберём чанки
foreach ($chunks as $chunk) {
  // получим имя чанка
  $output .= $chunk->get('name').'<br>';
}
// 5. Возвратим ответ
return $output;

Вывод данных посредством PDO

Получить данные из базы MODX Revolution можно не только с помощью методов xPDO (getOject, getCollection и др.), но и посредством PDO в виде массива. Данный способ не является стандартным способом получения данных в CMS MODX Revolution, но зато он позволяет сэкономить память и увеличить быстродействие. Эти преимущества в основном проявляют себя только в том случае, если вам необходимо из базы получить большой объём информации.

Внимание: Способ получения данных, основанный на PDO, выполняет это без проверки прав, и конечно без создания объектов xPDOObject.

Например, получим названия последних 5 опубликованных ресурсов:

// 1. Конструирование запроса выполним с помощью xPDO (метод newQuery)
$query = $modx->newQuery('modResource');
$query->sortby('publishedon','DESC');
$query->limit(5);
$query->where(array('published:='=>'1'));
// 2. Выполнение запроса выполним с помощью PDO
// подготовка запроса к выполнению
$query->prepare();
// выполнить подготовленный запрос
$query->stmt->execute();
// получаем массив, содержащий все строки результирующего набора
$rows = $query->stmt->fetchAll(PDO::FETCH_ASSOC);
$output = '';
foreach ($rows as $row) {
  $output .= $row['modResource_pagetitle'].' (дата публикации: '.$row['modResource_publishedon'].')<br>';
}
return output;

Комментарии:

  1. Amsterdam
    Amsterdam
    06.10.2021, 12:19
    Александр, добрый день!

    А как получить массив ресурсов по заранее известному списку алиасов? Так не получается…
    $resourses = $modx->getCollection('modResource',array(
       'alias' => 'res1,res2'
    ));
    1. Александр Мальцев
      Александр Мальцев
      06.10.2021, 15:12
      Привет!
      $resourses = $modx->getCollection('modResource', [
        'alias:IN' => ['search', 'authorization']
      ]);
      1. Amsterdam
        Amsterdam
        06.10.2021, 20:14
        Спасибо!
    2. Amsterdam
      Amsterdam
      16.06.2021, 18:25
      Александр, добрый вечер!

      Не подскажите, как в xPDO использовать регулярки? Например получили pagetitle

      $pagetitle = $modx->resource->get('pagetitle');
      return $pagetitle;
      результат: «Товар номер один, интернет-магазин Сталевар»
      А как использовать регулярку в данном контексте? что то никак не могу придумать… Допустим, нужно удалить слово «Сталевар»

      По аналогии с php не получается
      $pagetitle = $modx->resource->get('pagetitle');
      $pagetitle = preg_replace('Сталевар', '', $pagetitle);
      return $pagetitle;
      1. Александр Мальцев
        Александр Мальцев
        20.06.2021, 14:32
        Привет!
        Вместо preg_replace используйте функцию с поддержкой многобайтовых кодировок mb_ereg_replace:
        $pagetitle = $modx->resource->get('pagetitle');
        $pagetitle = mb_ereg_replace('Сталевар', '', $pagetitle);
        return $pagetitle;
      2. Amsterdam
        Amsterdam
        14.10.2020, 07:49
        Александр, доброго дня!

        Не подскажите, почему так происходит? Плагин пересчитывает цену в minishop2 через свой плагин. Имеется такой код:
        switch ($modx->event->name) {
        	case 'msOnGetProductPrice':
        
        		// Подключаем массив значений по ссылке
        		$values = & $modx->event->returnedValues;
        
        		// Цена может меняться несколькими плагинами сразу, поэтому проверяем:
        		if (isset($values['price'])) {
        			$price = $values['price'];
        		}
        
        		// Меняем цену:
        		$values['price'] = $_REQUEST['price'];
        		$modx->log(modX::LOG_LEVEL_ERROR, $modx->event->name . '. Цена2 ' . $values['price'] . print_r($values, true));
        	break;	
        }
        Цена должна пересчитываться посредством сложения и записи новых значений в value для input.price[name=price] на фронте, через выбор нужных радиокнопок. По задумке, начальное значение и новое должны складываться. Но, плагин сразу пересчитывает базовую цену и делает ее равной нулю.

        Сложение происходит, но не с указанной ценой товара, а с нулем. Не могу разобраться, почему так…
        1. Александр Мальцев
          Александр Мальцев
          18.10.2020, 14:47
          Привет! Так в $_REQUEST['price'] будет находиться строка, а нужно наверно число.
          Попробуйте так:
          $values['price'] = floatval($_REQUEST['price']);
          
          1. Amsterdam
            Amsterdam
            20.10.2020, 08:56
            Вообще, похоже логику использую неверную. Пересчет цены должен происходить только при выборе модификатора, а она сразу же при загрузке страницы меняется, и меняется на ноль.
            1. Александр Мальцев
              Александр Мальцев
              20.10.2020, 15:06
              Да, у вас это скорее всего должно происходить посредством AJAX, если конечно нужно выполнять какую-то обработку на сервере, или просто на клиенте. А так = получается, что при загрузке страницы данный параметр (price) не передаётся и у вас всегда цена устанавливается равной нулю.
            2. Amsterdam
              Amsterdam
              20.10.2020, 08:38
              не выходит… все равно начальную цену выводит как 0
              itchief.ru/assets/uploadify/e/6/9/e69a599b92bb1b49371d6f7d64b83636.png
              Но при выборе модификации, цена меняется, но только на выбранную, то есть становится либо 500 либо 830. А должна суммироваться 500 + 500, либо соответственно, 500 + 830
          2. Aleksei
            Aleksei
            15.09.2020, 21:57
            Привет, Александр!
            Голову сломал над одной задачкой.

            Есть код:
            $pdo = $modx->getService('pdoFetch');
            
            $collection = $pdo->getCollection('modResource',
                        array('template' => 5, 'published' => 1),
                        array(
                        'parents' => 28,
                        'sortbyTV' => 'event_date_time',
                        'includeTVs' => 'event_date_time,event_place',
                        'sortbyTVType' => 'datetime',
                        'sortdirTV' => 'ASC',
                        'where' => '{"event_place":"Место"}'
                        )
            );
            
            foreach ($collection as $key)
            {
              // То-сё, пятое, десятое;
            }
            
            Не могу понять, возможно ли использовать строку
            'where' => '{"event_place":"Место"}'
            
            в данной конструкции.
            Подозреваю, что пишу её неправильно. Подставлял строку
            'tvPrefix' => 'tv.',
            и на выходе вообще ничего, хмм…
            1. Александр Мальцев
              Александр Мальцев
              16.09.2020, 14:13
              Привет! Условие where необходимо задавать во втором аргументе:
              $collection = $pdo->getCollection('modResource',
                array('template' => 5, 'published' => 1, 'event_place' => 'Место'),
                array(
                  'parents' => 28,
                  'sortbyTV' => 'event_date_time',
                  'includeTVs' => 'event_date_time,event_place',
                  'sortbyTVType' => 'datetime',
                  'sortdirTV' => 'ASC',
                )
              );
              
            2. Amsterdam
              Amsterdam
              11.07.2020, 08:03
              Александр, а как возможно получить дату публикации ресурса через PDO без времени? Задача такая — выводится список ресурсов через pdoResources, необходимо вывести ресурсы, дата публикации которых совпадает с сегодняшней. Пробую сделать это через where:

              &where=`{"[[!pubday]]:=":"[[!today]]"}`
              В сниппете [[!today]] выводится «сегодняшняя» дата формата 2020-07-10, но никак не получается вывести в таком же формате дату публикации ресурса. Вывод publishedon напрямую вставляет туда и время (часы минуты секунды)

              &where=`{"publishedon:=":"[[!today]]"}`
              изза чего сравнение, конечно, не проходит. Как возможно вывести дату публикации в виде «2020-07-10»?
              1. Aleksei
                Aleksei
                13.07.2020, 11:33
                Добрый день!
                Осмелюсь предложить еще вариант, вроде как работает))
                &where = `{
                "publishedon:>=": "[[!+nowdate:default=`now`:strtotime:date=`%Y-%m-%d 00:00:00`]]",
                "publishedon:<=": "[[!+nowdate:default=`now`:strtotime:date=`%Y-%m-%d 23:59:59`]]"
                }`
                
                1. Александр Мальцев
                  Александр Мальцев
                  11.07.2020, 13:45
                  Например, это можно выполнить, если выбирать ресурсы, дата публикации которых находится между «2020-07-10 00:00:00» и «2020-07-10 23:59:59». При этом нужно учитывать, что publishedon в базе данных хранится в количестве миллисекунд (временной метке Unix).

                  Порядок действий:
                  1. Создать сниппет setDatePeriod, который будет устанавливать плейсхолдеры «date.start» и «date.end». Они будут хранить сегодняшнюю дату в миллисекундах на начало и конец дня.
                  <?php
                  // получаем текущую дату
                  $date_ts = time();
                  
                  // начальная дата
                  $day_start = strtotime('today', $date_ts);
                  // конечная дата
                  $day_end = strtotime('tomorrow', $day_start) - 1;
                  
                  return $modx->setPlaceholders(array(
                    'start' => $day_start,
                    'end' => $day_end,
                  ),'date.');
                  
                  2. Вызываем на странице сниппет setDatePeriod, который будет устанавливать плейсхолдеры «date.start» и «date.end».
                  [[!setDatePeriod]]
                  
                  3. В pdoResources в &where прописываем условия:
                  [[pdoResources?
                    ...
                    &where = `{
                      "publishedon:>=": "[[+date.start]]",
                      "publishedon:<=": "[[+date.end]]"
                    }`
                  ]]
                  1. Amsterdam
                    Amsterdam
                    06.12.2020, 09:37
                    Александр, добрый день!

                    Не подскажите, а как сделать, что и вчерашние даты захватывались? Пробовал прописать и yesterday вместо tomorrow, и — 2, но не получается…
                    1. Александр Мальцев
                      Александр Мальцев
                      07.12.2020, 08:41
                      Привет! Нужно так:
                      // начальная дата
                      $day_start = strtotime('yesterday', $date_ts);
                      // конечная дата
                      $day_end = strtotime('tomorrow', $day_start) - 1;
                      
                    2. Amsterdam
                      Amsterdam
                      11.07.2020, 17:53
                      Вот это да, решение оказалось несколько более сложным, чем я думал. Троекратное спасибо, Александр!!! Вашу помощь нельзя переоценить!
                  2. Nik
                    Nik
                    24.11.2019, 14:19
                    Здравствуйте Александр! Подскажите пожалуйста как можно на странице вывести данные пользователя, введя в форму поиска его телефон который указан в его профиле. То есть, если по другому выразиться, по номеру телефона найти пользователя и вывести его имя, email и прочее (если номер телефона есть). Нашел пример где это все делается по ID пользователя — работает, пробовал вывести по номеру телефона, используя вместо id — phone, не выводит. Вот рабочий пример, если вывод по ID.
                    Сниппет:
                    if(is_numeric($_REQUEST['id'])) $id = $_REQUEST['id'];
                    $user = $modx->getObject('modUserProfile', $id);
                    if(!$user) return;
                    return $modx->getChunk($tpl, array (
                    'email'=> $user->get('email'),
                    'fullname'=> $user->get('fullname'),
                    'phone'=> $user->get('phone'),
                    'comment'=> $user->get('comment')
                    ));
                    
                    Простейший чанк вывода:
                    <p>Имя пользователя: [[+fullname]]</p>
                     <p>Email: [[+email]]</p>
                     <p>Телефон: [[+phone]]</p>
                     <p>Комментарий: [[+comment]]</p>
                    
                    Вывод на странице:
                    <form action="">  
                    <input type="text" name="id"  class="search" placeholder="Введите номер" />  
                    <input type="submit" class="search" value="Найти" />  
                    </form>
                    
                    [[!snippet?
                    &tpl=`chank`
                    ]]
                    
                    1. Александр Мальцев
                      Александр Мальцев
                      24.11.2019, 15:35
                      Привет!
                      В форме полю желательно установить соответствующее имя, например phone:
                      <input type="text" name="phone"  class="search" placeholder="Введите номер" />  
                      
                      При выборе объекта нужно задавать условие по phone, а не id. В большинстве случаев телефон это не просто цифры. Поэтому проверить телефон с помощью is_numeric не всегда корректно. Если в поле phone кроме цифр есть знак +, скобочки и тире, то в этом случае следует удалять всё другое что ввел пользователь, крое этого и цифр.
                      $phone = preg_replace('/[^+()0-9-]/', '', $_REQUEST['phone']);
                      
                      if (empty($phone)) {
                        return;
                      }
                      
                      $user = $modx->getObject('modUserProfile',array('phone' => $phone));
                      
                      if($user) {
                        return $modx->getChunk($tpl, array (
                        'email'=> $user->get('email'),
                        'fullname'=> $user->get('fullname'),
                        'phone'=> $user->get('phone'),
                        'comment'=> $user->get('comment')
                        ));
                      }
                      
                      1. Nik
                        Nik
                        25.11.2019, 07:32
                        Спасибо! Насчет скобок и тире я не подумал, is_numeric проверяет же только цифры в строке. Еще вы использовали функцию empty. Все просто… То что я выдумывал целый день, у вас на это ушла одна секунда)))
                    2. Amsterdam
                      Amsterdam
                      08.08.2019, 07:40
                      Александр, добрый день

                      Не поможешь разобраться с такой задачкой?

                      Написал код, который работает в паре с PHP парсером. Необходимая логика его работы следующая:

                      — Парсер передает ему массив данных (ок)
                      — Процессор MODx создает ряд ресурсов из этих данных (ок)
                      — Если ресурс найден, обновляем данные (ок)
                      — Если часть ресурсов найдена, а часть еще не была загружена (такое бывает, когда в каталоге появляются новые товары),
                      то здесь возникает проблема — старые ресурсы он обновляет, а вот новые не создает (пытается их обновить, но не находит).

                      Нужно доработать то, что бы не найденные ресурсы он создавал, а не упирался в попытку поиска для обновления. Код следующий:

                      <?php
                      
                      // массив с данными
                      $data = [
                          'pagetitle' => $main_heading,
                          'alias' => "$url",
                          'content' => '',
                          'template' => 3,
                          'published' => 1,
                          'parent' => $parent_id
                      ];  
                      
                      // Заполняем ТВ
                      $specForPriceTV = 'tv15';
                      $brandTV = 'tv14';
                      
                      $data[$priceTV] = $price_result;
                      $data[$brandTV] = $brand;
                          
                      // Процессор выполнение   
                      $response = $modx->runProcessor('resource/create', $data);
                      
                      // если ошибка 
                      if($response->isError()){
                      //    echo "<div><b style='color:olive'>Документ не создан:</b> $main_heading</div>". $response->getMessage();
                          
                          // Выполняем поиск по alias 
                      $resource = $modx->getObject('modResource', array('alias' => "$url"));
                      
                      // Если ресурс найден
                      if (is_object($resource)) {
                      // Устанавливаем заголовок
                          $resource->set('pagetitle', "$main_heading");
                      // Обновляем TV
                          $resource->setTVValue('price', $price_result);
                          $resource->setTVValue('brand', $brand);
                          
                      //  Сохранение
                          $resource->save();
                        
                      echo "<div><b style='color:olive'>Документ обновлен:</b> $main_heading</div>";
                              
                      } else {
                          echo "<div><b style='color:red'>Документ не найден:</b> $main_heading</div>";
                      }
                          
                      }
                      else{
                          echo "<div><b style='color:green'>Документ создан:</b> $main_heading</div>";
                      }
                      1. Александр Мальцев
                        Александр Мальцев
                        12.08.2019, 15:44
                        Привет!
                        Сначала лучше проверить, если ли уже такой ресурс. Если да, то обновить его, в противном случае создать.
                        // массив с данными
                        $data = [
                          ...
                        ];
                        // выполняем поиск ресурса по alias 
                        $resource = $modx->getObject('modResource', array('alias' => "$url"));
                        
                        // если ресурс найден
                        if (is_object($resource)) {
                          // то обновляем ему поля и затем его сохраняем
                        } else {
                          // в противном случае создаём новый  
                        }
                        
                        Полный код:
                        // массив с данными
                        $data = [
                          'pagetitle' => $main_heading,
                          'alias' => "$url",
                          'content' => '',
                          'template' => 3,
                          'published' => 1,
                          'parent' => $parent_id
                        ];
                        
                        // выполняем поиск ресурса по alias 
                        $resource = $modx->getObject('modResource', array('alias' => "$url"));
                        
                        // ели ресурс найден
                        if (is_object($resource)) {
                          // устанавливаем ему заголовок
                          $resource->set('pagetitle', "$main_heading");
                          // обновляем TV
                          $resource->setTVValue('tv14', 'Значение TV14');
                          $resource->setTVValue('tv15', 'Значение TV15'); 
                          //  сохраняем
                          $resource->save();
                          echo "<div><b style='color:olive'>Документ обновлен:</b> $main_heading</div>";
                        } else {
                          // создаём ресурс через процессор   
                          $response = $modx->runProcessor('resource/create', $data);
                          if ($response->isError()) {
                            echo "<div><b style='color:red'>Ошибка при создании документа:</b> $main_heading</div>";
                            //echo $response->getMessage();
                          }
                          $modx->cacheManager->clearCache();
                          $newId = $response->response['object']['id'];  
                          $newResource = $modx->getObject('modResource', $newId);
                          $newResource->setTVValue('tv14', 'Новое значение TV14');
                          $newResource->setTVValue('tv15', 'Новое значение TV15'); 
                          $newResource->save();
                          echo "<div><b style='color:green'>Документ создан:</b> $main_heading</div>";  
                        }
                        
                        1. Amsterdam
                          Amsterdam
                          10.09.2019, 08:44
                          Доброго дня! Только удалось вернуться к теме и протестировать. Спасибо за вариант, но не совсем работает. Когда идет попытка создать новый документ после тех, которые уже были и обновились, то происходит проблема с передачей значений TV. То есть:

                          Как говорил, процессор работает в паре с PHP парсером сайтов.

                          Было создано два ресурса. Процессор прошелся по ним обновив данные.
                          Третьего ресурса не было и он должен создаться, при этом он создается, но дальнейший цикл обхода ломается с ошибкой:

                          Fatal error: Uncaught Error: Call to a member function setTVValue() on null

                          Не могу понять, почему с получением данных на этапе создания ресурса происходит проблема.

                          Возможно, он попадает в цикл создания ресурсов и не выходит для обновления?
                          1. Александр Мальцев
                            Александр Мальцев
                            10.09.2019, 15:35
                            Привет! Должно работать, пример тестировал. Может какая-та проблема с MODX. Попробуйте обновить CMS MODX на туже версию, которая стоит.
                            1. Amsterdam
                              Amsterdam
                              10.09.2019, 23:29
                              Заметил: если убрать обращение к TV, то ресурс создается. Т.е. вот так:

                              // массив с данными
                              $data = [
                                'pagetitle' => $main_heading,
                                'alias' => "$url",
                                'content' => '',
                                'template' => 3,
                                'published' => 1,
                                'parent' => $parent_id
                              ];
                              
                              // выполняем поиск ресурса по alias 
                              $resource = $modx->getObject('modResource', array('alias' => "$url"));
                              
                              // ели ресурс найден
                              if (is_object($resource)) {
                                // устанавливаем ему заголовок
                                $resource->set('pagetitle', "$main_heading");
                                // обновляем TV
                                $resource->setTVValue('tv14', 'Значение TV14');
                                $resource->setTVValue('tv15', 'Значение TV15'); 
                                //  сохраняем
                                $resource->save();
                                echo "<div><b style='color:olive'>Документ обновлен:</b> $main_heading</div>";
                              } else {
                                // создаём ресурс через процессор   
                                $response = $modx->runProcessor('resource/create', $data);
                                if ($response->isError()) {
                                  echo "<div><b style='color:red'>Ошибка при создании документа:</b> $main_heading</div>";
                                  //echo $response->getMessage();
                                }
                                $modx->cacheManager->clearCache();
                                $newId = $response->response['object']['id'];  
                                $newResource = $modx->getObject('modResource', $newId);
                              //Тут были TV
                                $newResource->save();
                                echo "<div><b style='color:green'>Документ создан:</b> $main_heading</div>";  
                              }
                              Но пока не понял, обновляет ли он данные при таком раскладе
                              1. Amsterdam
                                Amsterdam
                                10.09.2019, 23:22
                                Не совсем понял, на какую предлагается обновить? Версия самая свежая, 2.7.1…
                                1. Александр Мальцев
                                  Александр Мальцев
                                  11.09.2019, 07:09
                                  Попробуй просто переустановить эту же версию, если стоит 2.7.1, то 2.7.1.
                                  1. Amsterdam
                                    Amsterdam
                                    08.07.2020, 22:13
                                    В общем задача та же самая, что и в коде выше по нашей переписке, только сравнение нужно провести не по значению в alias, а по значению из TV (имя ТВ siteUrl)
                                    1. Александр Мальцев
                                      Александр Мальцев
                                      09.07.2020, 16:17
                                      Чтобы найти ресурс по значению TV нужно использовать запрос:
                                      $criteria = $modx->newQuery('modResource');
                                      $criteria->leftJoin('modTemplateVarResource', 'TV', 'TV.tmplvarid = 5 AND TV.contentid = modResource.id');
                                      $criteria->where([
                                       'TV.value' => 'tabs'
                                      ]);
                                      
                                      $resource = $modx->getObject('modResource',$criteria);
                                      if (is_object($resource)) {
                                        // ...
                                      }
                                      
                                      В примере вместо 5 вам нужно указать id вашей TV, а значение по которому найти вместо tabs.
                                      1. Amsterdam
                                        Amsterdam
                                        09.07.2020, 21:53
                                        А нет, не работает, оказывается) Call to a member function setTVValue() on null. Что то я опять не так делаю… Опробовал этот код и с массивом, и без массива, различные ошибки выдает…
                                        1. Amsterdam
                                          Amsterdam
                                          09.07.2020, 19:03
                                          Александр спасибо, шикарно работает!!!
                                      2. Amsterdam
                                        Amsterdam
                                        08.07.2020, 20:44
                                        Приветствую, Александр!

                                        В массив передаю значения:

                                        $data = [
                                            'pagetitle' => $main_heading,
                                            'alias' => "$url",
                                            'content' => '',
                                            'template' => 3,
                                            'published' => 1,
                                            'parent' => $parent_id
                                        ];


                                        но не могу понять, как через этот массив записать данные в какой либо TV?
                              2. Amsterdam
                                Amsterdam
                                12.08.2019, 07:50
                                нет идей?.. а если за финансовую помощь?)
                                1. Александр Мальцев
                                  Александр Мальцев
                                  12.08.2019, 15:52
                                  Поблагодарить всегда можно на этой страничке.
                              3. Amsterdam
                                Amsterdam
                                04.08.2019, 14:52
                                Александр, доброго вечера!

                                Не подскажешь, как найти всех детей ресурса с id=3, у которых значение tv1 = 'fraza', и удалить эти ресурсы? И так и так попробовал, не получается и все тут…
                                1. Александр Мальцев
                                  Александр Мальцев
                                  05.08.2019, 12:34
                                  Привет.
                                  Создай в корне проекта php-файл со следующим содержимым и запусти его на выполнение:
                                  <?php
                                  
                                  require_once dirname(__FILE__).'/config.core.php';
                                  require_once MODX_CORE_PATH.'model/modx/modx.class.php';
                                  $modx = new modX();
                                  $modx->initialize('web');
                                  $modx->getService('error','error.modError', '', '');
                                  
                                  $query = $modx->newQuery('modResource');
                                  $query->leftJoin('modTemplateVarResource', 'TemplateVarResources');
                                  $query->where(array(
                                    'parent:=' => '3',
                                    'TemplateVarResources.tmplvarid:=' => '2'
                                  ));
                                  $resources = $modx->getCollection('modResource', $query);
                                  foreach ($resources as $resource) {
                                    $id = $resource->get('id');
                                    $res = $modx->getObject('modResource', $id);
                                    // пометить на удаление
                                    $res->set('deleted', '1');
                                    $res->save();
                                    // или полностью удалить
                                    //$res->remove();
                                  }
                                  
                                  exit();
                                  
                                  Только вместо 2, укажи номер своего id tv1 = 'fraza'
                                  1. Amsterdam
                                    Amsterdam
                                    05.08.2019, 15:07
                                    Спасибо!!!
                                2. Ino
                                  Ino
                                  26.01.2019, 03:45
                                  Спасибо большое Александр!!!
                                  Наконец-то всё по полочкам.
                                  Я туточки по баннерам покликаю… Надеюсь никто не против?
                                  :-))
                                  1. Руслан
                                    Руслан
                                    08.11.2018, 10:19
                                    Прошу помочь. Чтот запнулся с пониманием массивов. Есть запрос:

                                    $q = $modx->newQuery('modContext');
                                    $where = array(
                                       'modContext.key:in' => array('web', 'mgr'),
                                       'cs.value:!=' => NULL,
                                       'cs.value:!=' => '',
                                    );
                                    $q->select(array(
                                       'modContext.key',
                                       'cs.key as setting_key',
                                       'cs.value'
                                    ));
                                    $q->innerJoin('modContextSetting', 'cs', 'cs.context_key = modContext.key');
                                    $q->where($where);
                                    
                                    здесь where присваивается за один раз. Как бы разбить это действие на несколько? Типа:

                                    $where['modContext.key:in'] => 'web';
                                    $where['modContext.key:in'] => 'mgr';
                                    $where['cs.value:!='] => NULL;
                                    $where['cs.value:!='] => '';
                                    
                                    Помогите, пожалуйста.

                                    Вообще, мне нужно сделать так, чтобы where собирался по ходу кода, а потом использовался в двух разных запросах. Для этого нужно, чтобы в where элементы добавлялись вместе с условиями «like», «in» и т.п. У меня получалось только, что они перекрывали друг друга, где в итоге только последний элемент в массиве оставался.
                                    1. Александр Мальцев
                                      Александр Мальцев
                                      08.11.2018, 13:39
                                      Собирайте, это обычная работа с массивами на php.
                                      $where['modContext.key:in'][0] = 'web';
                                      $where['modContext.key:in'][1] = 'mgr';
                                      $where['cs.value:!='] = NULL;
                                      
                                      1. Руслан
                                        Руслан
                                        08.11.2018, 13:42
                                        Спасибо большое за помощь. Уже докумекал. => вместо = писал. Туплю иногда)
                                    2. rumano
                                      rumano
                                      25.04.2017, 18:18
                                      Подскажите, пожалуйста, как сделать правильный bind.
                                      В этом коде:
                                      $criteria = $modx->newQuery('geodata');
                                      $criteria->select($modx->getSelectColumns('geodata'));
                                      $criteria->where("MATCH(city_name) AGAINST ('*:query*' IN BOOLEAN MODE)");
                                      $criteria->sortby('country_name', 'DESC');
                                      $criteria->prepare();
                                      $str="Моск";
                                      $criteria->stmt->execute(array('query'=>$str));
                                      $collection = $modx->getCollection('geodata', $criteria);
                                      
                                      и в этом параметры не устанавливаются и, как следствие, результат = 0;
                                      $str='Моск';
                                      $sql = "
                                          SELECT * 
                                          FROM
                                          	modx_geodata
                                          WHERE
                                          	MATCH(city_name) AGAINST ('*?*' IN BOOLEAN MODE)
                                      ";
                                      $statement = $modx->prepare($sql);
                                      $statement->bindValue(1, $str, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT);
                                      $result = $statement->execute();
                                      print_r($statement->rowCount());
                                      Спасибо.
                                      1. rumano
                                        rumano
                                        25.04.2017, 20:55
                                        Решил просто заэкранировать:
                                        $sQuery = 'Мос';
                                        // $sQuery = $modx->stripTags($sQuery);
                                        $sQuery = $modx->sanitizeString($sQuery);
                                        
                                        $criteria = $modx->newQuery('geodata');
                                        $criteria->select($modx->getSelectColumns('geodata'));
                                        $criteria->where("MATCH(city_name) AGAINST ('*{$sQuery}*' IN BOOLEAN MODE)");
                                        $criteria->sortby('country_name', 'DESC');
                                        // $criteria->prepare();
                                        //$criteria->stmt->execute();
                                        $collection = $modx->getCollection('geodata', $criteria, false);
                                        foreach($collection as $k => $v)
                                        {
                                            print_r($v->get('city_name') ."\n");
                                        }
                                      Войдите, пожалуйста, в аккаунт, чтобы оставить комментарий.