Свои поля в формах
Самая частая задача после установки. Разберём на телефоне в регистрации.
Поле, которого нет в правилах, выбрасывается
Это не придирка валидатора, а защита: форма принимает только объявленные поля, иначе в неё можно подсунуть что угодно — например sudo или active. Поэтому любое новое поле надо объявить, даже если проверять в нём нечего ('nullable|string').
Если у поля есть колонка в базе
phone — колонка таблицы modx_user_attributes, MODX её знает. Тогда хватит двух правок, PHP-логику писать не нужно.
Правка первая — объявить поле. core/App/config/pbauth.php:
<?php
return [
'rules' => [
'register' => [
'phone' => 'required|string|unique:user_attributes',
],
],
];Читается так: телефон обязателен, это строка, и такого телефона ещё нет в таблице user_attributes.
Правка вторая — добавить поле в форму. В core/App/elements/auth/chunks/form.register.tpl, по образцу соседних:
<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
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
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 и уберите из чанка формы:
'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 в профиле уже объявлено:
'newphoto' => 'nullable|file|image|mimes:jpg,jpeg,png|max:2048|exclude',Куда складывать файлы — настройка, :user_id подставляется:
'avatar_path' => 'assets/images/avatars/:user_id',Путь сохраняется в photo профиля. Чтобы поднять предел размера, правьте max:2048 (килобайты) — и помните, что сверху его всё равно ограничивают upload_max_filesize и post_max_size в PHP.
Если поле не сохраняется
Два вопроса по порядку:
- Оно объявлено в
rules? Всё, чего там нет, отбрасывается до сохранения. - У него есть колонка в базе? Если нет — нужен класс на
USER_SAVING, см. выше. Объявленное, но «не существующее» поле проходит проверку и тихо пропадает: MODX не знает, куда его записать.