SLOT-H: JSON-данные



В системе предусмотрен механизм хранения данных в формате JSON для полей, которые:
- могут отсутствовать у разных записей
- не используются в поиске
- не требуют индексации
- нуждаются в гибкой структуре, которая может меняться без изменения схемы БД




Назначение



JSON-поля позволяют хранить произвольные наборы данных без необходимости создавать отдельные колонки в таблице. Это удобно для:

- дополнительных настроек пользователей
- метаданных, которые могут быть не у всех записей
- данных, структура которых может меняться со временем
- полей, которые не участвуют в WHERE-условиях




Реализация



Для организации работы с JSON-данными в классе DbTable должны быть определены:

- поле типа `TEXT` для хранения JSON-строки
- константы для ключей JSON-объекта
- в соответствующей модели - свойство `$_dataField` с именем поля для данных (camelCase без префикса)

Пример из модуля Base:

DbTable `PersonProtected`:

php
class PersonProtected extends \Application\Assistance\DatabaseNormal
{
    const PERSON_PROTECTED_ID = 'person_protected_id';
    const PERSON_ID = 'person_id';
    const PERSON_PROTECTED_DATA = 'person_protected_data';

    // Ключи JSON-объекта
    const SKIN = 'skin';
    const TRANSLATE_MODE = 'translate_mode';
    const VOICE = 'voice';
    const REGISTRATION = 'registration';
    const LOCATIONS = 'locations';
    const SHOW_HELP = 'show_help';
    const DEVICE_TOKEN = 'device_token';
    const AUTH_CODE = 'auth_code';

    public static $_fields = [
        self::PERSON_PROTECTED_ID => [],
        self::PERSON_ID => [
            self::FP_INDEX => true,
            self::FP_LINK => Person::class
        ],
        self::PERSON_PROTECTED_DATA => [self::FP_TYPE => self::TYPE_TEXT],
    ];
}

Модель PersonProtected:

php
class PersonProtected extends \Application\Assistance\Model
{
    public $person_protected_id;
    public $person_id;
    public $person_protected_data;

    protected $_dataField = 'PersonProtectedData';
}

Работа с JSON-данными в модели
После настройки становятся доступны методы для работы с JSON-данными:

Получение значения


php
$value = $model->getData(db\PersonProtected::VOICE);

Если ключ отсутствует, возвращается false.

Установка значения


php
$model->setProtected(db\PersonProtected::VOICE, 'voice_value');

Установка нескольких значений


php
$model->setProtected(false, false, [
    db\PersonProtected::VOICE => 'voice_value',
    db\PersonProtected::SKIN => 'dark'
]);

Пример: добавление произвольных полей пользователю


Предположим, нужно добавить пользователю поле phone и telegram без изменения структуры базы данных.

Шаг 1: Добавить константы в DbTables/PersonProtected:



php
const PHONE = 'phone';
const TELEGRAM = 'telegram';

Шаг 2: В модели использовать штатные методы:



php
// Установка
$protected->setProtected(db\PersonProtected::PHONE, '+7 999 123-45-67');
$protected->setProtected(db\PersonProtected::TELEGRAM, '@username');

// Получение
$phone = $protected->getData(db\PersonProtected::PHONE);
$telegram = $protected->getData(db\PersonProtected::TELEGRAM);

Всё это работает без изменения базы данных, без миграций и без перезагрузки сервера.

Ограничения


JSON-поля не предназначены для:

- полнотекстового поиска

- сортировки по значениям внутри JSON

- индексации вложенных полей

- условий WHERE по значениям внутри JSON

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




Что дальше?



- ➡️ Раздел 21. Типы контроллеров
- ➡️ Раздел 22. Структура фронтенд части
- ➡️ Раздел 23. Выбор js-оболочки