Расширенные поля пользователей
Небольшая пошаговая инструкция, как научиться сохранять любые интересующие данные о юзере в специальное поле extended.
На самом деле, это никакой не секрет. Во многих объектах MODX есть специальное поле типа JSON, которое хранится в БД как текст, например, properties у modResource и extended у modUserProfile.
При работе с объектами xPDO, JSON текст из этих полей превращается в массивы. То есть, общий принцип выглядит так:

А теперь давайте напишем плагин, который будет сохранять данные о регистрации и последней активности пользователя, которые MODX сам, почему-то, не сохраняет.
Для плагина мы используем события OnUserSave и OnLoadWebDocument:

Для вывода пользователей я советую использовать сниппет pdoUsers, который обладает всеми основными возможностями pdoTools.
Если вызвать его без чанка, то он распечатает массив всех плейсхолдеров юзера, включая поле extended.

pdoTools выводит массивы плейсхолдеров через точку, поэтому нас интересуют [[+extended.lastactivity]] и [[+extended.registered]].

Можно использовать фильтры вывода или параметр &prepareSnippet, чтобы подготовить эти даты для вывода в более приятном виде.
Вот пример вывода с указанием &prepareSnippet:
А вот и сам сниппет prepareUser:
Из-за того, что в БД данные extended хранятся в виде JSON текста, по ним нельзя нормально осуществлять фильтрацию и сортировку.
Если вам нужно не просто выводить какие-то значения, то придётся написать дополнительную таблицу с id юзера и нужными колонками, чтобы сохранять данные в неё раздельно.
Тогда вы сможете присоединить эту таблицу в вызове сниппета pdoUsers и фильтровать\сортировать пользователяй по дополнительным полям.
На самом деле, это никакой не секрет. Во многих объектах MODX есть специальное поле типа JSON, которое хранится в БД как текст, например, properties у modResource и extended у modUserProfile.
При работе с объектами xPDO, JSON текст из этих полей превращается в массивы. То есть, общий принцип выглядит так:
// id нужного пользователя
$user_id = 15;
// Получаем объект modUser
if ($user = $modx->getObject('modUser', $user_id)) {
// Получаем связанный с ним профиль пользователя
if ($profile = $user->getOne('Profile')) {
// Получаем специальное поле extended
$extended = $profile->get('extended');
// Добавляем новое значение
$extended['mykey'] = 'mydata';
// И сохраняем обратно в профиль
$profile->set('extended', $extended);
$profile->save();
}
}Самое приятное, что эти данные вы можете не только просмотреть на странице пользователя, но и изменить.
Регистрация и активность
А теперь давайте напишем плагин, который будет сохранять данные о регистрации и последней активности пользователя, которые MODX сам, почему-то, не сохраняет.
Для плагина мы используем события OnUserSave и OnLoadWebDocument:
switch ($modx->event->name) {
case 'OnUserSave':
// Сохраняем дату создания нового пользователя
if ($user && $mode == 'new') {
if ($profile = $user->getOne('Profile')) {
$extended = $profile->get('extended');
$extended['registered'] = date('Y-m-d H:i:s');
$profile->set('extended', $extended);
$profile->save();
}
}
break;
case 'OnLoadWebDocument':
// Сохраняем дату открытия любой страницы сайта, если пользователь авторизован
if ($modx->user->isAuthenticated($modx->context->key)) {
// Здесь мы работаем с текущим пользователем - у него профиль уже загружен
$profile = $modx->user->Profile;
$extended = $profile->get('extended');
$extended['lastactivity'] = date('Y-m-d H:i:s');
$profile->set('extended', $extended);
$profile->save();
}
break;
}И вот, что у нас получается:
Вывод полей профиля
Для вывода пользователей я советую использовать сниппет pdoUsers, который обладает всеми основными возможностями pdoTools.
Если вызвать его без чанка, то он распечатает массив всех плейсхолдеров юзера, включая поле extended.

