Как я расширил стандартную таблицу пользователей

В последнее время довольно часто приходится делать различные стартапы на заказ, суть которых сводится к платному сервису, с регистрацией, личным кабинетом, ну и как следствие каталогом пользователей, представляющих ту или иную услугу.

Обычно использую office, который обеспечивает готовый личный кабинет из коробки с минимальными усилиями, он же позволяет сохранять все в базу, пользователей. Но вот беда, полей катастрофически не хватает. Логичным решением было создавать страницы для каждого пользователя, и добавлять сколько угодно TV. Так я и делал, но решил заморочиться и не дублировать страницы, а расширить таблицу пользователей и работать с ней напрямую, как с ресурсом.

Вот что я сделал:

Шаг первый.
Добавил в таблицу modx_user_attributes дополнительное поле company_name (varchar 255 Utf-8 general-ci). Ничего не обычного. Если кто не понял этот пункт, то наверное еще рано читать эту статью

Шаг второй.
Далее воспользовался этой методикой, любезно рекомендованной Василием.
У меня получился вот такой вот плагин
<?php
switch ($modx->event->name) {
	case 'OnMODXInit':
    	$modx->loadClass('modUserProfile');
    	$modx->map['modUserProfile']['fields']['company_name'] = 0;
    	$modx->map['modUserProfile']['fieldMeta']['company_name'] = array(
    		'dbtype' => 'varchar',
    		'precision' => 255,
    		'phptype' => 'string',
    		'null' => true,
    	);    	
	break;
}
Плагин активируется при наступлении события OnMODXInit, который срабатывает сразу же при запуске MODX.

К этому моменту MODX уже распознал наше новое поле и может работать с ним как с родным.
Мы можем получить значение этого поля используя следующий сниппет
if ($modx->user->isAuthenticated()) {
	// Сохранить название компании
	$modx->user->Profile->set('company_name', $companyName);
	$modx->user->save();
	// Получить название компании
	return $modx->user->Profile->get('company_name');
}
Шаг третий.
В принципе этого УЖЕ достаточно для работы, но хотелось бы еще и в админке этими данными управлять. Это значит, что нам нужно на странице с полями пользователя добавить новое поле.
За это отвечает JS фреймворк extJS.
Открываем для редактирования файл manager/assets/modext/widgets/security/modx.panel.user.js
Здесь как раз лежат все поля, написанные на JavaScript.
Я хочу чтобы мое новое поле находилось после поля Fullname, нахожу в файле где у нас выводится это поле (ищем в коде строку name: 'fullname').
Мы видим, что за вывод данного поля у нас отвечает следующий блок
{
 id: 'modx-user-fullname'
,name: 'fullname'
,fieldLabel: _('user_full_name')
,xtype: 'textfield'
,anchor: '100%'
,maxLength: 255
},
Насколько я понимаю id у нас отвечает за label
name — это название поля в базе данных
fieldLabel — это строка записываемая в label, новую строку user_company_name добавляем в лексикон
xtype: 'textfield' — обычное текстовое поле
maxLength — доступное количество символов.

Скопировав этот блок и немного подредактировав данные я получаю такой код
{
 id: 'modx-user-company_name'
 ,name: 'company_name'
 ,fieldLabel: _('user_company_name')
 ,xtype: 'textfield'
 ,anchor: '100%'
 ,maxLength: 255
 }
Сохраняем, обновляем, и по идее вы должны увидеть в таблице новое текстовое поле. Если в базе это поле уже заполнено, данные должны погрузиться.

Почему не использовать extended поле?
В комментариях возник вопрос, почему бы не использовать специальное поле extended, которое позволяет без проблем хранить большой массив дополнительных полей.
Суть в том, что я хочу использовать свои дополнительные поля в расширенной таблице для того, чтобы на их основе можно было сортировать моих пользователей (страна, город, вид деятельности и т.п.)
Василий Наумкин (сто лет ему успешных разработок) предусмотрел такую возможность в своем компоненте mFilter2, но там можно использовать только отдельные поля. В extended же вся информация лежит в одном большом массиве, закодированном в формете JSON. Сортировать по нему не получится. Можно конечно написать велосипед, но будут проблемы со скоростью.
Николай Савин
30 марта 2016, 14:48
modx.pro
25
5 084
+6
Поблагодарить автора Отправить деньги

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

