Как это часто бывает, есть несколько способов достичь этого.
Маршрут 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 .