Глобальный EAV
Обзор
- Scope
- Глобальная подсистема custom fields под app/Services/Eav и её таблицы БД
Ключевые понятия
- Custom Field
- Определение типизированного активного/обязательного/системного поля для entity_type.
- Typed Value
- Значение, хранимое ровно в одной колонке, выбранной FieldType: text, int, float, bool или JSON.
- Field Extension
- Поведение, специфичное для entity type, применяемое вокруг обработки field type.
- Locale Key
- Компонент locale в идентичности custom field value; по умолчанию — пустая строка.
- Entity Type
- Стабильный строковый ключ в custom_fields.entity_type и custom_field_values.entity_type; один класс модели соответствует одному entity_type.
- Has Custom Fields
- Eloquent trait, связывающий модель с глобальными custom_field_values через customFieldEntityType().
Структура
- Definition Tables
- Fieldscustom_fields
- Translationscustom_field_translations
- Optionscustom_field_options
- Value Tablecustom_field_values
- Services
- RegistryCustomFieldEntityRegistry
- CacheCustomFieldDefinitionCache
- PipelineValuePipeline
- Type RegistryFieldTypes/FieldTypeRegistry
- ExtensionsCustomFieldExtensionRegistry
- FormsEav/Filament/
Факты
- custom_fields хранит entity type, name, type, data, sort и флаги activity/requirement/system; translations и options — отдельные дочерние таблицы. authoritative
- custom_field_values уникален по field_id, entity_type, entity_id и locale. authoritative
- custom_field_values имеет колонки value_text, value_int, value_float, value_bool и value_json. authoritative
- Таблица values индексирует entity lookup, locale и типизированную фильтрацию по entity type, field, locale и каждому scalar value; создание text index зависит от диалекта БД. authoritative
- Директория field types реализует text, long text, number, boolean, date, datetime, select, multiselect и file. authoritative
- ValuePipeline выполняет extensions before store, field type store, затем extensions after store. authoritative
- ValuePipeline выполняет field type load до afterLoad processing extensions. authoritative
- ValuePipeline объединяет ошибки валидации FieldType с ошибками валидации каждого зарегистрированного extension. authoritative
- HasCustomFields требует customFieldEntityType(); опциональный customFieldEntityLabel() управляет видимостью в admin registry; модели field/value по умолчанию — App\Models\CustomField и App\Models\CustomFieldValue. authoritative
- EavServiceProvider обнаруживает каждый класс app/Models и modules/*/Models с HasCustomFields и регистрирует его через CustomFieldEntityRegistry::registerFromModel при boot. authoritative
- Когда customFieldEntityLabel возвращает null, registerFromModel пропускает entity, и она не появляется в селекторах entity в CustomFieldResource. authoritative
- User использует HasCustomFields с entity_type user и label Пользователь (user); values сохраняются в custom_field_values с entity_type user и entity_id равным users.id. authoritative
- HasCustomFields предоставляет getCustomFieldValue, setCustomFieldValue, setCustomFieldValues, getAllCustomFieldValues, loadCustomFields, relation customFieldValues и query scopes whereField или whereFields. authoritative
- CustomFieldsFormHelper строит Filament schema по entity_type; Edit pages используют fillCustomFieldsData и extractFromData плюс saveValues после сохранения parent record. authoritative
Инструкции
Connect Model
- добавить trait HasCustomFields к Eloquent-модели
- реализовать customFieldEntityType, возвращающий уникальный стабильный snake-case key
- реализовать customFieldEntityLabel, когда entity должна появляться в селекторах CustomFieldResource
- полагаться на auto-discovery EavServiceProvider или вызвать CustomFieldEntityRegistry::registerFromModel с именем модуля для module-owned entities
- создать field definitions в admin с matching entity_type
- подключить Filament resource form и save hooks через CustomFieldsFormHelper, когда нужно admin editing
Add Field Type
- реализовать контракт FieldType для validation, storage, loading и form behavior
- зарегистрировать его в FieldTypeRegistry
- проверить typed persistence и влияние на query/index
- добавить или обновить Filament form integration
Add Entity Extension
- реализовать custom field extension для целевого entity type
- зарегистрировать его в CustomFieldExtensionRegistry
- проверить beforeStore, afterStore, afterLoad и validation behavior
Правила
Architectural rule
Не пишите typed value columns напрямую, если у поля есть зарегистрированный type или extension; используйте EAV value pipeline.
Architectural rule
Не предполагайте, что глобальные EAV-таблицы применимы к Shop; у Shop отдельная EAV-схема и extension.
Примеры
User Model
use App\Services\Eav\Traits\HasCustomFields;
class User extends Authenticatable
{
use HasCustomFields;
public function customFieldEntityType(): string
{
return 'user';
}
public function customFieldEntityLabel(): ?string
{
return 'Пользователь (user)';
}
}
app/Models/User.php
Read Value
$bio = $user->getCustomFieldValue('bio');
$users = User::whereField('department', 'sales')->get();
app/Services/Eav/Traits/HasCustomFields.php
Filament User Form
CustomFieldsFormHelper::buildSchema('user', $record)
CustomFieldsFormHelper::fillCustomFieldsData($record, $data)
CustomFieldsFormHelper::saveValues($record, 'user', $cfData)
app/Filament/Admin/Resources/UserResource.php