Николай Ланец
5 окт. 2014 г., 8:26

ООП методы xPDOObject::__set() и xPDOObject::set()

Материал для экспертов.
Рассмотрим краткий пример:
$user = $modx->getObject('modUser', $id); print_r($user->Profile->toArray());
В результате выполнения кода, если был получен объект пользователя, мы видим данные профиля modUserProfile (или фатальную ошибку за попытку выполнения метода на non-object переменной :)).
Итак, давайте еще раз попытаемся проследить: мы получаем объект $user, и тут же пытаемся вывести данные профиля пользователя $user->Profile->toArray(), то есть переменная $user->Profile это как будто $user->Profile = $user->getOne('Profile'). Но ведь мы этого здесь не делали. Или может это делает xPDO автоматически в методе xPDO::getObject()? Нет, он там этого не делает...
За эту магию отвечают ООП методы xPDOObject::__set() и xPDOObject::__get() (смотрите исходники на гитхабе). Дело в том, что в методах __get() и __set() сразу прописана работа со связями getOne()/addOne() и т.д. и т.п. В нашем случае, когда мы обратились к необъявленной переменной $user->Profile, xPDOObject проверил свои aggregates/composites-связи, и найдя в них связь modUserProfile/Profile, выполнил $this->Profile = $this->getOne('Profile'). Таким образом у нас и появилась переменная-объект $user->Profile.
Этот механизм работает и в другую сторону, то есть в добавление объекта. Рассмотрим код:
$user = $modx->newObject('modUser', $user_data); $profile = $modx->newObject('modUserProfile', $profile_data); $user->Profile = $profile; $user->save();
Здесь, при сохранении, мы в базе данных будем иметь как запись пользователя, так и запись его профиля, так как в момент $user->Profile = $profile по сути выполнилось $user->addOne($profile), и при сохранении основного объекта сохранился и связанный с ним объект профиля (за это отвечает метод xPDOObject::_saveRelatedObjects(), выполняемый в методе xPDOObject::save() (дважды :))).
Вообще все это очень удобно при работе с xPDO-объектами, особенно в Smarty-шаблонах. К примеру вот такой небольшой код:
Пользователь: {$modx->user->Profile->fullname|default:$modx->user->username}
Здесь будет подставлено ФИО (если оно прописано в профиле) или username. При этом не надо париться был ранее получен из БД объект профиля пользователя или нет. Если не был получен, то будет получен. Если уже был получен (и является свойством объекта пользователя $modx->user), то повторного запроса к БД не будет, будет сразу возвращен текущий объект, так что и за нагрузку не приходится беспокоиться. Кстати, тут помарка: если при выполнении запроса к БД не был получен объект, то при повторном обращении к этой переменной будет опять выполнен запрос к БД, ибо значения переменной нет, и нет объекта.
В случаи работы с update пользователя и его профиля очень удобно, а вот если список пользователей вывести нужно, не лучше ли это через join делать?
Понят но дело что под каждую задачу выбирается свой инструмент. Для списка пользователей работа с объектам вообще не обязательна (в смысле, с объектами пользователей), просто выполнил запрос к БД и вывел данные. Конечно же в данном случае join-ы в помощь.

Добавить комментарий