Skip to content

feat(web-api): расширенные фильтры product/list - #580

Open
Ibochkarev wants to merge 3 commits into
betafrom
feat/issue-564-product-list-filters
Open

feat(web-api): расширенные фильтры product/list#580
Ibochkarev wants to merge 3 commits into
betafrom
feat/issue-564-product-list-filters

Conversation

@Ibochkarev

Copy link
Copy Markdown
Member

Описание

Расширяет публичный GET /api/v1/product/list валидируемыми фильтрами витрины: parents/nested, цена, stock, vendor, флаги, options. Без сырого SQL от клиента. Без новых параметров поведение как раньше.

Тип изменений

  • Новая функциональность (non-breaking change)

Связанные Issues

Closes #564

Refs #565 (facets follow-up), #577 (RFC)

Как это было протестировано?

cd core/components/minishop3
php -l src/Services/Product/ProductCatalogFilter*.php
php -l src/Services/Product/ProductCatalogService.php
php -l src/Controllers/Api/Web/ProductController.php
php tests/ProductCatalogFilterParserTest.php      # exit 0
php tests/ProductCatalogFiltersRoutesTest.php     # exit 0
php tests/ProductCatalogServiceTest.php           # exit 0
composer stan                                     # exit 0
composer test:smoke                               # exit 0 (72)
composer ci:php                                   # exit 0
  • Автоматические тесты
  • Ручное тестирование на живом MODX (нужны published products + msOption)

Конфигурация тестирования:

  • MiniShop3: feat/issue-564-product-list-filters
  • PHP: 8.4 CLI

Чеклист

  • Код соответствует стилю проекта
  • Лексиконы ru+en для ошибок фильтров
  • PHPStan без новых ошибок
  • CHANGELOG.md — не трогали (релиз)
  • Без фильтров — прежний SQL scope (parent/category BC)

Дополнительные заметки

Контракт (additive)

Параметр Семантика
parents CSV/array ID категорий; OR + msCategoryMember через CategoryProductScopeService
nested 1 → expand tree (depth 10); 0 → только перечисленные ID
price_min / price_max Data.price (stored). Плагины getPrice() меняют отображаемую цену в format, не колонку WHERE
in_stock Data.stock > 0
stock_min Data.stock >= N
vendor_id CSV → IN
new / popular / favorite truthy → Data.* = 1
options JSON или map; AND между ключами, OR внутри; неизвестный ключ → 400

parent/category без parents — как раньше (один primary parent, без members).

Реализация

  • ProductCatalogFilterParser — pure parse/validate
  • ProductCatalogFilterApplier — xPDO WHERE/JOIN + groupby(msProduct.id) при option JOIN
  • ProductController::getListProductCatalogFilterException → HTTP 400 + lexicon

Out of scope

Support parents/nested, price/stock/vendor/flags, and options filters on
the public catalog list without raw SQL, with 400 lexicon errors.
@Ibochkarev Ibochkarev added priority: medium Средний приоритет enhancement New feature or request labels Aug 16, 2026
COUNT(DISTINCT) with GROUP BY returned per-row counts and broke total
when options filters joined multi-value rows. Also harden empty context.
@Ibochkarev
Ibochkarev requested a review from biz87 August 16, 2026 05:33
@biz87

biz87 commented Aug 16, 2026

Copy link
Copy Markdown
Member

Спасибо, реализация аккуратная — парсер/спека/applier разнесены, тесты есть, гейт зелёный. Вопрос не к коду, а к очерёдности.

В RFC #577 ты сам зафиксировал порядок:

P0 — required for Nuxt MVP: 1. #576 security hardening 2. #572 error / HTTP contract 3. #563 Category API …

P1 — required for production: 1. #564 advanced product/list filters …

и там же:

#572 … Делать рано (P0): иначе #573 и Nuxt types плывут.

Сейчас в beta влит #563 (Category API, P0 — по плану), а этот PR — #564, то есть P1, при том что оба P0-фундамента (#576 security, #572 контракт ошибок) ещё не сделаны.

Конкретная причина, почему это важно именно для этого PR: он добавляет 12 новых кодов ошибок валидации на публичный endpoint — ms3_err_catalog_parents_invalid, …_price_range, …_options_json, …_option_unknown и т. д. Это ровно тот слой, который #572 должен стандартизировать (стабильные code / errors, честный HTTP-статус). Если влить фильтры сейчас, а контракт ошибок принять после — эти коды придётся либо ломать при переходе на новый формат, либо тащить как legacy-исключение в уже опубликованном API. Ровно тот риск, о котором предупреждает сам RFC.

Предлагаю: сначала #572 (и желательно #576), затем этот PR — при необходимости с косметической правкой формата ошибок под принятый envelope. PR не закрываю, гейт зелёный, вливаем сразу после.

Если считаешь, что порядок здесь не критичен и переезд на envelope будет дешёвым — скажи, вольём как есть.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request priority: medium Средний приоритет

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Web API: расширенные фильтры product/list для headless

2 participants