You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
В Manager API контроллерах распространён паттерн whitelisted-проброса полей из payload в xPDO-объект:
foreach ($allowedFieldsas$field) {
if (isset($data[$field])) {
$obj->set($field, $data[$field]);
}
}
isset($data[$field]) возвращает false для значения null, не только для отсутствующего ключа. На фронте Vue-форм PrimeVue InputNumber (и некоторые другие компоненты) при очистке поля отправляют null в payload. В результате очистка поля не доходит до $obj->set(), и старое значение остаётся в БД. Вода вводимая пользователем как 0 сохраняется корректно (isset(0) = true), а очистка — нет.
Этот баг был подтверждён и пофикшен в DeliveriesController / PaymentsController (PR #287, пример — free_delivery_amount). Сейчас открываю отдельную задачу, чтобы пройтись по остальным контроллерам Manager API с тем же паттерном.
Решение
Заменять isset($data[$field]) на array_key_exists($field, $data). Это корректно отличает «ключа нет в payload» от «ключ есть, но значение null». xPDO для NOT NULL колонок (decimal default 0.0, int default 0 и т.п.) безопасно приводит null → 0 через тип. Для строковых полей null тоже доходит до $obj->set() и сохраняется ожидаемо.
Кандидаты на проверку
Обнаружены 14 вхождений паттерна в 7 контроллерах. Не все из них — реальный баг: проблема возникает только когда соответствующее Vue-поле может реально отправить null (InputNumber с clearButton, Select с show-clear и т.п.). Нужно по каждому посмотреть Vue-форму, есть ли там очищаемые числовые/select-поля.
Высокая вероятность регрессии
OrdersController.php (строки 647, 1149) — заказ имеет числовые поля (cost, cart_cost, delivery_cost, weight и т.д.). Если хоть одно из них доступно для очистки в админке — баг.
Средняя вероятность
CustomerAddressesController.php (95, 144) — поля адресов. Большинство строковые, но могут быть index (почтовый индекс), номера квартир/этажей через InputNumber — нужно проверить.
VendorsController.php (170, 206) — вендоры (имя, страна, сайт). Скорее всего строки, но проверить нужно.
Низкая вероятность (но проверить тоже стоит)
CustomersController.php (170) — поля клиента в основном строковые.
LinksController.php (154, 191) — связи между товарами, поля категориальные.
Проблема
В Manager API контроллерах распространён паттерн whitelisted-проброса полей из payload в xPDO-объект:
isset($data[$field])возвращаетfalseдля значенияnull, не только для отсутствующего ключа. На фронте Vue-форм PrimeVueInputNumber(и некоторые другие компоненты) при очистке поля отправляютnullв payload. В результате очистка поля не доходит до$obj->set(), и старое значение остаётся в БД. Вода вводимая пользователем как0сохраняется корректно (isset(0)= true), а очистка — нет.Этот баг был подтверждён и пофикшен в
DeliveriesController/PaymentsController(PR #287, пример —free_delivery_amount). Сейчас открываю отдельную задачу, чтобы пройтись по остальным контроллерам Manager API с тем же паттерном.Решение
Заменять
isset($data[$field])наarray_key_exists($field, $data). Это корректно отличает «ключа нет в payload» от «ключ есть, но значение null». xPDO для NOT NULL колонок (decimal default 0.0,int default 0и т.п.) безопасно приводитnull→0через тип. Для строковых полейnullтоже доходит до$obj->set()и сохраняется ожидаемо.Кандидаты на проверку
Обнаружены 14 вхождений паттерна в 7 контроллерах. Не все из них — реальный баг: проблема возникает только когда соответствующее Vue-поле может реально отправить
null(InputNumberс clearButton,Selectсshow-clearи т.п.). Нужно по каждому посмотреть Vue-форму, есть ли там очищаемые числовые/select-поля.Высокая вероятность регрессии
OrdersController.php(строки 647, 1149) — заказ имеет числовые поля (cost,cart_cost,delivery_cost,weightи т.д.). Если хоть одно из них доступно для очистки в админке — баг.Средняя вероятность
CustomerAddressesController.php(95, 144) — поля адресов. Большинство строковые, но могут бытьindex(почтовый индекс), номера квартир/этажей черезInputNumber— нужно проверить.VendorsController.php(170, 206) — вендоры (имя, страна, сайт). Скорее всего строки, но проверить нужно.Низкая вероятность (но проверить тоже стоит)
CustomersController.php(170) — поля клиента в основном строковые.LinksController.php(154, 191) — связи между товарами, поля категориальные.StatusesController.php(121, 165) — статусы заказа (name,color).Не баг (отдельный паттерн)
CategoryProductsController.php(89, 97, 121) — тамisset && !== ''. Это GET-параметры фильтров: «пустой фильтр = не фильтровать» — корректное поведение. Не трогать.План работ
isset→array_key_exists, как в PR fix(api): preserve null in delivery/payment numeric fields on save #287). Не подтверждённые — оставить, чтобы не плодить шум.issetдля проверки наличия ключа» вCLAUDE.mdили в общем гайде для контроллеров.Связанное
DeliveriesController/PaymentsController. Кейс был обнаружен по тестированиюfree_delivery_amount(PrimeVueInputNumberпри очистке).