Skip to content

[Feature] Тип поля key=value (ms3-key-value) для extra fields #300

Description

@Ibochkarev

Описание функции

Добавить в MiniShop3 тип поля «key=value» — UI для редактирования плоского ассоциативного массива (JSON object / map), где каждая запись — пара «ключ → значение».

Виджет должен:

  • редактироваться в менеджере как список пар «Параметр / Значение» (добавить, удалить пару);
  • храниться в БД в колонке JSON (одна колонка на поле, объект, не массив строк);
  • быть доступен через утилиту «Дополнительные поля» (ms3_extra_fields) и формы товара/заказа;
  • отдавать данные в API и сниппетах как ассоциативный массив / объект, а не как «сырой» JSON-строкой.

См. также: #299 — тип поля «повторитель» (repeater) — для табличных списков однотипных строк с фиксированной схемой колонок (JSON массив объектов).

Проблема, которую решает

Для плоских наборов пар «ключ → значение» (КБЖУ, meta, flat config) repeater из #299 избыточен: там нужна схема колонок и массив однотипных строк. Сейчас остаются обходные пути:

  1. Плоское extra field dbtype=json + textarea — колонку можно создать, но нет UI пар ключ/значение, легко сломать JSON, нет валидации уникальности ключей.
  2. MODX TV + произвольный JSON — вне extra fields MS3, слабая связь с Manager API и REST компонента.
  3. 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

Критерии приёмки (черновик):

  • В extra fields можно создать поле типа ms3-key-value (фиксированные и/или свободные ключи).
  • В карточке сущности — UI пар ключ/значение; данные сохраняются в JSON-колонку (объект).
  • Уникальность ключей и валидация при save; понятные ошибки API.
  • API возвращает ассоциативный массив, не JSON-строку.
  • Документация: пример КБЖУ, save через Data, вывод Fenom, SQL-примеры JSON_EXTRACT.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions