Magento 2: Получить ID родительской категории ID категории - PullRequest
0 голосов
/ 09 ноября 2019

Как получить идентификатор родительской категории для идентификатора категории в Magento 2?

В Magento 1 я сделал это следующим образом:

$product_id = 101; //for example
$product = Mage::getModel('catalog/product')->load($product_id); //get product object by product ID
$category_ids = $product->getCategoryIds(); //array of all categories that the product is in
foreach ($category_ids as $cat_ids) {
    $parent_id = Mage::getModel('catalog/category')->load($cat_id)->getParentId(); //
    echo $parent_id; //outputs an int ID of parent category
}

В Magento 2 яя пытался сделать то же самое со следующим:

$product_id = 101; //again, for example
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$productRepository = $objectManager->create('\Magento\Catalog\Model\ProductRepository');
$product = $productRepository->getById($product_id); //get product object by product ID
$category_ids = $product->getCategoryIds(); //array of all categories that the product is in
foreach ($category_ids as $cat_ids) {
    echo $cat_ids;
}

До этого мой код работал отлично, а $ category_ids - это массив всех категорий, в которых находится продукт. Однако я не могу понять,как получить идентификаторы родительской категории для каждого дочернего идентификатора категории в массиве $ category_ids.

УВЕДОМЛЕНИЕ * Мне известно, что я официально не должен напрямую использовать ObjectManager, поэтому, пожалуйста, сохраните это из своего ответа,Я пытаюсь специально использовать ObjectManager таким образом, чтобы перебрать $ category_ids и загрузить идентификаторы родительской категории для каждого идентификатора дочерней категории.

1 Ответ

0 голосов
/ 12 ноября 2019

Как это часто бывает, есть несколько способов достичь этого.

Маршрут CategoryFactory

Чтобы загрузить категорию напрямую, вы загружаете ее через Factory Singleton, отвечающий за класс \Magento\Catalog\Model\Category,Это класс \Magento\Catalog\Model\CategoryFactory. Из каждого экземпляра Category вы можете просто вызвать метод getParentId(), чтобы получить родительский идентификатор.

foreach ($categoryIds as $categoryId) {
    try {
        $category = $this->_categoryFactory->create()->load($categoryId);
    } catch (\Exception $e) {
        /* Handle this appropriately... */
    }
    echo 'Parent Category ID: ', $category->getParentId(), PHP_EOL;
}

В этом примере $categoryIds - это array идентификаторов категорий, извлеченных изВаш \Magento\Catalog\Model\Product экземпляр.

Маршрут CategoryRepository

Или, предпочтительно, вы можете использовать экземпляр Singleton класса \Magento\Catalog\Model\CategoryRepository в качестве оболочки вокруг Factory. Он будет обрабатывать всю загрузку с некоторой дополнительной обработкой ошибок, а также будет хранить ссылку на загруженную категорию для последующего повторного использования. Так что, если вы делаете это несколько раз в течение одного выполнения, или подозреваете, что вы загрузите ту же категорию позже, использование Repository оптимизирует вашу производительность.

foreach ($categoryIds as $categoryId) {
    try {
        $category = $this->_categoryRepository->get($categoryId);
    } catch (\Exception $e) {
        /* Handle this appropriately... */
    }
    echo 'Parent Category ID: ', $category->getParentId(), PHP_EOL;
}

Маршрут сбора

Это должен быть гораздо более быстрый маршрут, поскольку вы (1) загружаете все категории один раз из базы данных вместо использования нескольких множественных вызовов sql в бэкэнде и (2) у вас есть некоторый контроль над тем, что заполнено в Category, а что не учтено. Пожалуйста, имейте в виду, что в Коллекции будет заполнено только то, что вы положили в addAttributeToSelect(). Но если вы только после parent_id, это не должно быть проблемой.

Сначала убедитесь, что вы знакомы с коллекциями , затем приобретите CollectionFactory Синглтон для Magento\Catalog\Model\ResourceModel\Category\CollectionFactory, а затем заполнить его следующим образом:

/** @var \Magento\Catalog\Model\ResourceModel\Category */
$collection = $this->_categoryCollectionFactory->create();

# Specifically select the parent_id attribute
$collection->addAttributeToSelect('parent_id');

# Only select categories with certain entity_ids (category ids)
$collection->addFieldToFilter('entity_id', ['in' => $categoryIds])

# Iterate over results and print them out!
foreach ($collection as $category) {
    echo 'Parent Category ID: ', $category->getParentId(), PHP_EOL;
}

Однако, с большими силами приходит большой риск. Этот код не будет исправлять ошибки вообще. Если существует логическая ошибка базы данных, например, продукт, который указывает на отсутствующую категорию, эта категория будет просто исключена из коллекции, и вы, как программист, сможете определить ее и устранить. Кроме того, вам придется решить для себя, как вы обрабатываете представление магазина и активные / неактивные категории через фильтры к коллекции.

Прямой маршрут к базе данных

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

Это будет безумно быстро, но есть все виды проблем, например, полагаться на базовыйхранение данных и структура данных, не говоря уже о том, что вы открыты (очень маловероятно, чтобы быть справедливым) будущими обновлениями базовой структуры базы данных, либо напрямую через обновления Magento, либо через (неприятные) сторонние модули. Не говоря уже об опасности SQL-инъекций или XSS-атак. ( Хотя вы всегда должны помнить об этом всеми 4 методами. )

Поскольку вы используете ObjectManager напрямую, я предполагаю, что вы не будете возражать против этих недостатков, поэтомуХотя я бы дал вам и эту опцию.

Основной псевдо-sql:

select parent_id from <name of catalog_category_entity table> where entity_id in (<sanitized, comma-separated list of category ids);

Во-первых, получите экземпляр класса \Magento\Framework\App\ResourceConnection. Вы будете использовать это для получения необходимого имени таблицы для catalog_category_entity, а также для получения соединения с базой данных. Затем вам следует санировать ваши данные и, наконец, связать и выполнить запрос и извлечь ваши данные.

/** @var \Magento\Framework\App\Connection */
$connection = $this->_resourceConnection->getConnection();

# Get prefixed table name of catalog_category_entity
$categoryEntityTableName = $this->_resourceConnection->getTableName('catalog_category_entity');

# Sanitize the $categoryIds array using a bit of overkill
array_walk_recursive($categoryIds, function(&$value, $key){
    $value = filter_var($value, FILTER_SANITIZE_NUMBER_INT);
});

# Prepare a sql statement which fetches entity_id and parent_id
$preparedStatement = $this->connection->prepare('select entity_id, parent_id from ' . $categoryEntityTableName . ' where entity_id in (' . implode(',', array_fill(0, sizeof($categoryIds), '?')) . ')');

# Bind sanitized $categoryIds array to statement and execute said statement in one single step 
$preparedStatement->execute($categoryIds);

# fetch result as a key-value pair array of entity_id=>parent_id
$parentIds = $preparedStatement->fetchAll(\PDO::FETCH_KEY_PAIR);

# Iterate over results and print them out!
foreach ($parentIds as $categoryId => $parentId) {
    echo 'Parent Category ID: ', (int)$parentId, PHP_EOL;
}

Сноска

Я полагаю, вы хорошо осведомлены о плюсах и минусах использованияObjectManager напрямую, поэтому я избавлю вас от лекции ;-). Тем не менее, для дальнейшего использования я также должен сообщить будущим читателям, которые наткнулись на этот ответ, что, если они не знают, как получить экземпляры классов CategoryFactory, CategoryRepository, CollectionFactory или ResourceConnection, я оченьРекомендую им сделать это с помощью механизма Dependency Injection .

...