Описание функции
Добавить в MiniShop3 тип поля «key=value» — UI для редактирования плоского ассоциативного массива (JSON object / map), где каждая запись — пара «ключ → значение».
Виджет должен:
- редактироваться в менеджере как список пар «Параметр / Значение» (добавить, удалить пару);
- храниться в БД в колонке
JSON (одна колонка на поле, объект, не массив строк);
- быть доступен через утилиту «Дополнительные поля» (
ms3_extra_fields) и формы товара/заказа;
- отдавать данные в API и сниппетах как ассоциативный массив / объект, а не как «сырой» JSON-строкой.
См. также: #299 — тип поля «повторитель» (repeater) — для табличных списков однотипных строк с фиксированной схемой колонок (JSON массив объектов).
Проблема, которую решает
Для плоских наборов пар «ключ → значение» (КБЖУ, meta, flat config) repeater из #299 избыточен: там нужна схема колонок и массив однотипных строк. Сейчас остаются обходные пути:
- Плоское extra field
dbtype=json + textarea — колонку можно создать, но нет UI пар ключ/значение, легко сломать JSON, нет валидации уникальности ключей.
- MODX TV + произвольный JSON — вне extra fields MS3, слабая связь с Manager API и REST компонента.
- Repeater (MIGX-подобный грид) — UX тяжелее, модель данных — массив объектов, а не
{ "key": "value" }.
Идея из обсуждения (С. Гончаров): отдельный, частый кейс — не repeater, а плоский key-value map. В Laravel Filament для этого есть KeyValue — удобно, когда нужен ассоциативный массив без фиксированной табличной схемы.
Предлагаемое решение
1. Новый xtype: ms3-key-value
| Уровень |
Значение |
dbtype |
json |
phptype |
json |
xtype |
ms3-key-value (рабочее имя) |
Опционально в схеме extra field (конфиг в ms3_extra_fields):
- фиксированный набор ключей — для КБЖУ:
calories, protein, fat, carbs (labels из конфига);
- или свободные ключи — как Filament KeyValue (add/remove пар).
2. UI менеджера
- В ExtraFieldsManager — выбор режима: фиксированные ключи / свободные ключи.
- В карточке товара / заказа — две колонки «Параметр» / «Значение», кнопки «Добавить / Удалить» пару.
- Сохранение — сериализация в JSON-объект в колонку модели (
msProductData, msOrder, …).
3. Бэкенд
- Валидация: уникальность ключей, запрет пустых ключей, тип значения (string/number) по конфигу.
- Нормализация при save (как для
json в ProductDataService::prepareObject).
- API — декодированный объект/ассоциативный массив PHP.
4. Фильтрация и сортировка (MySQL 5.7+ / MariaDB 10.3+)
Хранение в JSON-колонке модели MS3 позволяет без join к TV:
-- фильтр по ключу
WHERE JSON_EXTRACT(ms3_products.nutrition, '$.calories') IS NOT NULL
-- сортировка каталога по числовому полю
ORDER BY CAST(
JSON_UNQUOTE(JSON_EXTRACT(ms3_products.nutrition, '$.calories')) AS UNSIGNED
) ASC
5. Область первой итерации (MVP)
- Extra fields для
msProductData, msOrder, msOrderAddress.
- Режим фиксированных ключей (пример КБЖУ) + режим свободных ключей.
- Vue-менеджер, API, документация.
Вне MVP: локализация labels ключей из схемы, generated column + index на частый path, sort/filter в Grid API по JSON-path.
Альтернативные варианты
| Вариант |
Плюсы |
Минусы |
| Repeater (#299) |
Единый «структурированный JSON» UX |
Избыточен для flat map; массив вместо object |
Плоский json + textarea |
Уже можно создать колонку |
Нет UX, нет валидации ключей |
| Filament KeyValue (идея) |
Проверенный UX |
Нужна своя реализация на PrimeVue |
| Отдельная таблица key-value |
Нормализация |
Избыточно для MVP |
Сравнение с repeater (#299):
|
Repeater |
Key=value |
| Форма в БД |
JSON массив [{...}, {...}] |
JSON объект { "key": "value" } |
| UI |
Таблица строк со схемой колонок |
Пары ключ/значение |
| Типичный кейс |
Характеристики, комплектация |
КБЖУ, meta-пары, flat config |
| Сложность UI |
Выше |
Ниже |
Key=value проще repeater'а и может быть реализован раньше или параллельно.
Примеры использования
КБЖУ для товара
Поле nutrition (dbtype=json, phptype=json, xtype=ms3-key-value):
{
"calories": "250",
"protein": "12",
"fat": "8",
"carbs": "30"
}
Передача через процессор / API (после #297)
$response = $modx->runProcessor('MiniShop3\\Processors\\Product\\Create', [
'pagetitle' => 'Бокс «Весенний каприз» XL',
'class_key' => \MiniShop3\Model\msProduct::class,
'parent' => 409,
'Data' => [
'price' => 5200,
'nutrition' => [
'calories' => '250',
'protein' => '12',
'fat' => '8',
'carbs' => '30',
],
],
]);
Fenom / витрина
<dl class="nutrition">
<dt>{$_('ms3_nutrition_calories')}</dt><dd>{$nutrition.calories}</dd>
<dt>{$_('ms3_nutrition_protein')}</dt><dd>{$nutrition.protein} г</dd>
</dl>
Произвольные meta-пары (свободные ключи)
{
"warranty_months": "24",
"origin_country": "RU",
"cert_gost": "ГОСТ 12345"
}
Дополнительный контекст
- MySQL JSON (5.7+) —
JSON_EXTRACT, JSON_CONTAINS для выборок без TV join.
- В MS3 уже есть задел:
ExtraFields, ExtraFieldsManager.vue, dbtype=json / phptype=json, ProductDataService.
- Аналоги: Filament KeyValue, meta fields в e-commerce (flat key-value metafields).
Связанные области кода:
core/components/minishop3/src/Utils/ExtraFields.php
vueManager/src/components/ExtraFieldsManager.vue
core/components/minishop3/src/Services/Product/ProductDataService.php
Критерии приёмки (черновик):
Описание функции
Добавить в MiniShop3 тип поля «key=value» — UI для редактирования плоского ассоциативного массива (JSON object / map), где каждая запись — пара «ключ → значение».
Виджет должен:
JSON(одна колонка на поле, объект, не массив строк);ms3_extra_fields) и формы товара/заказа;См. также: #299 — тип поля «повторитель» (repeater) — для табличных списков однотипных строк с фиксированной схемой колонок (JSON массив объектов).
Проблема, которую решает
Для плоских наборов пар «ключ → значение» (КБЖУ, meta, flat config) repeater из #299 избыточен: там нужна схема колонок и массив однотипных строк. Сейчас остаются обходные пути:
dbtype=json+ textarea — колонку можно создать, но нет UI пар ключ/значение, легко сломать JSON, нет валидации уникальности ключей.{ "key": "value" }.Идея из обсуждения (С. Гончаров): отдельный, частый кейс — не repeater, а плоский key-value map. В Laravel Filament для этого есть KeyValue — удобно, когда нужен ассоциативный массив без фиксированной табличной схемы.
Предлагаемое решение
1. Новый xtype:
ms3-key-valuedbtypejsonphptypejsonxtypems3-key-value(рабочее имя)Опционально в схеме extra field (конфиг в
ms3_extra_fields):calories,protein,fat,carbs(labels из конфига);2. UI менеджера
msProductData,msOrder, …).3. Бэкенд
jsonвProductDataService::prepareObject).4. Фильтрация и сортировка (MySQL 5.7+ / MariaDB 10.3+)
Хранение в JSON-колонке модели MS3 позволяет без join к TV:
5. Область первой итерации (MVP)
msProductData,msOrder,msOrderAddress.Вне MVP: локализация labels ключей из схемы, generated column + index на частый path, sort/filter в Grid API по JSON-path.
Альтернативные варианты
json+ textareaСравнение с repeater (#299):
[{...}, {...}]{ "key": "value" }Key=value проще repeater'а и может быть реализован раньше или параллельно.
Примеры использования
КБЖУ для товара
Поле
nutrition(dbtype=json,phptype=json,xtype=ms3-key-value):{ "calories": "250", "protein": "12", "fat": "8", "carbs": "30" }Передача через процессор / API (после #297)
Fenom / витрина
Произвольные meta-пары (свободные ключи)
{ "warranty_months": "24", "origin_country": "RU", "cert_gost": "ГОСТ 12345" }Дополнительный контекст
JSON_EXTRACT,JSON_CONTAINSдля выборок без TV join.ExtraFields,ExtraFieldsManager.vue,dbtype=json/phptype=json,ProductDataService.Связанные области кода:
core/components/minishop3/src/Utils/ExtraFields.phpvueManager/src/components/ExtraFieldsManager.vuecore/components/minishop3/src/Services/Product/ProductDataService.phpКритерии приёмки (черновик):
ms3-key-value(фиксированные и/или свободные ключи).Data, вывод Fenom, SQL-примерыJSON_EXTRACT.