Перейти к основному содержимому

← Предварительная загрузка · Вернуться к README · Преобразования данных →

Конфигурация

Публикация конфигурации​

php artisan vendor:publish --tag="model_settings"

Команда публикует config/model_settings.php и миграцию пакета.

Доступные параметры​

ПараметрЗначение по умолчаниюНазначение
modelDragonCode\LaravelModelSettings\Models\SettingsEloquent-модель для сохранённых настроек
connectionСтандартное для приложенияПодключение к базе данных для модели и миграции
tablesettingsТаблица базы данных для модели и миграции
casts[]Преобразования данных, выбранные по классу родительской модели и, при необходимости, ключу настройки

Пакет читает следующие переменные окружения:

ПеременнаяЗначение по умолчанию
MODEL_SETTINGS_DATABASE_CONNECTIONDATABASE_CONNECTION, затем стандартное подключение Laravel
MODEL_SETTINGS_DATABASE_TABLEsettings

Задайте подключение и таблицу до запуска миграции:

MODEL_SETTINGS_DATABASE_CONNECTION=mysql
MODEL_SETTINGS_DATABASE_TABLE=model_settings

Изменение этих параметров позже не переносит существующие записи.

Настройка преобразований данных​

Устаревшая, но совместимая форма для всей модели по-прежнему поддерживается. Один класс преобразования обрабатывает все данные, принадлежащие классу модели:

'casts' => [
App\Models\User::class => App\Casts\UserSettingsPayloadCast::class,
],

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

'casts' => [
App\Models\User::class => [
'profile' => App\Data\ProfileData::class,
'billing.credentials' => App\Casts\EncryptedSettingPayload::class,
],
],

Ключи сопоставляются точно. Точки не обозначают вложенный путь, а отсутствующий в карте ключ использует стандартное JSON-преобразование. Запись каждой модели задаётся либо строкой класса для всей модели, либо картой по ключам; символа подстановки внутри карты нет. Поддерживаемые контракты и пример шифрования описаны в разделе Преобразования данных.

Схема хранения​

Опубликованная миграция создаёт следующие столбцы:

СтолбецНазначение
idПервичный ключ строки настройки
item_typeMorph-класс родительской модели или псевдоним
item_idИдентификатор родителя в виде строки длиной до 36 символов
is_defaultОтличает значения класса по умолчанию от переопределений моделей
keyКлюч настройки
payloadДанные, объявленные в миграции как jsonb
created_at и updated_atВременные метки Laravel

Комбинация item_type, item_id, is_default и key уникальна. Индекс поиска по item_type, is_default и item_id поддерживает чтение значений по умолчанию и области владельца.

Значения класса по умолчанию и переопределения моделей находятся в одной таблице. Пакет не создаёт вторую таблицу значений по умолчанию и не добавляет столбцы с метаданными шифрования.

Стандартный столбец item_id хранит не более 36 символов. Целочисленные, строковые, UUID- и ULID-идентификаторы помещаются в эту схему, если их строковое представление не длиннее 36 символов. Для более длинного пользовательского первичного ключа потребуется соответствующее изменение миграции.

Значения класса по умолчанию используют item_id = '0' с is_default = true. Сохранённый владелец с целочисленным ключом 0 или строковым '0' использует то же физическое значение item_id с is_default = false, поэтому обе строки могут существовать для одного типа модели и ключа настройки. Если данные уже существуют, изменение подключения, имени таблицы или псевдонимов morph map требует самостоятельного переноса или обновления строк.

Обновление с более ранней версии 1.x​

Этот выпуск меняет контракт выполнения вместе с миграцией дискриминатора хранения:

Поведение прежней версии 1.xТекущее поведениеНеобходимое изменение приложения
set($key, null), пустые строки, строки из пробелов и пустые массивы удаляли строкуset() сохраняет каждое JSON-значение без измененийЗамените вызовы удаления на forget($key)
Пустые элементы setMany() удалялись в том же пакетеКаждый элемент setMany() сохраняется одним транзакционным upsertПередайте удаляемые ключи отдельному вызову forgetMany()
Пустые ключи и ключи только из пробелов принималисьНормализованные пустые ключи выбрасывают InvalidSettingKeyПереименуйте или удалите недопустимые ключи до обновления
Для проверки наличия требовался all()->has($key)has($key) отличает сохранённый JSON null от отсутствующего ключаИспользуйте специализированный метод has()

Сохранённое переопределение модели со значением null теперь скрывает заполненное значение класса по умолчанию, пока forget() не удалит переопределение. Пользовательские преобразования данных теперь получают пустые значения от обоих методов записи, а события create или update пользовательской модели хранения получают их от set(). get() по-прежнему принимает только один аргумент; резервное значение вызывающего кода и постоянный псевдоним put() не добавлены.

После обновления пакета опубликуйте новую миграцию и запустите её в режиме обслуживания приложения:

php artisan vendor:publish --tag="model_settings"
php artisan migrate

Миграция добавляет is_default, относит все прежние строки с item_id = '0' к значениям класса по умолчанию, создаёт индексы с дискриминатором и затем удаляет прежний уникальный индекс. Она не выводит ключи или данные настроек.

В прежней схеме 1.x значения класса по умолчанию и строки реального владельца с идентификатором 0 хранились одинаково. Поэтому миграция не может отличить добавленное вручную переопределение владельца от значения по умолчанию и относит обе строки к значениям по умолчанию. После миграции проверьте известные прежние данные владельцев с идентификатором 0 и установите is_default = false для строк, которые являются переопределениями моделей.

Не запускайте прежнюю версию пакета с обновлённой схемой. Она не записывает дискриминатор и сохранит значения по умолчанию как переопределения. Разворачивайте миграцию и совместимую версию пакета в одной границе режима обслуживания.

Откат безопасен только до появления реального переопределения владельца с идентификатором 0. Миграция останавливается до изменения схемы, если находит item_id = '0' с is_default = false, поскольку прежняя схема не может представить такую строку без изменения её смысла. Удалите или экспортируйте эти переопределения перед откатом. Безопасный откат восстанавливает прежний уникальный индекс и удаляет is_default.

Замена модели хранения​

Встроенная модель настроек объявлена как final. Вместо наследования настройте замену:

namespace App\Models;

use DragonCode\LaravelModelSettings\Casts\PayloadCast;
use Illuminate\Database\Eloquent\Model;

final class ApplicationSetting extends Model
{
protected $fillable = [
'item_type',
'item_id',
'is_default',
'key',
'payload',
];

public function __construct(array $attributes = [])
{
$this->setConnection(config('model_settings.connection'));
$this->setTable(config('model_settings.table'));

parent::__construct($attributes);
}

protected function casts(): array
{
return [
'item_id' => 'string',
'is_default' => 'boolean',
'payload' => PayloadCast::class,
];
}
}

Затем обновите конфигурацию:

'model' => App\Models\ApplicationSetting::class,

Замена должна оставаться совместимой с опубликованной схемой. Сохраните заполняемые атрибуты и PayloadCast, если новая модель не реализует эквивалентную сериализацию.

Как минимум, новая модель должна сохранять следующее поведение:

ТребованиеПричина
Заполнять item_type, item_id, is_default, key и payloadХранилище записывает эти атрибуты
Использовать настроенные подключение и таблицуМиграция и репозиторий должны обращаться к одним строкам
Преобразовывать item_id в stringЦелые числа, строки, UUID и ULID хранятся в одном столбце
Преобразовывать is_default в booleanЛенивая и предварительная загрузка должны читать один дискриминатор области
Преобразовывать payload через PayloadCast или эквивалентЧтение и запись должны сохранять поведение JSON

См. также​