【问题标题】:get all Categories and SubCatgories without loading model in foreach loop获取所有类别和子类别而不在 foreach 循环中加载模型
【发布时间】:2017-05-14 07:53:32
【问题描述】:

我想在主导航菜单中显示所有类别及其子类别。 当我将鼠标悬停在类别上时,它应该显示其子类别。 我想在 foreach 循环中不加载 Mage::getModel('catalog/category') 来实现此功能。

【问题讨论】:

    标签: magento magento-1.9


    【解决方案1】:

    如果您想在 phtml 文件中编写代码,请使用下面的代码来创建类别的树结构。

    <ul>
        <?php
            $obj = new Mage_Catalog_Block_Navigation();
            $storeCategories = $obj->getStoreCategories();
            Mage::registry('current_category') ? $currentCategoryId = Mage::registry('current_category')->getId() : $currentCategoryId='';
            foreach ($storeCategories as $_category):
        ?>
                <li>
                    <strong><?php echo $_category->getName(); ?></strong>
                    <?php $categoryChildren = $_category->getChildren(); ?>
                    <?php if($categoryChildren->count()) : ?>
                        <ul>
    
                            <?php foreach($categoryChildren as $_categoryChild) : ?>
                                <?php $_categoryChildModel = Mage::getModel('catalog/category')->load($_categoryChild->getId());?>
                                <?php $categoryGrandchildren=$_categoryChild->getChildren(); ?>
                                <li>
                                    <?php
                                        $currentCategoryId===$_categoryChild->getId() ? $bold="style=\"font-weight:bold\"" : $bold='';
                                        echo '&emsp;' . '<a href="' . $_categoryChildModel->getUrl() . '"' . $bold . '>' .  $_categoryChild->getName() . '(' . $_categoryChildModel->getProductCollection()->count() . ')</a>';
                                    ?>
                                </li>
                                <?php if($categoryGrandchildren->count()) : ?>
                                    <?php foreach($categoryGrandchildren as $_categoryGrandchild) : ?>
                                        <?php $_categoryGrandchildModel = Mage::getModel('catalog/category')->load($_categoryGrandchild->getId());?>
                                        <li>
                                            <?php
                                                $currentCategoryId===$_categoryChild->getId() ? $bold="style=\"font-weight:bold\"" : $bold='';
                                                echo '&emsp;&emsp;' . '<a href="' . $_categoryGrandchildModel->getUrl() . '"' . $bold . '>' .  $_categoryGrandchild->getName() . '(' . $_categoryGrandchildModel->getProductCount() . ')</a>';
                                            ?>
                                        </li>
                                    <?php endforeach; ?>
                                <?php endif; ?>
                            <?php endforeach; ?>
                        </ul>
                    <?php endif; ?>
                </li>
            <?php endforeach ?>
    </ul>
    

    使用 css 和 HTML,您可以实现在主菜单悬停时显示子菜单的目标。

    如果您需要任何其他帮助,请继续联系我。

    谢谢

    【讨论】:

    • 谢谢。但是当我们在 for 循环中使用模型时,站点变得很重。我不想将模型放在 for 循环中。
    • 好的,您是否检查过这个解决方案,它可能会有所帮助。 link
    • 我已经将此代码放入我的 phtml 文件中。我不想在 for 循环中加载 mage::getModel。
    • 您也可以使用缓存来避免加载时间。
    【解决方案2】:

    好的,所以我就这样做了,我想我会搜索看看是否有人想知道如何实现这一目标。诀窍是

    Mage::getResourceSingleton('catalog/category')->getAttributeRawValue($categoryEntityId,array('name','level','url_key','path','is_active'),Mage::app()->getStore());
    

    这不会加载类别模型让我们看看它实际上在做什么。

    转到 app/code/core/Mage/Catalog/Model/Resource/Abstract

    public function getAttributeRawValue($entityId, $attribute, $store)
    {
        if (!$entityId || empty($attribute)) {
            return false;
        }
        if (!is_array($attribute)) {
            $attribute = array($attribute);
        }
    
        $attributesData     = array();
        $staticAttributes   = array();
        $typedAttributes    = array();
        $staticTable        = null;
        $adapter            = $this->_getReadAdapter();
    
        foreach ($attribute as $_attribute) {
            /* @var $attribute Mage_Catalog_Model_Entity_Attribute */
            $_attribute = $this->getAttribute($_attribute);
            if (!$_attribute) {
                continue;
            }
            $attributeCode = $_attribute->getAttributeCode();
            $attrTable     = $_attribute->getBackend()->getTable();
            $isStatic      = $_attribute->getBackend()->isStatic();
    
            if ($isStatic) {
                $staticAttributes[] = $attributeCode;
                $staticTable = $attrTable;
            } else {
                /**
                 * That structure needed to avoid farther sql joins for getting attribute's code by id
                 */
                $typedAttributes[$attrTable][$_attribute->getId()] = $attributeCode;
            }
        }
        /**
         * Collecting static attributes
         */
        if ($staticAttributes) {
            $select = $adapter->select()->from($staticTable, $staticAttributes)
                ->where($this->getEntityIdField() . ' = :entity_id');
            $attributesData = $adapter->fetchRow($select, array('entity_id' => $entityId));
        }
    
        /**
         * Collecting typed attributes, performing separate SQL query for each attribute type table
         */
        if ($store instanceof Mage_Core_Model_Store) {
            $store = $store->getId();
        }
    
        $store = (int)$store;
        if ($typedAttributes) {
            foreach ($typedAttributes as $table => $_attributes) {
                $select = $adapter->select()
                    ->from(array('default_value' => $table), array('attribute_id'))
                    ->where('default_value.attribute_id IN (?)', array_keys($_attributes))
                    ->where('default_value.entity_type_id = :entity_type_id')
                    ->where('default_value.entity_id = :entity_id')
                    ->where('default_value.store_id = ?', 0);
                $bind = array(
                    'entity_type_id' => $this->getTypeId(),
                    'entity_id'      => $entityId,
                );
    
                if ($store != $this->getDefaultStoreId()) {
                    $valueExpr = $adapter->getCheckSql('store_value.value IS NULL',
                        'default_value.value', 'store_value.value');
                    $joinCondition = array(
                        $adapter->quoteInto('store_value.attribute_id IN (?)', array_keys($_attributes)),
                        'store_value.entity_type_id = :entity_type_id',
                        'store_value.entity_id = :entity_id',
                        'store_value.store_id = :store_id',
                    );
    
                    $select->joinLeft(
                        array('store_value' => $table),
                        implode(' AND ', $joinCondition),
                        array('attr_value' => $valueExpr)
                    );
    
                    $bind['store_id'] = $store;
    
                } else {
                    $select->columns(array('attr_value' => 'value'), 'default_value');
                }
    
                $result = $adapter->fetchPairs($select, $bind);
                foreach ($result as $attrId => $value) {
                    $attrCode = $typedAttributes[$table][$attrId];
                    $attributesData[$attrCode] = $value;
                }
            }
        }
    
        if (sizeof($attributesData) == 1) {
            $_data = each($attributesData);
            $attributesData = $_data[1];
        }
    
        return $attributesData ? $attributesData : false;
    }
    

    如您所见,仅在检索特定信息时不会发生模型加载。作为资源摘要的一部分也意味着所有目录资源模型(我没有检查过其他资源模型,但在其他资源模型中发现这一点我不会太惊讶)都有这个可用。

    如果您在 Mage_Catalog_Block_Navigation 的覆盖中使用它,则可以调用您需要的有关任何类别的所有信息,而无需加载模型。但是,要遍历树,您必须做一些可怕的事情。

    您可以使用 'path'(explode on /) 轻松检索父母,但您需要弄脏才能检索子类别,所以像这样来获取孩子。

            $childrenQuery = "SELECT entity_id FROM catalog_category_entity WHERE path REGEXP '^.*\/" . $categoryId . "\/[[:digit:]]?[[:digit:]]?[[:digit:]]?[[:digit:]]?$'";
            $resource = Mage::getSingleton('core/resource');
            $readCxn = $resource->getConnection('core/read');
            $children = $readCxn->fetchAll($childrenQuery);
            if ($children[0]) {
                return $children;
            } else {
                return;
            }
    

    总体困难在于,所有模型和资源模型函数都需要一个类别对象的实例来使它们都使用 entity_id 工作,这绝对是一种痛苦。

    所以我一般不建议这样做,我这样做的唯一原因是因为在我的情况下,默认的 magento 根类别不是类别的实际功能根(很有趣)。如果您使用的是标准根类别,我建议您使用 Helper 函数并从缓存中检索信息。

    从这里开始,您所要做的就是在 Mage_Catalog_Block_Navigation 中完成您的功能,并在模板中组装您的菜单。你去吧;无需访问模型即可完成类别菜单->加载。

    【讨论】:

      【解决方案3】:

      试试这个代码

      <?php
      require_once("app/Mage.php");
      Mage::app();
      
      function getChildCategories($category, $First = false) {
      
      
              $sub = $First ? $category : $category->getChildren();
      
      
              foreach ($sub as $child) {
                      $_categories[] = [ "name" => $child->getName(), "id" => $child->getId(), "children" => getChildCategories($child) ];
              }
      
      
              return $_categories;
      };
      
      function CategoriesTree($category, $First = false) {
      
      
              $sub = $First ? $category : $category->getChildren();
              echo "<pre>";
      
              foreach ($sub as $child) {
                echo $child->getName(); ;
                      CategoriesTree($child);
              }
      
      }
      
      $_categories = Mage::helper('catalog/category')->getStoreCategories();
      
      
      $categories = getChildCategories($_categories, true);
      
      CategoriesTree($_categories, true);
      
      ?>
      

      【讨论】:

      • 我应该在哪里写这段代码?我想在 phtml 文件中编写代码。
      猜你喜欢
      • 1970-01-01
      • 2011-07-30
      • 2012-12-26
      • 1970-01-01
      • 2016-09-20
      • 2016-04-24
      • 2014-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多