pdoTools выводит массивы плейсхолдеров через точку, поэтому нас интересуют [[+extended.lastactivity]] и [[+extended.registered]].
[[!pdoUsers?
&tpl=`@INLINE <p>[[+fullname]] - Регистрация: [[+extended.registered]], активность: [[+extended.lastactivity]]</p>`
]]
Можно использовать фильтры вывода или параметр &prepareSnippet, чтобы подготовить эти даты для вывода в более приятном виде.
Вот пример вывода с указанием &prepareSnippet:
[[!pdoPage?
&element=`pdoUsers`
&tpl=`tpl.Users.list.row`
&prepareSnippet=`prepareUser`
]]А вот и сам сниппет prepareUser:
<?php
// Комментарии юзера
$row['comments'] = $modx->getCount('TicketComment', array('createdby' => $row['id'], 'published' => 1));
// Тикеты
$row['tickets'] = $modx->getCount('Ticket', array('createdby' => $row['id'], 'class_key' => 'Ticket', 'published' => 1, 'deleted' => 0));
// Проверка и красивое форматирование дат через сниппет dateAgo
$row['registered'] = !empty($row['extended']['registered'])
? $modx->runSnippet('dateAgo', array('input' => $row['extended']['registered']))
: '-';
$row['lastactivity'] = !empty($row['extended']['lastactivity'])
? $modx->runSnippet('dateAgo', array('input' => $row['extended']['lastactivity']))
: '-';
return serialize($row);&prepareSnippet — это особенность pdoTools, можно использовать со всеми сниппетами.Недостатки
Из-за того, что в БД данные extended хранятся в виде JSON текста, по ним нельзя нормально осуществлять фильтрацию и сортировку.
Если вам нужно не просто выводить какие-то значения, то придётся написать дополнительную таблицу с id юзера и нужными колонками, чтобы сохранять данные в неё раздельно.
Тогда вы сможете присоединить эту таблицу в вызове сниппета pdoUsers и фильтровать\сортировать пользователяй по дополнительным полям.
Комментарии: 39
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
Жаль, что не посортируешь.
Еще такой вопрос. Плагин висит на OnUserSave, а в HybridAuth нет его вызова: github.com/bezumkin/modx-hybridauth/search?q=OnUserSave&ref=cmdform
Зато есть OnUserFormSave — github.com/bezumkin/modx-hybridauth/search?q=OnUserFormSave&type=Code, который судя по описанию, вызывается при сохранению пользователя из админки. Нестыковочка какая-то, или я упустил что?
Прошу совета: Хочу в Extended поле сохранить многострочный текст. Не понимаю, как сделать так, чтобы символы перевода строки учитывались. А то я получаю весь текст слепленный в одну строку.
Просто я хочу, чтобы в одной из настроек пользователя хранился шаблон письма. Чтобы у каждого пользователя был такой свой и он мог его редактировать как и весь Profile.
Буду очень признателен за помощь, сам ответ не смог найти.
Пытался туда html засунуть, тоже режется при выводе в textarea
Ticket связан с TicketThread через Ticket.id — TicketThread.resource, а TicketThread с TicketComment через TicketThread.id — TicketComment.thread.
Нужно 2 джойна и если комментариев много — будут тормоза.
Такое присоединение есть в старых версиях getTickets, потом я от него отказался и выбираю количество комментариев отдельно.
Вот пример:
На выходе — откровенная фигня. Числа берутся не пойму откуда… но явно не те)
p.s. если что это вопрос как тут modx.pro/users/ вывести кол-во постов и комментов.
Если нужно посчитать количество строк в двух разных таблицах — то нужна группировка и минимум 2 запроса.
Лично я использую &prepareSnippet и считаю строки уже в нём — и быстро и удобно.
А про постановку задачи понял… 1 джойн хорошо проходит, а 2 уже нельзя…
А вот если написать запрос с двумя джоинами и подсчетом количества комментариев для каждой страницы — может быть и 5 секунд. Особенно, если 2000 страниц и 30000 комментариев.
Короче, лучше много маленьких запросов, чем один большой.
Ну а я добавил эту информацию в заметку.
создал тип datetime но зараза туда только дата залетает…
время (часы, минуты, секунды) почему то все время по нулям присваивает…
ЧЯСНТ?
Если xPDO — то покажи схему таблицы, если SQL — то запрос.
плагин
данные в базу записываются, все нормально.
Теперь хочу присоединить таблицу к сниппету pdoUsers, делаю и в ответ получаю ругань
Если указываешь
Это значит, что файлы модели должны лежать в
Пример.
Если же ты прописываешь загрузку модели в системную настройку extension_packages, то loadModels вообще указывать не нужно — должно работать сразу.
а достаточно
Например таблицы Tickets и MS2 присоединяются свободно и без loadModels.
В любом случае, ошибки pdoTools пишутся в системный журнал.
теперь осталось разобраться с лексиконом запроса и дело в шляпе!)
Я ж все обычно тупо копирую с твоих примеров вот эти лефтджойны и селекты..., а че это такое — не вникал.
тупо написал, а оно взяло и заработало…
Что не ясно спрашивайте, я со своей стороны как малограмотный могу на пальцах обьяснить.)
А у меня пришла в голову мысль, что пора сделать такую таблицу для юзеров в Tickets по умолчанию. Хотя бы активность и дату регистрации фиксировать.
Как будет время — попробую добавить.
Как мне его вывести в данном куске кода?
Для удобного вывода extended-полей пользователя сделал себе сниппет extended в качестве фильтра.
Пример вызова:
Код сниппета extended:
Данный вызов для текущего пользователя, но можно смело подставлять id любого пользователя.
Может кому-нибудь пригодиться.
Решил это следующим образом в сниппете:
Не знаю, может есть и более красивое решение, чем подсовывать пробел на выводе…