@kolomat

Получения полного древа категорий из yml?

Добрый день, поскажите по такому вопросу. Есть стандартный yml файл, в нем древо категорий
<categories>
<category id="119604754" parentId="112971624">Блокноты</category>
<category id="112971624">Бумажные изделия</category>
<category id="112971626">Канцелярские товары</category>
<category id="112971625">Папки и файлы</category>
<category id="112971627">Товары для школы и творчества</category>
<category id="112971629">Детские книги и развитие</category>
<category id="112971630">Офисные товары</category>
<category id="112971631" parentId="112971624">Бумага для принтера</category>
<category id="112971632" parentId="112971624">Бумага для принтера цветная</category>
<category id="112971636" parentId="112971624">Бумага для заметок</category>
<category id="112971633" parentId="112971624">Специальная бумага</category>
<category id="112971634" parentId="112971624">Этикетки и ценники</category>
<category id="112971635" parentId="112971624">Ежедневники</category>
<category id="112971637" parentId="112971624">Конверты</category>
<category id="112971638" parentId="112971625">Папки на кнопке</category>
<category id="112971644" parentId="112971625">Папки-уголки</category>
<category id="112971645" parentId="112971625">Папки-регистраторы</category>
<category id="112971649" parentId="112971626">Клей</category>
<category id="112971647" parentId="112971625">Файлы</category>
<category id="112971646" parentId="112971625">Папки с зажимом</category>
<category id="112971648" parentId="112971626">Бейджи</category>
<category id="112971650" parentId="112971626">Скотч</category>
<category id="112971655" parentId="112971626">Стаканы и подставки для ручек</category>
<category id="112971654" parentId="112971626">Лотки для бумаг</category>


Хотел создать для google merchanta xml в котором бы у оффера был указан полный путь категорий
Например
<category id="119604754" parentId="112971624">Блокноты</category>
<category id="112971624">Бумажные изделия</category>


Что бы получилось так например
<item>
        <g:id>2023198597</g:id>
        <g:product_type>Бумажные изделия > Блокноты </g:product_type>
    </item>


Пробовал сделать вот так
foreach ($price->shop->categories->category as $category) {
    if (!$category->attributes()->parentId) {
        $categories[] = [
            'id' => (string)$category['id'],
            'name' => (string)$category
        ];
    } else {
        $pCategories[] = [
            'id' => (string)$category['parentId'],
            'name' => (string)$category
        ];
    }
}

$xml = new DomDocument('1.0', 'UTF-8');
$items = $xml->appendChild($xml->createElement('channel'));

foreach ($price->shop->offers->offer as $offer) {
    $categoryId = $offer->categoryId;
    $item = $items->appendChild($xml->createElement('item'));

    $id = $item->appendChild($xml->createElement('g:id'));
    $id->appendChild($xml->createTextNode($offer->attributes()->id));
    $category = $item->appendChild($xml->createElement('g:product_type'));

    array_filter($categories, function ($a) use ($pCategories, $categoryId, $category, $xml) {
        foreach ($pCategories as $pCategory) {
                if ($pCategory['id'] == $categoryId) {
                    return $category->appendChild($xml->createTextNode($a['name'] . '>' . $pCategory['name']));
                }
            }
    });
}


Внутри если распечатать $a['name'] . '>' . $pCategory['name'] там все верно, но в самом xml почему то сохраняеться для одного офера все древо категорий. Не подскажите что не верно или возможно есть более правильный способ реализовать это. Буду рад за любую помощь.
  • Вопрос задан
  • 89 просмотров
Решения вопроса 1
Набросал пару функций
/**
 * @param array<int, array> $categories
 */
function getCategoryPath(int $categoryId, array $categories): string|null
{
    $category = $categories[$categoryId] ?? null;

    if ($category === null) {
        return null;
    }

    $categoryName     = $category['name'];
    $categoryParentId = $category['parent_id'];

    if ($categoryParentId) {
        return getCategoryPath($categoryParentId, $categories) . ' > ' . $categoryName;
    } else {
        return $categoryName;
    }
}

/**
 * @param array<array> $array
 * @return array<mixed, array>
 */
function indexArrayByColumn(array $array, string $column): array
{
    return array_combine(array_column($array, $column), $array);
}


Пример использования:
$categories = [
    ['id' => 1,  'parent_id' => null, 'name' => 'Электроника'],
    ['id' => 2,  'parent_id' => 1,    'name' => 'Ноутюуки'],
    ['id' => 3,  'parent_id' => 2,    'name' => 'Apple'],
    ['id' => 4,  'parent_id' => 2,    'name' => 'Acer'],
    ['id' => 5,  'parent_id' => 2,    'name' => 'HP'],
    ['id' => 6,  'parent_id' => 2,    'name' => 'Dell'],
    ['id' => 7,  'parent_id' => 1,    'name' => 'Холодильники'],
    ['id' => 8,  'parent_id' => 1,    'name' => 'Телевизоры'],
    ['id' => 9,  'parent_id' => null, 'name' => 'Одежка'],
    ['id' => 10, 'parent_id' => 9,    'name' => 'Куртки'],
    ['id' => 11, 'parent_id' => 9,    'name' => 'Штаны'],
    ['id' => 12, 'parent_id' => null, 'name' => 'Игрушки'],
];

// Индексируем массив по полю 'id'
$categories = indexArrayByColumn($categories, 'id');

foreach ($categories as $categoryId => $_) {
    echo getCategoryPath($categoryId, $categories);
    echo PHP_EOL;
}


Результат:
php categories/script.php
Электроника
Электроника > Ноутюуки
Электроника > Ноутюуки > Apple
Электроника > Ноутюуки > Acer
Электроника > Ноутюуки > HP
Электроника > Ноутюуки > Dell
Электроника > Холодильники
Электроника > Телевизоры
Одежка
Одежка > Куртки
Одежка > Штаны
Игрушки


У этого кода преимущество в том, что путь будет корректно строиться при любой вложенности категорий
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы