Дополнительные поля профиля юзера (не extended)



Разрабатываю проект, в котором необходимо было реализовать более простое редактирование дополнительных полей профиля, чем есть из коробки. К слову, неудобное редактирование — это не единственный минус нативного способа расширения профиля полями. Ни для кого не секрет, что фильтрацию по JSON полям нормально не осуществить, только костылями. Фактически, мне надо было получить решение, которое бы расширяло стандартный код MODX, не трогая исходники, дабы сохранить карму в порядке возможность обновления системы.
Пришёл к выводу, что буду расширять стандартную вкладку профиля «Общая информация». При желании можно чуть переписать код в событии OnUserFormPrerender и создать свою вкладку со своими полями.

Инструкция получения дополнительных полей, как на скриншоте выше

  1. Первым делом идём в phpMyAdmin (или что-то подобное) и создаём:
    • столбец new_checkbox в таблице modx_users:

      ALTER TABLE `modx_users` ADD `new_checkbox` TINYINT(1) UNSIGNED NOT NULL DEFAULT '1' ;
    • столбец new_field в таблице modx_user_attributes:

      ALTER TABLE `modx_user_attributes` ADD `new_field` VARCHAR(255) NOT NULL ;
     
  2. После этого нам осталось повесить плагин на события OnMODXInit и OnUserFormPrerender:
    switch ($modx->event->name) {
        case "OnMODXInit":
            $map = array(
                'modUser' => array(
                    'fields' => array(
                        'new_checkbox' => 1,
                    ),
                    'fieldMeta' => array(
                        'new_checkbox' => array(
                            'dbtype' => 'tinyint',
                            'precision' => '1',
                            'phptype' => 'boolean',
                            'attributes' => 'unsigned',
                            'null' => false,
                            'default' => 1,
                        ),
                    ),
                ),
                'modUserProfile' => array(
                    'fields' => array(
                        'new_field' => '',
                    ),
                    'fieldMeta' => array(
                        'new_field' => array(
                            'dbtype' => 'varchar',
                            'precision' => '255',
                            'phptype' => 'string',
                            'null' => false,
                        ),
                    ),
                ),
            );
    
            foreach ($map as $class => $data) {
                $modx->loadClass($class);
    
                foreach ($data as $tmp => $fields) {
                    if ($tmp == 'fields') {
                        foreach ($fields as $field => $value) {
                            foreach (array('fields', 'fieldMeta', 'indexes') as $key) {
                                if (isset($data[$key][$field])) {
                                    $modx->map[$class][$key][$field] = $data[$key][$field];
                                }
                            }
                        }
                    } elseif ($tmp == 'composites' || $tmp == 'aggregates') {
                        foreach ($fields as $alias => $relation) {
                            if (!isset($modx->map[$class][$tmp][$alias])) {
                                $modx->map[$class][$tmp][$alias] = $relation;
                            }
                        }
                    }
                }
            }
            break;
        
        case "OnUserFormPrerender":
            if (!isset($user) || $user->get('id') < 1) {
                return;
            }
    
            if (!$modx->getCount('modPlugin', array('name' => 'AjaxManager', 'disabled' => false))) {
                $data['new_checkbox'] = $user->new_checkbox ? 'true' : 'false';
                $data['new_field'] = htmlspecialchars($user->Profile->new_field);
    
                $modx->controller->addHtml("
                    <script type='text/javascript'>
                        Ext.ComponentMgr.onAvailable('modx-user-tabs', function() {
                            this.on('beforerender', function() {
                                // Получаем колонки первой вкладки
                                var leftCol = this.items.items[0].items.items[0].items.items[0];
                                var rightCol = this.items.items[0].items.items[0].items.items[1];
    
                                // Добавляем новое поле в левую колонку 4ым по счёту полем (перед полем 'Email')
                                leftCol.items.insert(4, 'modx-user-new-field', new Ext.form.TextField({
                                    id: 'modx-user-new-field',
                                    name: 'new_field',
                                    fieldLabel: 'Новое поле профиля',
                                    xtype: 'textfield',
                                    anchor: '100%',
                                    maxLength: 255,
                                    value: '{$data['new_field']}',
                                }));
    
                                // Добавляем чекбокс первым по счёту полем (перед чекбоксом 'Активный')
                                rightCol.items.insert(0, 'modx-user-new-checkbox', new Ext.form.Checkbox({
                                    id: 'modx-user-new-checkbox',
                                    name: 'new_checkbox',
                                    hideLabel: true,
                                    boxLabel: 'Новый чекбокс юзера',
                                    description: 'Описание нового чекбокса...',
                                    xtype: 'xcheckbox',
                                    inputValue: 1,
                                    listeners: {
                                        beforerender: function(that) {
                                            that.hiddenField = new Ext.Element(document.createElement('input')).set({
                                                type: 'hidden',
                                                name: that.name,
                                                value: 0,
                                            });
                                        },
                                        afterrender: function(that) {
                                            that.el.insertHtml('beforeBegin', that.hiddenField.dom.outerHTML);
                                        },
                                    },
                                    checked: {$data['new_checkbox']},
                                }));
                            });
                        });
                    </script>
                ");
            }
            break;
    }

Небольшое пояснение, что вообще делает этот плагин

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

Итого

Мы получаем свои дополнительные поля данных, встроенные в стандартный MODX, без использования JSON извращения, которое мы имеем из коробки.
31 may 2016, 01:36    Павел Гвоздь   
58    1977 +19

Comments (62)

  1. Павел Гвоздь 31 may 2016, 03:57 # +2
    Интересный момент в том, что эти поля можно вызывать во фронтенде, как обычные поля юзера:
    [[+modx.user.id:userinfo=`new_checkbox`]]
    [[+modx.user.id:userinfo=`new_field`]]
    или
    {0 | user : 'new_checkbox'}
    {0 | user : 'new_field'}
    1. Александр 31 may 2016, 06:27 # 0
      Здравствуйте! Возник вопрос: А если, допустим, необходимо добавление полей, но для одной категории юзеров одного набора, а для другой — другого. Например, для пациентов — номер карты, а для врачей — название специализации. Данный способ не подойдет?
      1. Павел Гвоздь 31 may 2016, 07:18 # 0
        Что значит «категории юзеров»? Как их разделять будешь? По участию в группе «Пациенты», «Врачи»?
        Вообще можно, если так, но надо понимать, что при назначении группы, смены набора полей происходить не будет. Ибо при входе на страницу редактирования юзера в код будет подгружен один набор полей для нужной группы, либо не будет подгружен никакой вообще, т.к. юзер не состоит ни в той, ни в другой группе. И когда мы будем менять группу у юзера на вкладке «Права доступа», то нам нужно будет совершать перезагрузку страницы вручную, чтобы подгрузить нужный набор полей.
        Проще создать отдельную вкладку для всех новых полей и там разделить их между собой либо подвкладками, как это сделано в новой версии miniShop2, либо FieldSet-ами.
        1. Василий Наумкин 31 may 2016, 11:20 # +3
          Насколько я вижу, он предлагает добавлять свои таблицы и хранить данные там. А потом выбирать своими сниппетами — это всё не очень удобно.

          Пашин способ проще, приятнее и более «родной» для всех компонентов системы.
        2. Антон Пастухов 31 may 2016, 12:38 # 0
          Меня смущает создание полей в БД вручную, без соответсвующего обновления классов xPDO
          1. Василий Наумкин 31 may 2016, 13:24 # +4
            Внимательно посмотри на плагин и не смущайся.
            1. Антон Пастухов 31 may 2016, 13:59 # 0
              И то правда
          2. Александр 01 june 2016, 05:27 # 0
            А возможно ли в качестве x-type указать не 'textfield', а собственный комбобокс. Например, изменив код плагина, вот так?
            $modx->controller->addHtml("
                            <script type='text/javascript'>
                                MODx.combo.moSpecializations = function(config) {
                                    config = config || {};
                                    Ext.applyIf(config,{
                                        name: 'specialization'
                                        ,hiddenName: 'specialization'
                                        ,displayField: 'title'
                                        ,valueField: 'id'
                                        ,fields: ['title','id']
                                        ,pageSize: 20
                                        ,url: 'core/components/medOffice/processors/'
                                        ,baseParams: {
                                            action: 'mgr/specialization/getlist'
                                        }
                                        ,typeAhead: true
                                        ,editable: true
                                    });
                                    MODx.combo.moSpecializations.superclass.constructor.call(this,config);
                                };
                                Ext.extend(MODx.combo.moSpecializations,MODx.combo.ComboBox);
                                Ext.reg('modx-combo-specialization',MODx.combo.moSpecializations);
                                
                                Ext.ComponentMgr.onAvailable('modx-user-tabs', function() {
                                    this.on('beforerender', function() {
                                        // Получаем колонки первой вкладки
                                        var leftCol = this.items.items[0].items.items[0].items.items[0];
                                        var rightCol = this.items.items[0].items.items[0].items.items[1];
            
                                        // Добавляем новое поле в левую колонку 4ым по счёту полем (перед полем 'Email')
                                        leftCol.items.insert(4, 'modx-user-new-field', new Ext.form.ComboBox({
                                            id: 'modx-user-new-field',
                                            name: 'specialization_id',
                                            fieldLabel: 'Специализация',
                                            xtype: 'modx-combo-specialization',
                                            anchor: '100%',
                                            maxLength: 255,
                                            value: '{$data['specialization_id']}',
                                        }));
            
                                        // Скрытое поле с нулевым значением, для корректной обработки чекбокса при сохранении
                                        ncb_hiddenField = new Ext.Element(document.createElement('input'));
                                        ncb_hiddenField.set({
                                            type: 'hidden',
                                            name: 'new_checkbox',
                                            value: 0,
                                        });
            
                                        // Добавляем чекбокс первым по счёту полем (перед чекбоксом 'Активный')
                                        rightCol.items.insert(0, 'modx-user-new-checkbox', new Ext.form.Checkbox({
                                            id: 'modx-user-new-checkbox',
                                            name: 'is_doctor',
                                            hideLabel: true,
                                            boxLabel: 'Доктор',
                                            description: 'Описание нового чекбокса...',
                                            xtype: 'xcheckbox',
                                            inputValue: 1,
                                            hiddenField: ncb_hiddenField,
                                            listeners: {
                                                afterrender: function(that) {
                                                    that.el.insertHtml('beforeBegin', ncb_hiddenField.dom.outerHTML);
                                                }
                                            },
                                            checked: {$data['is_doctor']},
                                        }));
                                    });
                                });
                            </script>
                        ");
            1. Павел Гвоздь 01 june 2016, 05:38 # +1
              А возможно проверить, а потом спрашивать, если что-то не получается и проблему не удаётся решить?) Тем более, для проверок есть замечательный хостинг с тестовым тарифом за 0 рублей.
              1. Александр 01 june 2016, 06:53 # 0
                Сделал. Получил ошибку. Но не знаю в чем ее причина.
                1. Павел Гвоздь 01 june 2016, 07:01 # +2
                  Возможно причина в том, что процессор getlist неправильно отдаёт данные для комбобокса. А возможно, что надо не
                  new Ext.form.ComboBox
                  а
                  new MODx.combo.moSpecializations
                  писать.
                  Я не могу сказать точно, тебе будет проще всё это проверить самому. И вообще, неплохо почитать исходники компонентов, которые уже делают что-то подобное, например miniShop2 и сравнить со своим кодом. А также, читать документацию по ExtJS 3.4. И пробовать, пробовать, пробовать… У меня только так получается разобраться с ошибками при написании компонентов.
            2. Abu 05 june 2016, 18:00 # 0
              Таким же макаром получилось выводить extended поле в главном табе пользователя.

              if (!$modx->getCount('modPlugin', array('name' => 'AjaxManager', 'disabled' => false))) {
                          
                          $profile = $user->getOne('Profile');
                          $extended = $profile->get('extended');
                          $field= $extended['field'];
                          
                          $data['extended-field'] = htmlspecialchars($field);
              	    
              	   ....
              
              Вопрос: как сделать так, чтобы все нормально сохранялось в поле extended, если хочется без доп таблиц?
              1. Павел Гвоздь 05 june 2016, 18:04 # 0
                Думаю возможно, но надо будет ещё вешать плагин на событие OnUserSave.

                если хочется без доп таблиц
                Тут нет доп таблиц, здесь ты расширяешь системную таблицу своими полями.
                1. Павел Гвоздь 05 june 2016, 18:08 # +2
                  Что-то подобное, на мой взгляд, должно быть на событии OnUserSave:
                  /* @var modUser $user */
                  if (!isset($user) || $user->get('id') < 1) {
                      return;
                  }
                  
                  if ($_REQUEST['HTTP_MODAUTH']) {
                      if ($_REQUEST['HTTP_MODAUTH'] == $modx->user->getUserToken($modx->context->get('key'))) {
                          // $modx->log(1, $this->modx->event->name .' '. print_r($_REQUEST,1));
                          
                          if (isset($_REQUEST['extended_field_1'])) {
                              // Здесь будет код, сохраняющий extended поле extended_field_1 в modUserProfile.extended
                          }
                      }
                  }
                2. Николай Загумённов 07 june 2016, 16:59 # -1
                  Интересно? а можно ли как-то переопределить гриду в тикетс?
                  Как ни пробую вставлять свой файл comments2.grid.js он все время расположен выше файлов тикетс. Как я понял, чтобы переопределение работало надо, чтобы свой файл подключался ниже файлов тикетс.
                  1. Павел Гвоздь 07 june 2016, 18:12 # 0
                    На событии OnBeforeManagerPageInit проверяешь $action['controller'] на соответствие нужному тебе значению и вставляешь такой код:
                    $modx->controller->addLastJavascript('/путь/до/js/файла.js);
                    1. Все равно файл выше проставляется:

                      1. Павел Гвоздь 07 june 2016, 22:12 # 0
                        А почему у тебя файл в папке с файлами тикетс лежит?
                        1. Потому что проверяю. Я уж подумал, что есть разница в месте расположении файла и проверил переместив его в другое место))
                        2. Максим Кузнецов 07 june 2016, 22:54 # 0
                          Возможно, стоит поэкспериментировать с параметром приоритета плагинов (вашего и tickets'a).
                          1. В Tickets скрипты админки вызываются в контролере.
                      2. Николай Загумённов 08 june 2016, 23:50 # +2
                        Спасибо Паше за помощь. Открыл для себя Ext.ComponentMgr.onAvailable.

                        Вот такой плагин получился и не надо создавать никаких comments2.grid.js.
                        <?php
                        switch ($modx->event->name) {
                            case 'OnBeforeManagerPageInit':
                                
                                if ($action['namespace'] == 'tickets' && $action['controller'] == 'index') {
                                    $modx->controller->addHtml("<script type='text/javascript'>
                                        Ext.ComponentMgr.onAvailable('tickets-home-tabs', function() {
                                            // Тут можно переопределять все что угодно
                                        });
                                    </script>");
                                }
                                break;
                        }
                        
                      3. Bluetenstadt 16 june 2016, 16:37 # 0
                        Дополнительные поля профиля юзера можно ли искать по ним как по простым tv? А то по extended не получается.
                        1. Павел Гвоздь 16 june 2016, 19:21 # 0
                          Не понял вопроса. Где искать? Каким способом реализован поиск?
                          1. Воеводский Михаил 16 june 2016, 21:36 # +1
                            По ним можно будет искать так же, как по username или fullname.
                          2. stas 20 july 2016, 07:13 # 0
                            С компонентом office не работает, начинаются глюки, при регистрации/авторизации офис начинает выдавать не те сообщения которые нужно, еще крашнулся емейл, отключил плагин, убрал поле из базы, но теперь не могу зарегить или войти через свой емейл, офис пишет что пользователь с таким емейлом уже существует, хотя всех пользователей удалил и у админа другой.
                            1. Павел Гвоздь 20 july 2016, 08:11 # 0
                              А у меня работает. Почему именно в этом проблему видишь?
                              1. stas 20 july 2016, 08:21 # 0
                                В общем понял следующее с емейлом разобрался, joxi.ru/12MD1VJI4zP4lm оказалось что из таблицы modx_users пользователь удалился а в таблицы modx_user_attributes пользователь остался, после удаления с емейлом все заработало, то есть с крашнутым емейлом все норм,
                                но в любом случае не понимаю как у вас работает, вот смотрите я включил ваш плагин и при регистрации выдает следующее joxi.ru/D2PDj6MId5Pdg2 хотя в пользователях его нет joxi.ru/ZrJXVE7h1BP962, после чего он добавляется joxi.ru/LmGEV7ktR0Pe5A, но сообщение на мыло не приходит и как можете заметить емейл добавляется не в поле емейл а в имя.
                                авторизация так же глючит я создал пользователя но мне выдает вот такое joxi.ru/D2PDj6MId5Ppg2
                                1. Павел Гвоздь 20 july 2016, 08:28 # 0
                                  Я не знаю, каким образом ты удалял пользователя, что он удалился только из таблицы _users, но точно каким-нибудь квадратно-гнездовым способом, не иначе. Интересно другое… почему ты до сих пор связываешь эти две проблемы? У меня стоит Office и на сайте внедрён этот способ. Всё великолепно работает и есть не просит… Возможно, ты что-то делаешь не так, где-нибудь в другом месте, что у тебя Office отрабатывает некорректно. Давай, ты попробуешь создать на modHost.pro тестовый сайт и воспроизведёшь данную проблему там, ткнув меня носом, что данный способ мешает работе пакета Office, а я утрусь и найду вариант решения проблемы? :)
                                  1. stas 20 july 2016, 08:49 # 0
                                    я бы с радостью, но office платный, его можно развернуть там бесплатно? Когда ваш плагин включен не добавляется в таблицу modx_user_attributes пользователь, а в modx_users добавляется, вот что заметил
                                    1. Павел Гвоздь 20 july 2016, 08:53 # 0
                                      Скинь доступ к сайту в личку, постараюсь выявить причину.
                                      1. stas 20 july 2016, 09:11 # 0
                                        Вы получили доступы? Ответе пожалуйста, а то не понятно отправилось или нет
                                        1. Павел Гвоздь 20 july 2016, 09:14 # 0
                                          Получил и причину, по всей видимости, уже нашёл. Плагин не будет работать корректно, если в базе нет какого-либо поля, используемого в плагине. В данном случае, не было поля new_field в таблице _user_attributes.
                                          Кстати, можно на «ты».

                                          — Обновлено
                                          Ну и как следствие, спокойно зарегистрировался на сайте со своим мылом через форму Office.
                                          1. stas 20 july 2016, 09:23 # 0
                                            Все верно, добавил сюда это поле _user_attributes и заработало! спасибо за оперативность!!!
                                            1. Павел Гвоздь 20 july 2016, 09:24 # 0
                                              Так, давай по порядку. Вижу ты зачем-то перенёс поле new_checkbox в таблицу _user_attributes практически прямо на моих глазах. Этого делать не нужно, по крайней мере, если хочешь, чтобы у тебя корректно всё работало. Перечитай пост о том, где нужно создавать new_checkbox, а где new_field. А потом сравни эту информацию с массивом $map, начинающимся со строки номер 4 данного плагина.

                                              спасибо за оперативность!!!
                                              Рад помочь.
                                              1. stas 20 july 2016, 09:30 # 0
                                                Я вроде допер в чем была проблема, этот плагин рассчитан на то что я добавлю и чек бокс и фиелд, а мне нужен только чек бокс и я фиелд не добавлял, поэтому глючило так получается?
                                                1. Павел Гвоздь 20 july 2016, 09:33 # 0
                                                  Нет. Этот плагин расчитан быть развёрнутым в умелых руках. Ну, то есть, порог вхождения здесь определённый есть. По крайней мере, нужно понимать, что делаешь, добавляя эти строки плагина на сайт. Если нужно только одно поле, то нужно вырезать определённые части плагина и переименовать поле так, как нужно тебе.

                                                  поэтому глючило так получается?
                                                  Именно!
                                                  1. stas 20 july 2016, 09:36 # 0
                                                    ок я понял, просто мой первый сайт на модиксе, пока не понимаю что добавляю и как работает плагин, учусь, спасибо еще раз!
                                                    1. Павел Гвоздь 20 july 2016, 09:38 # 0
                                                      Если сайт на MODX первый и с PHP есть определённые трудности, то лучше не нужно использовать это решение, т.к. опять же повторюсь:
                                                      порог вхождения здесь определённый есть
                                                      1. Николаевич 21 july 2016, 21:42 # 0
                                                        Подскажите, пожалуйста, почему не работает
                                                        <?php
                                                        $user = $modx->getUser();
                                                        echo $user->get('new_checkbox');
                                                        
                                                        1. Павел Гвоздь 21 july 2016, 23:33 # 0
                                                          Понятия не имею.
                                                          1. Николаевич 21 july 2016, 23:52 # 0
                                                            т.е. в сниппете никак не получить значение 'new_checkbox'?
                                                            1. Павел Гвоздь 21 july 2016, 23:53 # 0
                                                              Получить.
                                            2. Алексей 19 august 2016, 06:55 # 0
                                              Доброго времени суток!
                                              Поле типа minishop2-combo-autocomplete не показывает варианты выбора, пока не начнешь вводить первые буквы в поле ввода. Как сделать обычное поле select с несколькими статичными вариантами выбора?
                                              1. Павел Гвоздь 19 august 2016, 09:08 # 0
                                                Насколько мне известно, данный тип предназначен точно не для профиля пользователя, а для ресурсов.
                                                На счёт «как сделать» — присмотреться к КомбоБоксу. И вообще, почаще читать документацию той технологии, с которой работаешь. А также, смотреть на уже готовые решения, хотя бы в самом MODX Revolution.
                                                1. Алексей 19 august 2016, 09:42 # 0
                                                  Я извиняюсь, не знаю как так получилось — мой разум помутился и я промахнулся топиком :) Нужно больше спать. Поле товара минишоп мне нужно с вариантами выбора.
                                              2. Максим Степанов 07 october 2016, 06:49 # 0
                                                Здравствуйте. Помогите разобраться. Мне нужно добавить 2 текстовых поля. На данный момент плагин выглядит так
                                                <?php
                                                switch ($modx->event->name) {
                                                    case "OnMODXInit":
                                                        $map = array(
                                                            'modUser' => array(
                                                                'fields' => array(
                                                                    'executor' => 1,
                                                                ),
                                                                'fieldMeta' => array(
                                                                    'executor' => array(
                                                                        'dbtype' => 'tinyint',
                                                                        'precision' => '1',
                                                                        'phptype' => 'boolean',
                                                                        'attributes' => 'unsigned',
                                                                        'null' => false,
                                                                        'default' => 1,
                                                                    ),
                                                                ),
                                                            ),
                                                            'modUserProfile' => array(
                                                                'fields' => array(
                                                                    'surname' => '',
                                                                    'patronymic' => '',
                                                                ),
                                                                'fieldMeta' => array(
                                                                    'surname' => array(
                                                                        'dbtype' => 'varchar',
                                                                        'precision' => '255',
                                                                        'phptype' => 'string',
                                                                        'null' => false,
                                                                    ),
                                                                ),
                                                                'fieldMeta' => array(
                                                                    'patronymic' => array(
                                                                        'dbtype' => 'varchar',
                                                                        'precision' => '255',
                                                                        'phptype' => 'string',
                                                                        'null' => false,
                                                                    ),
                                                                ),
                                                            ),
                                                        );
                                                
                                                        foreach ($map as $class => $data) {
                                                            $modx->loadClass($class);
                                                
                                                            foreach ($data as $tmp => $fields) {
                                                                if ($tmp == 'fields') {
                                                                    foreach ($fields as $field => $value) {
                                                                        foreach (array('fields', 'fieldMeta', 'indexes') as $key) {
                                                                            if (isset($data[$key][$field])) {
                                                                                $modx->map[$class][$key][$field] = $data[$key][$field];
                                                                            }
                                                                        }
                                                                    }
                                                                } elseif ($tmp == 'composites' || $tmp == 'aggregates') {
                                                                    foreach ($fields as $alias => $relation) {
                                                                        if (!isset($modx->map[$class][$tmp][$alias])) {
                                                                            $modx->map[$class][$tmp][$alias] = $relation;
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                        break;
                                                    
                                                    case "OnUserFormPrerender":
                                                        if (!isset($user) || $user->get('id') < 1) {
                                                            return;
                                                        }
                                                
                                                        if (!$modx->getCount('modPlugin', array('name' => 'AjaxManager', 'disabled' => false))) {
                                                            $data['executor'] = $user->executor ? 'true' : 'false';
                                                            $data['surname'] = htmlspecialchars($user->Profile->surname);
                                                            $data['patronymic'] = htmlspecialchars($user->Profile->patronymic);
                                                
                                                            $modx->controller->addHtml("
                                                                <script type='text/javascript'>
                                                                    Ext.ComponentMgr.onAvailable('modx-user-tabs', function() {
                                                                        this.on('beforerender', function() {
                                                                            // Получаем колонки первой вкладки
                                                                            var leftCol = this.items.items[0].items.items[0].items.items[0];
                                                                            var rightCol = this.items.items[0].items.items[0].items.items[1];
                                                
                                                                            // Добавляем новое поле в левую колонку 3ым по счёту полем (перед полем 'Email')
                                                                            leftCol.items.insert(3, 'modx-user-new-field', new Ext.form.TextField({
                                                                                id: 'modx-user-new-field',
                                                                                name: 'surname',
                                                                                fieldLabel: 'Фамилия',
                                                                                xtype: 'textfield',
                                                                                anchor: '100%',
                                                                                maxLength: 255,
                                                                                value: '{$data['surname']}',
                                                                            }));
                                                                            
                                                                            leftCol.items.insert(4, 'modx-user-patronymic-field', new Ext.form.TextField({
                                                                                id: 'modx-user-patronymic-field',
                                                                                name: 'patronymic',
                                                                                fieldLabel: 'Отчество',
                                                                                xtype: 'textfield',
                                                                                anchor: '100%',
                                                                                maxLength: 255,
                                                                                value: '{$data['patronymic']}',
                                                                            }));
                                                
                                                                            // Скрытое поле с нулевым значением, для корректной обработки чекбокса при сохранении
                                                                            ncb_hiddenField = new Ext.Element(document.createElement('input'));
                                                                            ncb_hiddenField.set({
                                                                                type: 'hidden',
                                                                                name: 'executor',
                                                                                value: 0,
                                                                            });
                                                
                                                                            // Добавляем чекбокс первым по счёту полем (перед чекбоксом 'Активный')
                                                                            rightCol.items.insert(0, 'modx-user-new-checkbox', new Ext.form.Checkbox({
                                                                                id: 'modx-user-new-checkbox',
                                                                                name: 'executor',
                                                                                hideLabel: true,
                                                                                boxLabel: 'Исполнитель',
                                                                                description: 'Назначить пользователя исполнителем',
                                                                                xtype: 'xcheckbox',
                                                                                inputValue: 1,
                                                                                hiddenField: ncb_hiddenField,
                                                                                listeners: {
                                                                                    afterrender: function(that) {
                                                                                        that.el.insertHtml('beforeBegin', ncb_hiddenField.dom.outerHTML);
                                                                                    }
                                                                                },
                                                                                checked: {$data['executor']},
                                                                            }));
                                                                        });
                                                                    });
                                                                </script>
                                                            ");
                                                        }
                                                        break;
                                                }
                                                
                                                Оба поля в профиле есть, но сохраняется только одно patronymic. Поле surname очищается после сохранения. Подскажите как сохранить оба этих поля?
                                                1. Павел Гвоздь 07 october 2016, 10:38 # 0
                                                  У вас в $map массиве ошибка. Там, где вы формируете поля для объекта modUserProfile в fieldMeta должен быть список всех полей, а у вас 2 fieldMeta, следовательно второй перезаписывает первого.

                                                  Проще говоря, вместо:
                                                  'fieldMeta' => array(
                                                      'surname' => array(
                                                          'dbtype' => 'varchar',
                                                          'precision' => '255',
                                                          'phptype' => 'string',
                                                          'null' => false,
                                                      ),
                                                  ),
                                                  'fieldMeta' => array(
                                                      'patronymic' => array(
                                                          'dbtype' => 'varchar',
                                                          'precision' => '255',
                                                          'phptype' => 'string',
                                                          'null' => false,
                                                      ),
                                                  ),
                                                  Надо так:
                                                  'fieldMeta' => array(
                                                      'surname' => array(
                                                          'dbtype' => 'varchar',
                                                          'precision' => '255',
                                                          'phptype' => 'string',
                                                          'null' => false,
                                                      ),
                                                      'patronymic' => array(
                                                          'dbtype' => 'varchar',
                                                          'precision' => '255',
                                                          'phptype' => 'string',
                                                          'null' => false,
                                                      ),
                                                  ),
                                                  1. Максим Степанов 07 october 2016, 12:10 # 0
                                                    Большое спасибо. Все работает)
                                                2. stas 25 october 2016, 08:08 # 0
                                                  Здравствуйте мне нужно два чекбокс, проблем с текстовыми не возникло а чекбоксы не получается
                                                  <?php
                                                  switch ($modx->event->name) {
                                                      case "OnMODXInit":
                                                          $map = array(
                                                              'modUserProfile' => array(
                                                                  'fields' => array(
                                                                      'checkbox_my' => 1,
                                                                      'new_checkboxMy' => 1,
                                                                  ),
                                                                  'fieldMeta' => array(
                                                                      'checkbox_my' => array(
                                                                          'dbtype' => 'tinyint',
                                                                          'precision' => '1',
                                                                          'phptype' => 'boolean',
                                                                          'attributes' => 'unsigned',
                                                                          'null' => false,
                                                                          'default' => 1,
                                                                      ),
                                                                      'new_checkboxMy' => array(
                                                                          'dbtype' => 'tinyint',
                                                                          'precision' => '1',
                                                                          'phptype' => 'boolean',
                                                                          'attributes' => 'unsigned',
                                                                          'null' => false,
                                                                          'default' => 1,
                                                                      ),
                                                                  ),
                                                              ),
                                                          );
                                                  
                                                          foreach ($map as $class => $data) {
                                                              $modx->loadClass($class);
                                                  
                                                              foreach ($data as $tmp => $fields) {
                                                                  if ($tmp == 'fields') {
                                                                      foreach ($fields as $field => $value) {
                                                                          foreach (array('fields', 'fieldMeta', 'indexes') as $key) {
                                                                              if (isset($data[$key][$field])) {
                                                                                  $modx->map[$class][$key][$field] = $data[$key][$field];
                                                                              }
                                                                          }
                                                                      }
                                                                  } elseif ($tmp == 'composites' || $tmp == 'aggregates') {
                                                                      foreach ($fields as $alias => $relation) {
                                                                          if (!isset($modx->map[$class][$tmp][$alias])) {
                                                                              $modx->map[$class][$tmp][$alias] = $relation;
                                                                          }
                                                                      }
                                                                  }
                                                              }
                                                          }
                                                          break;
                                                      
                                                      case "OnUserFormPrerender":
                                                          if (!isset($user) || $user->get('id') < 1) {
                                                              return;
                                                          }
                                                  
                                                          if (!$modx->getCount('modPlugin', array('name' => 'AjaxManager', 'disabled' => false))) {
                                                              $data['checkbox_my'] = $user->Profile->checkbox_my ? 'true' : 'false';
                                                              $data['new_checkboxMy'] = $user->Profile->new_checkboxMy ? 'true' : 'false';
                                                  
                                                              $modx->controller->addHtml("
                                                                  <script type='text/javascript'>
                                                                      Ext.ComponentMgr.onAvailable('modx-user-tabs', function() {
                                                                          this.on('beforerender', function() {
                                                                              
                                                                              var leftCol = this.items.items[0].items.items[0].items.items[0];
                                                                              var rightCol = this.items.items[0].items.items[0].items.items[1];
                                                                              
                                                  
                                                                              ncb_hiddenField = new Ext.Element(document.createElement('input'));
                                                                              ncb_hiddenField.set({
                                                                                  id: 'check_hidden',
                                                                                  type: 'hidden',
                                                                                  name: 'checkbox_my',
                                                                                  value: 0,
                                                                              });
                                                  
                                                  
                                                                              rightCol.items.insert(0, 'modx-user-new-checkbox1', new Ext.form.Checkbox({
                                                                                  id: 'modx-user-new-checkbox1',
                                                                                  name: 'checkbox_my',
                                                                                  hideLabel: true,
                                                                                  boxLabel: 'Мой чекбокс юзера',
                                                                                  description: 'Описание нового чекбокса...',
                                                                                  xtype: 'xcheckbox',
                                                                                  inputValue: 1,
                                                                                  hiddenField: ncb_hiddenField,
                                                                                  listeners: {
                                                                                      afterrender: function(that) {
                                                                                          that.el.insertHtml('beforeBegin', ncb_hiddenField.dom.outerHTML);
                                                                                      }
                                                                                  },
                                                                                  checked: {$data['checkbox_my']},
                                                                              }));
                                                                              
                                                  
                                                                              ncb_hiddenField = new Ext.Element(document.createElement('input'));
                                                                              ncb_hiddenField.set({
                                                                                  id: 'check_hidden1',
                                                                                  type: 'hidden',
                                                                                  name: 'new_checkboxMy',
                                                                                  value: 0,
                                                                              });
                                                  
                                                  
                                                                              leftCol.items.insert(0, 'modx-user-new-checkbox2', new Ext.form.Checkbox({
                                                                                  id: 'modx-user-new-checkbox2',
                                                                                  name: 'new_checkboxMy',
                                                                                  hideLabel: true,
                                                                                  boxLabel: 'Левый мой чекбокс',
                                                                                  description: 'Описание нового чекбокса...',
                                                                                  xtype: 'xcheckbox',
                                                                                  inputValue: 1,
                                                                                  hiddenField: ncb_hiddenField,
                                                                                  listeners: {
                                                                                      afterrender: function(that) {
                                                                                          that.el.insertHtml('beforeBegin', ncb_hiddenField.dom.outerHTML);
                                                                                      }
                                                                                  },
                                                                                  checked: {$data['new_checkboxMy']},
                                                                              }));
                                                                          });
                                                                      });
                                                                  </script>
                                                              ");
                                                          }
                                                          break;
                                                  }
                                                  
                                                  как я понял проблема тут
                                                  ncb_hiddenField = new Ext.Element(document.createElement('input'));
                                                                              ncb_hiddenField.set({
                                                                                  id: 'check_hidden1',
                                                                                  type: 'hidden',
                                                                                  name: 'new_checkboxMy',
                                                                                  value: 0,
                                                                              });
                                                  айдишник check_hidden заменяется check_hidden1 и получается два чекбокса с одним айди, как это исправить? или не в этом проблема?
                                                  1. Павел Гвоздь 25 october 2016, 10:53 # +2
                                                    Id там вообще не нужно указывать для скрытого поля. Поправил немного код плагина в посте, чтобы таких моментов не возникало больше. Вот код, который ставит на страницу 2 чекбокса — откорректируй под себя:
                                                    switch ($modx->event->name) {
                                                        case "OnMODXInit":
                                                            $map = array(
                                                                'modUserProfile' => array(
                                                                    'fields' => array(
                                                                        'cb1' => 1,
                                                                        'cb2' => 1,
                                                                    ),
                                                                    'fieldMeta' => array(
                                                                        'cb1' => array(
                                                                            'dbtype' => 'tinyint',
                                                                            'precision' => '1',
                                                                            'phptype' => 'boolean',
                                                                            'attributes' => 'unsigned',
                                                                            'null' => false,
                                                                            'default' => 1,
                                                                        ),
                                                                        'cb2' => array(
                                                                            'dbtype' => 'tinyint',
                                                                            'precision' => '1',
                                                                            'phptype' => 'boolean',
                                                                            'attributes' => 'unsigned',
                                                                            'null' => false,
                                                                            'default' => 1,
                                                                        ),
                                                                    ),
                                                                ),
                                                            );
                                                    
                                                            foreach ($map as $class => $data) {
                                                                $modx->loadClass($class);
                                                    
                                                                foreach ($data as $tmp => $fields) {
                                                                    if ($tmp == 'fields') {
                                                                        foreach ($fields as $field => $value) {
                                                                            foreach (array('fields', 'fieldMeta', 'indexes') as $key) {
                                                                                if (isset($data[$key][$field])) {
                                                                                    $modx->map[$class][$key][$field] = $data[$key][$field];
                                                                                }
                                                                            }
                                                                        }
                                                                    } elseif ($tmp == 'composites' || $tmp == 'aggregates') {
                                                                        foreach ($fields as $alias => $relation) {
                                                                            if (!isset($modx->map[$class][$tmp][$alias])) {
                                                                                $modx->map[$class][$tmp][$alias] = $relation;
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                            break;
                                                        
                                                        case "OnUserFormPrerender":
                                                            if (!isset($user) || $user->get('id') < 1) {
                                                                return;
                                                            }
                                                    
                                                            if (!$modx->getCount('modPlugin', array('name' => 'AjaxManager', 'disabled' => false))) {
                                                                $data['cb1'] = $user->Profile->cb1 ? 'true' : 'false';
                                                                $data['cb2'] = $user->Profile->cb2 ? 'true' : 'false';
                                                    
                                                                $modx->controller->addHtml("
                                                                    <script type='text/javascript'>
                                                                        Ext.ComponentMgr.onAvailable('modx-user-tabs', function() {
                                                                            this.on('beforerender', function() {
                                                                                var rightCol = this.items.items[0].items.items[0].items.items[1];
                                                    
                                                                                rightCol.items.insert(0, 'modx-user-cb1', new Ext.form.Checkbox({
                                                                                    id: 'modx-user-cb1',
                                                                                    name: 'cb1',
                                                                                    hideLabel: true,
                                                                                    boxLabel: 'Новый чекбокс юзера 1',
                                                                                    description: 'Описание нового чекбокса...',
                                                                                    xtype: 'xcheckbox',
                                                                                    inputValue: 1,
                                                                                    listeners: {
                                                                                        beforerender: function(that) {
                                                                                            that.hiddenField = new Ext.Element(document.createElement('input')).set({
                                                                                                type: 'hidden',
                                                                                                name: that.name,
                                                                                                value: 0,
                                                                                            });
                                                                                        },
                                                                                        afterrender: function(that) {
                                                                                            that.el.insertHtml('beforeBegin', that.hiddenField.dom.outerHTML);
                                                                                        },
                                                                                    },
                                                                                    checked: {$data['cb1']},
                                                                                }));
                                                                                
                                                                                rightCol.items.insert(0, 'modx-user-cb2', new Ext.form.Checkbox({
                                                                                    id: 'modx-user-cb2',
                                                                                    name: 'cb2',
                                                                                    hideLabel: true,
                                                                                    boxLabel: 'Новый чекбокс юзера 2',
                                                                                    description: 'Описание нового чекбокса...',
                                                                                    xtype: 'xcheckbox',
                                                                                    inputValue: 1,
                                                                                    listeners: {
                                                                                        beforerender: function(that) {
                                                                                            that.hiddenField = new Ext.Element(document.createElement('input')).set({
                                                                                                type: 'hidden',
                                                                                                name: that.name,
                                                                                                value: 0,
                                                                                            });
                                                                                        },
                                                                                        afterrender: function(that) {
                                                                                            that.el.insertHtml('beforeBegin', that.hiddenField.dom.outerHTML);
                                                                                        }
                                                                                    },
                                                                                    checked: {$data['cb2']},
                                                                                }));
                                                                            });
                                                                        });
                                                                    </script>
                                                                ");
                                                            }
                                                            break;
                                                    }
                                                  2. Игорь Терентьев 29 october 2016, 00:17 # 0
                                                    У вас там ошибка небольшая (в посте), из-за которой я около часа протупил :)
                                                    $data['new_checkbox'] = $user->new_checkbox ? 'true' : 'false';
                                                    А нужно:
                                                    $data['new_checkbox'] = $user->Profile->new_checkbox ? 'true' : 'false';
                                                    1. Павел Гвоздь 29 october 2016, 21:53 # +1
                                                      Да нет, в посте такого быть не должно… Может быть вы поменяли массив $map у себя, перенеся поле new_checkbox из modUser в modUserProfile, поэтому у вас такая ошибка была, но если почитаете код, который есть в посте, то там всё корректно.
                                                      1. Игорь Терентьев 29 october 2016, 23:11 # 0
                                                        Точно!
                                                        На это не обратил внимания:) Спасибо за разъяснение.
                                                        А в чем принципиальная разница в какой таблице хранить данные? Я добавил все 6 полей в modUserProfile.
                                                        1. Павел Гвоздь 29 october 2016, 23:16 # +1
                                                          Разница только в их доступности из того или иного класса, на мой взгляд. Если вам проще доставать их из modUserProfile, не делая лишнего обращения к базе, то пожалуйста.
                                                    2. Гриборий 24 november 2016, 02:03 # 0
                                                      Приветствую. Было бы совсем здорово еще добавить новые поля в табличку на странице со всеми пользователями, с возможностью поиска и сортировки по ним.
                                                      1. Владимир Тельнов 17 march 2017, 21:33 # 0
                                                        Подскажите, пожалуйста, каким образом можно внести изменения в поля new_checkbox и new_field из фронэнда?
                                                        В частности со страницы редактирования профиля Office и на странице создания заказа MiniShop?

                                                        Что то простое вида:
                                                        <input type="text" name="new_field" placeholder="" value="[[+modx.user.id:userinfo=`new_field`]]"/>/code>
                                                        Данные из новых полей отображаются, но перезаписать или задать новые данные не получается.
                                                        
                                                        Догадываюсь, что нужно плагин прикрепить к каким либо событиям, но не знаю к каким.
                                                        
                                                        Спасибо.
                                                        
                                                        
                                                        1. Владимир Тельнов 18 march 2017, 01:58 # 0
                                                          Разобрался.

                                                          У меня стояла задача добавить поля «Дом» и «Номер квартиры» в профиль пользователя и отображать содержимое этих полей при создании нового заказа в miniShop2. Поля building и room — это единственные поля, которые не совпадают с полями в стандартном профиле пользователя, в результате чего при создании нового заказа приходится указывать номер дома и квартиры каждый раз в ручную.

                                                          Выполнил инструкцию из первого поста. После чего внес изменения в параметры сниппета officeProfile и в чанки tpl.msOrder (miniShop2), tpl.Office.profile.form (Office)

                                                          Для отображения нового поля в профиле в параметрах сниппета officeProfile, в раздел profileFields необходимо добавить поле new_field и соответствующее поле input
                                                          <input type="text" name="new_field" placeholder="" value="[[+modx.user.id:userinfo=`new_field`]]"/>
                                                          
                                                          Для отображения нового поля при создании нового заказа в чанке tpl.msOrder отредактировал соответсвущий input
                                                          {foreach ['building'] as $field}
                                                          	<input type="text" id="{$field}" placeholder="{('ms2_frontend_' ~ $field) | lexicon}"
                                                          	name="{$field}" value="[[+modx.user.id:userinfo=`new_field`]]"
                                                          	class="form-control{($field in list $errors) ? ' error' : ''}">                      
                                                          {/foreach}
                                                          
                                                        2. Dmitry L. 09 may 2017, 13:37 # 0
                                                          Товарищи, разобрали как сделать текстовые поля и чек-боксы. Можно добавить изображение? Как «photo».
                                                          А то я сделал два поля, которые:
                                                          1) Не работают (ставлю галки на вкладке «Системные события» напротив OnMODXInit и OnUserFormPrerender у плагина — блок «Пользователи» не рендериться)
                                                          2) Просто текстовые

                                                          switch ($modx->event->name) {
                                                              case "OnMODXInit":
                                                                  $map = array(
                                                                      'modUser' => array(
                                                                          'fields' => array(
                                                                              'photo01' => '',
                                                                          ),
                                                                          'fieldMeta' => array(
                                                                              'photo01' => array(
                                                                                  'dbtype' => 'varchar',
                                                                                  'precision' => '1',
                                                                                  'phptype' => 'string',
                                                                                  'null' => false,
                                                                              ),
                                                                          ),
                                                                      ),
                                                                      'modUserProfile' => array(
                                                                          'fields' => array(
                                                                              'photo02' => '',
                                                                          ),
                                                                          'fieldMeta' => array(
                                                                              'photo02' => array(
                                                                                  'dbtype' => 'varchar',
                                                                                  'precision' => '255',
                                                                                  'phptype' => 'string',
                                                                                  'null' => false,
                                                                              ),
                                                                          ),
                                                                      ),
                                                                  );
                                                          
                                                                  foreach ($map as $class => $data) {
                                                                      $modx->loadClass($class);
                                                          
                                                                      foreach ($data as $tmp => $fields) {
                                                                          if ($tmp == 'fields') {
                                                                              foreach ($fields as $field => $value) {
                                                                                  foreach (array('fields', 'fieldMeta', 'indexes') as $key) {
                                                                                      if (isset($data[$key][$field])) {
                                                                                          $modx->map[$class][$key][$field] = $data[$key][$field];
                                                                                      }
                                                                                  }
                                                                              }
                                                                          } elseif ($tmp == 'composites' || $tmp == 'aggregates') {
                                                                              foreach ($fields as $alias => $relation) {
                                                                                  if (!isset($modx->map[$class][$tmp][$alias])) {
                                                                                      $modx->map[$class][$tmp][$alias] = $relation;
                                                                                  }
                                                                              }
                                                                          }
                                                                      }
                                                                  }
                                                                  break;
                                                              
                                                              case "OnUserFormPrerender":
                                                                  if (!isset($user) || $user->get('id') < 1) {
                                                                      return;
                                                                  }
                                                          
                                                                  if (!$modx->getCount('modPlugin', array('name' => 'AjaxManager', 'disabled' => false))) {
                                                                      $data['photo01'] = htmlspecialchars($user->Profile->photo01);
                                                                      $data['photo02'] = htmlspecialchars($user->Profile->photo02);
                                                          
                                                                      $modx->controller->addHtml("
                                                                          <script type='text/javascript'>
                                                                              Ext.ComponentMgr.onAvailable('modx-user-tabs', function() {
                                                                                  this.on('beforerender', function() {
                                                                                      // Получаем колонки первой вкладки
                                                                                      var leftCol = this.items.items[0].items.items[0].items.items[0];
                                                                                      var rightCol = this.items.items[0].items.items[0].items.items[1];
                                                          
                                                                                      rightCol.items.insert(14, 'modx-user-photo01', new Ext.form.photo02({
                                                                                          id: 'modx-user-new-field',
                                                                                          name: 'photo02',
                                                                                          fieldLabel: 'Фото 02',
                                                                                          xtype: 'image',
                                                                                          anchor: '100%',
                                                                                          maxLength: 255,
                                                                                          value: '{$data['photo02']}',
                                                                                      }));
                                                          
                                                                                      rightCol.items.insert(13, 'modx-user-photo02', new Ext.form.photo01({
                                                                                          id: 'modx-user-new-checkbox',
                                                                                          name: 'photo01',
                                                                                          fieldLabel: 'Фото 01',
                                                                                          xtype: 'image',
                                                                                          anchor: '100%',
                                                                                          maxLength: 255,
                                                                                          value: '{$data['photo01']}',
                                                                                      }));
                                                                                  });
                                                                              });
                                                                          </script>
                                                                      ");
                                                                  }
                                                                  break;
                                                          }
                                                          1. Sergey 16 may 2017, 18:29 # 0
                                                            Всем доброго времени суток!
                                                            У меня возникла необходимость вынести дополнительное поле в отдельную вкладку, но при добавлении параметра «value» она у меня почему-то не отображается, без этого параметра все выводиться, помогите пожалуйста разобраться в чем моя ошибка, вот так я добавляю новую вкладку и вывожу в ней дополнительное поле:

                                                            $modx->regClientStartupHTMLBlock('
                                                               <script type="text/javascript">
                                                                  MODx.on("ready",function() {
                                                                     MODx.addTab("modx-user-tabs",{
                                                                        title: "Доп. поля",
                                                                        width: "95%",
                                                                        items: [{
                                                                           id: "modx-user-new-field",
                                                                           name: "new_field",
                                                                           fieldLabel: "Новое поле профиля",
                                                                           xtype: "textfield",
                                                                           anchor: "100%",
                                                                           maxLength: 255,
                                                                           value: "{$data["new_field"]}",
                                                                        }]
                                                                     });
                                                                  });
                                                               </script>');
                                                            За ранее благодарен за оказанную помощь.
                                                            1. Sergey 18 may 2017, 17:53 # 0
                                                              Всем спасибо, удалось самостоятельно разобраться со своей проблемой, оказалось, что все дело было в синтаксисе, просто необходимо было заменить кавычки на апостроф, а апостроф на кавычки. :)
                                                            You need to login to create comments.