Привязка встроенных объектов к кастомным

В силу ряда причин, мне потребовалось в свой кастомный объект, имеющий свою таблицу в бд и наследующий xPDOSimpleObject, добавить привязку к стандартному объекту MODX. Например, modUser.
Сделать это с помощью aggregates и composites в схеме моего кастомного объекта не получилось (собственно, добавление в схему связи с нативным modx-объектом ни к чему не привело — связи не появилось). Я полагаю, это свзяано с тем, что в схеме modx.mysql.schema.xml свзяи с моим кастомным объектом как не было, так и нет.


Поскольку мне необходимы были дополнительные поля в атрибутах пользователя, а поле extended для этого не подходило в связи с необходимостью выборки по одному из дополнительных полей, я для пущего удобства, а так же из любви к искусству присвоил объект modUser переменной моего кастомного класса так, что самого пользователя можно получать без лишних телодвижений так:

$myCustomClassInstance->User instanceof modUser //true
То есть, мои кастомные классы содержат объекты, с которыми связаны, подобно нативным классам MODX. Например, объект класса modUser содержит в своих переменных так же и свзанные объекты, такие как профиль ($user->Profile), группу и т.д.

Чтобы этого добиться, надо взять файл, созданный после парсинга вашей схемы (подробно останавливаться на этом моменте не буду, на данном сайте она описана подробно, а так же у Василия есть целый учебный курс по созданию компонентов, гед этот вопрос так же отлично освещен) и описывающий наш кастомный класс. Как правило, все такие файлы изначально выглядят так:

<?php
class DSProfile extends xPDOSimpleObject {}


Чтобы при выполнении команды

$foo = $modx->getObject('DSProfile',$criteria);


Мы в переменной $foo получали объект нашего класса с привязанным к его переменной соответствующим объектом класса modUser, необходимо в нашем классе переопределить некоторые методы класса xPDOSimpleObject:

class DSProfile extends xPDOSimpleObject {

     public $User;

     public static function load(xPDO & $xpdo, $className, $criteria, $cacheFlag= true) {
          
          $thisObj = parent :: load($xpdo, $className, $criteria, $cacheFlag);
          $thisObj->User = $xpdo->getObject('modUser',$thisObj->userid);
          return $thisObj;
          
     }


Другими словами, мы сначала получаем инстанс объкта с полями, заполненными из БД (выполняем метод load родительского класса), а потом присваиваем переменной $User объект класса modUser стандартным методом xPDO :: getObject(), при этом, в качестве критерия используется значение поля userid нашего кастомного объекта.

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

$dsprofile = $modx->getObject('DSProfile', $id);

мы без лишних строк и усилий получаем сразу и связанный с ним объект modUser.

Если же нам надо получать так же и связанные объекты при получении коллекции наших кастомных объектов методом xPDO :: getCollection(), нужно для нашего кастомного класса переопределить так же и метод loadCollection таким образом:

public static function loadCollection(xPDO & $xpdo, $className, $criteria= null, $cacheFlag= true) {
          
          $collection = parent :: loadCollection($xpdo, $className, $criteria, $cacheFlag);
          $newCol = array();
          foreach($collection as $key => $item){
               $item->User = $xpdo->getObject('modUser', $item->userid);
               $newCol[$key] = $item;
          }
          
          return $newCol;
     }

Как мы видим, принцип действия такой же — выполняем одноименный метод родительского класса, получая массив объектов нашего класса по критерию, потом итерируем этот массив, добавляя каждому элементу к переменной $User соответствующий ему объект modUser.

Так же, если нужно удалять привязанный объект вместе с кастомным, при этом главный в этой связке именно кастомный, можно перегрузить так же метод класса remove.

public function remove(){
     
          if($op = $this->xpdo->getObject('modUser', ['id' => $this->userid])){
               $op->remove();
          }
          
          parent::remove();
     
     }

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

public function remove(){

	$this->User->remove();
	parent :: remove();

}

Здесь действуем в обратном порядке — сначала получаем и удаляем связанный объект, а потом выполняем метод remove родительского класса.

В итоге при выполнении $ourObject->remove() удалится из БД как сам наш объект, так и связанный с ним modUser.

Не уверен, возможно MODX предлагет более простой инструментарий для связывания стандартных и кастомных объектов, но я не нашел. За подсказку в комментариях буду очень благодарен.

Надеюсь, моя писанина сможет быть кому-то полезной:))
Антон Фомичёв
04 марта 2015, 10:42
modx.pro
5
2 035
+2

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

Василий Наумкин
04 марта 2015, 13:57
3
+2
Сделать это с помощью aggregates и composites в схеме моего кастомного объекта не получилось (собственно, добавление в схему связи с нативным modx-объектом ни к чему не привело — связи не появилось).
Вот здесь ты просто где-то ошибся.

К своему объекту можно привязать что угодно — для того и нужны aggregates и composites. Например, вот связь сервиса HybridAuth с юзером. Вот она же, но уже в самом классе.

А вот связать объект MODX со своим чуть сложнее, нужно проявить фантазию. Мне нравится делать это при загрузке metadata своей модели.
    Илья Ершов
    04 марта 2015, 15:04
    +1
    А вот связать объект MODX со своим чуть сложнее, нужно проявить фантазию. Мне нравится делать это при загрузке metadata своей модели.
    Как раз то что я искал последние 3 дня… Супер!
      Антон Фомичёв
      04 марта 2015, 16:35
      0
      Вот же блин, стока лишней работы, а вопрос всего лишь в одной строчке:)))

      Спасибо за подсказку, пойду всё нафик перепишу:))
      GrinRom
      05 марта 2015, 10:25
      0
      Мне тоже пригодилось, спасибо!)
        Илья Уткин
        05 марта 2015, 11:48
        +1
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        7