Skip to content

Свои поля в формах ​

Самая частая задача после установки. Разберём на телефоне в регистрации.

Поле, которого нет в правилах, выбрасывается

Это не придирка валидатора, а защита: форма принимает только объявленные поля, иначе в неё можно подсунуть что угодно — например sudo или active. Поэтому любое новое поле надо объявить, даже если проверять в нём нечего ('nullable|string').

Если у поля есть колонка в базе ​

phone — колонка таблицы modx_user_attributes, MODX её знает. Тогда хватит двух правок, PHP-логику писать не нужно.

Правка первая — объявить поле. core/App/config/pbauth.php:

php
<?php

return [
    'rules' => [
        'register' => [
            'phone' => 'required|string|unique:user_attributes',
        ],
    ],
];

Читается так: телефон обязателен, это строка, и такого телефона ещё нет в таблице user_attributes.

Правка вторая — добавить поле в форму. В core/App/elements/auth/chunks/form.register.tpl, по образцу соседних:

html
<div class="form-group mb-3">
    <label class="mb-2" for="phone">Телефон</label>
    <input type="text" name="phone" id="phone"
           class="form-control{if $errors.phone} is-invalid{/if}"
           value="{$old_input.phone}" required>
    <span class="invalid-feedback" data-error="phone">{$errors.phone}</span>
</div>

Всё. Телефон сохранится сам.

Телефон потом работает и как логин

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

Если колонки в базе нет ​

Например, telegram. Такие поля MODX хранит в служебном поле extended — туда их надо положить самому. Первые две правки те же, добавляется третья.

Правка третья — маленький класс, который разложит поля.

core/App/Events/Auth/StoreExtendedFields.php:

php
<?php

namespace PageBlocks\App\Events\Auth;

class StoreExtendedFields
{
    protected const FIELDS = ['telegram', 'viber'];

    public function handle(array $params, string $event): void
    {
        $profile = $params['profile'] ?? null;
        $validated = $params['validated'] ?? [];

        if (!$profile) {
            return;
        }

        $extended = $profile->get('extended') ?: [];
        foreach (static::FIELDS as $field) {
            if (array_key_exists($field, $validated)) {
                $extended[$field] = $validated[$field] ?? '';
            }
        }

        $profile->set('extended', $extended);
    }
}

И сказать компоненту, когда его звать — перед сохранением пользователя:

php
<?php

use Boshnik\PbAuth\Events\Dispatcher;
use PageBlocks\App\Events\Auth\StoreExtendedFields;

return [
    'rules' => [
        'register' => ['telegram' => 'nullable|string'],
        'profile'  => ['telegram' => 'nullable|string'],
    ],
    'listeners' => [
        Dispatcher::USER_SAVING => [StoreExtendedFields::class],
    ],
];

Сохранять профиль внутри класса не нужно — компонент сохранит его сразу после.

USER_SAVING стреляет и при регистрации, и при правке профиля

Если поле нужно только в одном из двух случаев, смотрите на $params['action'] — там лежит register или profile.

Убрать поставочное поле ​

Задайте ему null и уберите из чанка формы:

php
'rules' => [
    'profile' => ['fullname' => null],
],

null именно убирает поле, а не делает его необязательным. Так сделано, чтобы ради одного лишнего поля не приходилось переписывать весь набор правил.

Частые правила проверки ​

ПравилоЧто значит
requiredобязательное
nullableможно оставить пустым
string, integerтип значения
emailпохоже на адрес почты
min:8, max:30длина
confirmedрядом должно быть поле имя_confirmation с тем же значением
unique:usersтакого значения ещё нет в таблице modx_users
exists:user_attributes,emailтакое значение в таблице есть
emptyполе обязано прийти пустым (ловушка для ботов)
excludeпроверить, но до сохранения не доносить
file, image, mimes:jpg,png, max:2048загружаемый файл

Правила пишутся через |: 'required|string|min:3|max:30'.

string у числовых логинов обязателен

Без него min и max сравнивают величину, а не длину, и логин 2385672156 проходит max:30 как число два с лишним миллиарда. Поэтому в поставочном правиле регистрации стоит required|string|alpha_dash:ascii|min:3|max:30|unique:users.

В unique: и exists: указывается имя таблицы, а не класс MODX

unique:users, unique:user_attributes — да. unique:modUser — нет: проверка молча не найдёт ничего и пропустит дубликат.

Чем занято honeypot ​

У форм входа, регистрации и восстановления есть поле honeypot с правилом empty: человек его не видит и не заполняет, бот заполняет. У всех форм, кроме входа, к нему добавлено exclude — проверить надо, а дальше оно не нужно.

Если собираете форму с нуля, оставьте это поле в разметке. И не переименовывайте его, не поправив правила.

Аватар ​

Поле newphoto в профиле уже объявлено:

php
'newphoto' => 'nullable|file|image|mimes:jpg,jpeg,png|max:2048|exclude',

Куда складывать файлы — настройка, :user_id подставляется:

php
'avatar_path' => 'assets/images/avatars/:user_id',

Путь сохраняется в photo профиля. Чтобы поднять предел размера, правьте max:2048 (килобайты) — и помните, что сверху его всё равно ограничивают upload_max_filesize и post_max_size в PHP.

Если поле не сохраняется ​

Два вопроса по порядку:

  1. Оно объявлено в rules? Всё, чего там нет, отбрасывается до сохранения.
  2. У него есть колонка в базе? Если нет — нужен класс на USER_SAVING, см. выше. Объявленное, но «не существующее» поле проходит проверку и тихо пропадает: MODX не знает, куда его записать.

pbAuth — вход, регистрация и профиль для PageBlocks