Григорий Коленько
30 марта 2016, 18:30
+1
Вообще немного заморочившись, ты можешь без изменения в стандартных скриптом при инициализации панели вставлять свое поле.

Ext.ComponentMgr.onAvailable("modx-user-tabs", function (e) {
var items = Ext.getCmp('modx-user-tabs').items;
}
Дальше уже пишешь логику для вставки поля. (На верность решения не претендую буду рад услышать, как это можно сделать лучше, без вмешательства в код modx).
    Николай Савин
    30 марта 2016, 20:21
    0
    Дойдем и до этого. Я пока extJS не освоил
      Илья Уткин
      31 марта 2016, 13:21
      2
      +4
      Стало интересно, не поленился, потестил и сделал плагинчик. Спасибо за наводку, сам теперь тоже буду пользоваться))
      <?php
      if ($modx->event->name == "OnUserFormPrerender") {
          $modx->controller->addHtml('<script type="text/javascript">
              Ext.ComponentMgr.onAvailable("modx-user-tabs", function (e) {
                  var items = Ext.getCmp("modx-user-tabs").items;
      
                  // Вкладка -> «тело» вкладки -> колонка
                  // 2 - пропускаем ID и username, 0 - ничего не удаляем
                  items[0].items[0].items[0].items.splice(2, 0, {
                   id: "modx-user-company_name"
                   ,name: "company_name"
                   ,fieldLabel: _("user_company_name")
                   ,xtype: "textfield"
                   ,anchor: "100%"
                   ,maxLength: 255
                  });
              });
          </script>');
      }
        Николай Савин
        31 марта 2016, 15:14
        0
        Илья, а как можно в данном случае указать позицию поля? Если я хочу чтобы данное поле было не вторым, а скажем четвертым по счету?
        UPD. Там же есть комментарий, что то я туплю.
        Спасибо за решение. Вырисовывается неплохой комплексный подход к задаче. Коллективный разум творит чудеса.
          Илья Уткин
          31 марта 2016, 15:18
          0
          Тут простая работа с массивом на JS.
          Можно, кстати, лишние поля удалить, чтобы не мешались
            Николай Савин
            31 марта 2016, 15:19
            0
            А можно пример, как удалить ненужное поле? Ну например Gender
              Илья Уткин
              31 марта 2016, 15:32
              0
              items[0].items[0].items[0].items.splice(15, 1);
              Только не запутаться бы в индексах…
              Сначала, думаю, надо удалять, а потом добавлять.
      Сергей Шлоков
      30 марта 2016, 19:59
      0
      Для описанной задачи вполне хватит поля extended из коробки.
      Конкретно это решение недоработанное. Вы про проблемы с обновлением помните?
        Николай Савин
        30 марта 2016, 20:27
        0
        Ну понятное дело что поля extended хватит, только вот я планирую использовать определенные поля для сортировки, ну например по городу или по сфере деятельности, а по extended фильтровать довольно сложно. Используя такой метод я планирую фильтровать через mFilter2.
        Про обновление я конечно помню. У нас по идее перезаписаться должен только extJS файл. Наверное правильно просто его сохранить и потом заменить.

        К сожалению, других доступных для меня пошаговых материалов я не нашел, сделал, как сумел.
        С радостью изучу предложенную Вами пошаговую альтернативу по расширению системных таблиц, с возможностью будущей фильтрации и безопасным обновлением.
          Сергей Шлоков
          30 марта 2016, 20:39
          0
          я планирую использовать определенные поля для сортировки
          Ну о данных планах в статье ничего не написано. Для хранения компании достаточно extended.
          Конечно предложенный вариант расширения таблицы пользователей гораздо лучше, чем TV или extended.
            Сергей Шлоков
            30 марта 2016, 21:49
            +1
            Николай, боюсь, что вашего плюса (если он ваш) я не заслужил, так как положительно я говорил только про ту часть, которую придумал Василий. А ваша реализация вызывает смешанные чувства. Сниппет лучше заменить. Например, на такой
            if ($modx->user->isAuthenticated()) {
            	// Сохранить название компании
            	$modx->user->Profile->set('company_name',$companyName);
            	$modx->user->save();
            	// Получить название компании
            	return $modx->user->Profile->get('company_name');
            }
            Правка ExtJs исходников решает задачу до первого обновления. Лучше сделать свой скрипт и подключать его используя вариант Григория.
            Тогда это будет готовое решение.
              Николай Савин
              31 марта 2016, 08:00
              0
              К сожалению моих знаний пока не хватает, чтобы понять что написал Григорий. В extJS я не разбираюсь совсем.
              Что касается вашего варианта сниппета… Ну тоже самое же написано, только запись сокращенная. Ровно ничего не изменится, кроме размера записи. Это как использовать тернарный оператор, вместо классического условия.
              Но все равно спасибо, я о таком варианте записи не знал.
                Сергей Шлоков
                31 марта 2016, 09:13
                0
                Ну тоже самое же написано, только запись сокращенная. Ровно ничего не изменится, кроме размера записи. Это как использовать тернарный оператор, вместо классического условия.
                Ну да, ну да.
                {private message}
                  Николай Савин
                  31 марта 2016, 09:28
                  0
                  Сергей, вы все правильно написали, я в начале пути и знаний маловато. Я сужу о коде и принимаю решения на основе своих знаний и того, что мне удалось найти и разобрать. И это нормально, что код не всегда получается оптимальный. Даже Apple сразу не сделали идеальный смартфон (Какая там уже сейчас версия, 7 вроде выходит)
                  Проблема только в том, что источников знаний для Junior разработчиков маловато.
                  Разве что документация, которая не всегда помогает. Все же кто поопытнее только свысока смотрят и посмеиваются, вместо того чтобы помочь разобраться, что да как.
                  В любом случае спасибо, парочку новых мыслей от Вас я узнал.

                  Ну по крайней мере я предложил решение, которое хоть как-то отвечает моим требованиям. Когда мне понадобилось решить эту задачу, ЗДЕСЬ пошагового решения не было. Пришлось убить на него несколько дней. Я надеюсь следующему разработчику, который решит также решить задачу будет проще с этой заметкой.
        Вадим
        02 мая 2016, 21:46
        +1
        Все же кто поопытнее только свысока смотрят и посмеиваются, вместо того чтобы помочь разобраться, что да как.
        На этот ваш посыл, могу привести ваши же слова несколькими абзацами ранее
        Если кто не понял этот пункт, то наверное еще рано читать эту статью
        Старую гвардию вы уже не исправите, а вот молодым и начинающим могли бы подавать пример толерантности, а не снобизма. Большинство философов утверждает, что надо начинать с себя, что бы изменить свой небольшой мирок.
        Так, что пусть читают и те кому
        еще рано
        , смотришь — у них появятся вопросы, а за ними и найдутся ответы :)
          Николай Савин
          02 мая 2016, 22:05
          0
          Вы приводите мои слова, вырванные из контекста. Данные слова были применены к фундаментальным основам программирования, и если человек не знаком с данными моментами, то данная статья ему действительно пока не нужна. Ему было бы правильнее разобраться с основами Баз данных, потому что работа с сайтом это прежде всего взаимодействие с информацией в базах данных.
          Если у кого то появляются вопросы — что ж, пусть задают. Я подскажу какой материал нужно изучить по данной тематике.
          Вадим
          02 мая 2016, 21:54
          0
          вот за пост спасибо! Полезный пример и информация для сообщества.
            Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
            17