Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

## Навигация

- **Текущий месяц:** [Апрель 2026](#апрель-2026) (ниже)
- **Предыдущий месяц:** [Март 2026](#март-2026) (ниже)
- **Текущий месяц:** [Май 2026](#май-2026) (ниже)
- **Предыдущий месяц:** [Апрель 2026](#апрель-2026) (ниже)
- **Ещё раньше:** [Февраль 2026](#февраль-2026), [Январь 2026](#январь-2026) (ниже)
- **Архив по месяцам:**
- [Декабрь 2025](changelogs/2025-12.md)
Expand All @@ -15,6 +15,27 @@

---

## Май 2026

### [2026-05-08] 🐛 Исправления Manager API и сохранения товара (#238)

#### 🐛 Исправлено

**Категория → опции — PHP Warning `Undefined array key "id"` (PHP 8+):**
- У `msCategoryOption` составной первичный ключ; в выборке списка нет столбца `id`. `CategoryOptionsController::formatRow()` больше не обращается к несуществующему ключу: если `id` нет в строке PDO, для поля ответа `id` используется `option_id` (в рамках одной категории уникально; Vue-грид и так использует `data-key="option_id"`).

**Товар — сохранение без вкладки «Категории» обнуляло дополнительные категории:**
- `ProductDataService::saveCategories()` при отсутствии ключа `categories` в `_fields` (POST не содержит поля, пока дерево вкладки не отрисовалось) больше не трактует это как пустой список и не вызывает `removeCollection`. Поведение согласовано с `saveLinks()`: явная передача `categories` по-прежнему синхронизирует `msCategoryMember` (в том числе пустой массив после открытия вкладки).

#### 📁 Изменённые файлы

```
core/components/minishop3/src/Controllers/Api/Manager/CategoryOptionsController.php
core/components/minishop3/src/Services/Product/ProductDataService.php
```

---

## Апрель 2026

### [2026-04-27] 🚀 Версия 1.10.1-beta1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,10 +368,15 @@ protected function formatRow(array $row): array
$globalCaption
);

// msCategoryOption has composite PK (category_id, option_id); SQL select has no `id` column.
$categoryId = (int)($row['category_id'] ?? 0);
$optionId = (int)($row['option_id'] ?? 0);
$rowId = array_key_exists('id', $row) ? (int)$row['id'] : $optionId;

return [
'id' => (int)$row['id'],
'option_id' => (int)$row['option_id'],
'category_id' => (int)$row['category_id'],
'id' => $rowId,
'option_id' => $optionId,
'category_id' => $categoryId,
'position' => (int)($row['position'] ?? 0),
'active' => (bool)($row['active'] ?? false),
'required' => (bool)($row['required'] ?? false),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ public function prepareObject(msProductData $productData): void
* IMPORTANT: msProductData::get('categories') is overridden and reads from DB,
* so we use reflection to get the value from $_fields (POST data)
*
* If `categories` was not sent (e.g. manager save before the Categories tab mounted its
* hidden field), leave msCategoryMember untouched — same contract as saveLinks().
*
* @param msProductData $productData
* @return void
*/
Expand All @@ -90,7 +93,12 @@ public function saveCategories(msProductData $productData): void
$property = $reflection->getProperty('_fields');
$property->setAccessible(true);
$fields = $property->getValue($productData);
$categories = $fields['categories'] ?? null;

if (!array_key_exists('categories', $fields)) {
return;
}

$categories = $fields['categories'];

if (is_string($categories)) {
$categories = json_decode($categories, true);
Expand Down