Magento 2:获取类别 ID 的父类别 ID
Magento 2: Get Parent Category ID of Category ID
如何在 Magento 2 中获取类别 ID 的父类别 ID?
在 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 是产品所属的所有类别的数组。但是我不知道如何获取每个子项的父类别 ID $category_ids 数组中的类别 ID。
注意* 我知道我不正式应该直接使用 ObjectManager,所以请从您的回答中保存这一点。我正在寻求以这种方式专门使用 ObjectManager 来迭代 $category_ids 并为每个子类别 ID 加载父类别 ID。
像往常一样,有多种方法可以实现这一目标。
CategoryFactory 路由
要直接加载类别,您可以通过负责 \Magento\Catalog\Model\Category
class 的 Factory Singleton 加载它。这是\Magento\Catalog\Model\CategoryFactory
class。从 Category
的每个实例中,您可以简单地调用方法 getParentId()
来获取 parent ID。
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
是您从 \Magento\Catalog\Model\Product
实例中提取的类别 ID 的 array
。
CategoryRepository 路由
或者您最好使用 \Magento\Catalog\Model\CategoryRepository
class 的 Singleton 实例作为 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;
}
Collection路线
这应该是一条更快的路线,因为您 (1) 从数据库加载一次所有类别,而不是在后端使用多个 sql 调用,并且 (2) 您可以控制填充的内容在 Category
中,遗漏了什么。请注意,几乎只有您在 addAttributeToSelect()
中输入的内容才会填充到 Collection 中。但如果你只是在 parent_id
之后,这应该不是问题。
首先,确保你是 familiar with collections,然后为 Magento\Catalog\Model\ResourceModel\Category\CollectionFactory
获取一个 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;
}
然而,强大的力量伴随着巨大的风险。上面的代码不会有任何纠错。如果存在逻辑数据库错误,例如指向缺失类别的产品,则该类别将从 collection 中省略,由程序员来发现并处理。此外,您必须自己决定如何通过 collection.
过滤器处理商店视图和 active/inactive 类别
直接数据库路由
好的,我不会推荐这条路线,除非你确切地知道你在做什么,并且迫切需要性能。
这将是crazy-fast,但存在各种问题,例如依赖底层数据存储和数据结构,更不用说您对(公平地说,不太可能)未来持开放态度直接通过 Magento 升级或通过(讨厌的)第 3 方模块更新底层数据库结构。更不用说 SQL 注入或 XSS 攻击的危险了。 (不过,您应该始终牢记这一点,使用所有 4 种方法。)
由于您是直接使用 ObjectManager,因此我假设您不会介意这些缺点,但是,所以我还是会为您提供此选项。
基本的pseudo-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
class 的一个实例。您将使用它为 catalog_category_entity
获取必要的 table 名称,以及获取数据库连接。然后你应该清理你的数据,最后,绑定并执行查询并获取你的数据。
/** @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
class 是的,我强烈建议他们通过预期的 Dependency Injection 机制这样做。
如何在 Magento 2 中获取类别 ID 的父类别 ID?
在 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 是产品所属的所有类别的数组。但是我不知道如何获取每个子项的父类别 ID $category_ids 数组中的类别 ID。
注意* 我知道我不正式应该直接使用 ObjectManager,所以请从您的回答中保存这一点。我正在寻求以这种方式专门使用 ObjectManager 来迭代 $category_ids 并为每个子类别 ID 加载父类别 ID。
像往常一样,有多种方法可以实现这一目标。
CategoryFactory 路由
要直接加载类别,您可以通过负责 \Magento\Catalog\Model\Category
class 的 Factory Singleton 加载它。这是\Magento\Catalog\Model\CategoryFactory
class。从 Category
的每个实例中,您可以简单地调用方法 getParentId()
来获取 parent ID。
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
是您从 \Magento\Catalog\Model\Product
实例中提取的类别 ID 的 array
。
CategoryRepository 路由
或者您最好使用 \Magento\Catalog\Model\CategoryRepository
class 的 Singleton 实例作为 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;
}
Collection路线
这应该是一条更快的路线,因为您 (1) 从数据库加载一次所有类别,而不是在后端使用多个 sql 调用,并且 (2) 您可以控制填充的内容在 Category
中,遗漏了什么。请注意,几乎只有您在 addAttributeToSelect()
中输入的内容才会填充到 Collection 中。但如果你只是在 parent_id
之后,这应该不是问题。
首先,确保你是 familiar with collections,然后为 Magento\Catalog\Model\ResourceModel\Category\CollectionFactory
获取一个 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;
}
然而,强大的力量伴随着巨大的风险。上面的代码不会有任何纠错。如果存在逻辑数据库错误,例如指向缺失类别的产品,则该类别将从 collection 中省略,由程序员来发现并处理。此外,您必须自己决定如何通过 collection.
过滤器处理商店视图和 active/inactive 类别直接数据库路由
好的,我不会推荐这条路线,除非你确切地知道你在做什么,并且迫切需要性能。
这将是crazy-fast,但存在各种问题,例如依赖底层数据存储和数据结构,更不用说您对(公平地说,不太可能)未来持开放态度直接通过 Magento 升级或通过(讨厌的)第 3 方模块更新底层数据库结构。更不用说 SQL 注入或 XSS 攻击的危险了。 (不过,您应该始终牢记这一点,使用所有 4 种方法。)
由于您是直接使用 ObjectManager,因此我假设您不会介意这些缺点,但是,所以我还是会为您提供此选项。
基本的pseudo-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
class 的一个实例。您将使用它为 catalog_category_entity
获取必要的 table 名称,以及获取数据库连接。然后你应该清理你的数据,最后,绑定并执行查询并获取你的数据。
/** @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
class 是的,我强烈建议他们通过预期的 Dependency Injection 机制这样做。