Skip to content

[Bug] Грид «Товары категории»: свои поля msProductData не читаются и молча не сохраняются #914

Closed

Description

@biz87

Описание проблемы

В гриде «Товары категории» колонка, настроенная на своё поле msProductData («Свои поля»), не работает в обе стороны:

  1. значение не читается — колонка пустая, хотя у товаров поле заполнено;
  2. значение не сохраняется — правка через inline-редактирование теряется, причём API отвечает {"ok": true}, то есть интерфейс показывает успешное сохранение.

Вторая часть опаснее первой: данные теряются молча, без ошибки.

Проблема шире своих полей — тем же задето штатное поле stock, см. раздел «Дополнительный контекст».

Источник: сообщение пользователя на modx.pro.

Шаги воспроизведения

  1. Создать своё поле для msProductData через «Утилиты → Свои поля», например wholesale_price (numberfield, decimal).
  2. Заполнить это поле у какого-нибудь товара (в карточке товара поле сохраняется нормально).
  3. Открыть «Утилиты → Конфигурация гридов», грид «Товары категории», добавить колонку с этим полем и отметить её как редактируемую.
  4. Открыть категорию с этим товаром.
  5. Посмотреть на колонку, затем отредактировать её прямо в гриде.

Ожидаемое поведение

Колонка показывает значение поля из базы. Правка через грид сохраняется — так же, как это уже работает в карточке товара.

Фактическое поведение

Колонка пустая. Правка не доезжает до базы, но интерфейс сообщает об успехе.

Замеры на товаре 152351, поле wholesale_price, значение в базе 7.00:

значение в таблице ms3_products:        '7.00'
через модель ($product->loadData()):     7.0        — поле есть в карте
getDataFieldsNames() содержит поле:      ДА

ключ 'wholesale_price' в строке листинга: ОТСУТСТВУЕТ

updateProductData(152351, ['wholesale_price' => 777.77])
  ответ:                                 {"ok":true, "data":{... "wholesale_price":7 ...}}
  значение в базе после записи:          '7.00'     — не изменилось

контроль, штатное поле article:          сохранилось

Строка листинга содержит только фиксированный набор ключей:

id, pagetitle, longtitle, alias, parent, menuindex, published, deleted,
hidemenu, createdon, editedon, article, price, old_price, weight, image,
thumb, vendor_id, made_in, new, popular, favorite, preview_url

Причина

Поля проходят через три статических списка, ни один из которых не знает про «Свои поля»:

Место Что делает
Services/Category/CategoryProductsListService.php:70 $selectParts — фиксированный перечень Data.* в SELECT: своё поле не выбирается из базы
Services/Category/CategoryProductsListService.php:347 formatProductRow() — собирает строку ответа из фиксированного набора ключей
Services/Product/ProductDataService.php:27 $allowedUpdateFields — белый список записи; несовпавшие ключи отбрасываются через array_intersect_key без сообщения

Опции и поля связей попадают в грид через отдельные механизмы (GridOptionColumnResolver, GridRelationColumnResolver), а колонки собственных полей модели не поддержаны ни одним из них.

При этом карточка товара с теми же полями работает: Processors/Product/ProductDataPayloadTrait.php:118 строит список динамически — getDataFieldsNames() (вся карта модели вместе со своими полями) минус id и preview_file_id.

Конфигурация гридов добавить такую колонку и отметить её редактируемой позволяет, то есть интерфейс обещает возможность, которой в бэкенде нет.

Дополнительный контекст

Задето и штатное поле stock. Списки чтения и записи расходятся между собой: stock входит в $allowedUpdateFields, но отсутствует и в $selectParts, и в formatProductRow(). Проверено на том же товаре:

stock в базе:                25
stock в строке листинга:     ОТСУТСТВУЕТ
updateProductData(152351, ['stock' => 99]) → ok: true
stock в базе после записи:   '99.000'     — записался

То есть колонка «Остаток» в этом гриде пустая, но правка в неё уходит в базу: значение пропадает с экрана, хотя сохранилось.

Предлагаемое направление. Заменить статические списки на динамический по образцу ProductDataPayloadTrait: брать колонки, настроенные в гриде, пересекать с getDataFieldsNames() и исключать служебные (id, preview_file_id). Это закрывает и расхождение по stock. Белый список записи при этом должен остаться — именно он защищает служебные колонки, просто строиться ему нужно от карты модели, а не от зашитого перечня.

Не регрессия 1.14.2-beta1. Проверялось отдельно, поскольку в этом релизе менялся CategoryProductsController (#473): обе ветки листинга — быстрая и с проверкой ACL — вызывают один и тот же getPage(), существовавший до той правки, и набор полей она не затрагивала.

Окружение

  • MiniShop3: 1.14.2-beta1
  • MODX: 3
  • PHP: 8.3.25
  • MySQL: не влияет
  • Браузер: не влияет
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions