Добавьте столбец категорий в таблицу продуктов в Magento admin - PullRequest
12 голосов
/ 13 августа 2010

Я пытаюсь добавить столбец категории в таблицу товаров.Я изменил Mage_Adminhtml_Block_Catalog_Product_Grid.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *, * * * * * * * * * * * * * * * * *.я могу исправить свой запрос, чтобы я не получил ошибку?Можно ли показывать и фильтровать по именам категорий вместо идентификаторов?

В сообщении на форуме показан похожий код, но я не могу заставить его работать с категориями http://www.magentocommerce.com/boards/viewthread/44534/

static protected $COLUMN_ID_TRADE_REFERENCES = 'ref_text';

protected function _prepareCollection()
{
    $store = $this->_getStore();
    $collection = Mage::getModel('catalog/product')->getCollection()
        ->addAttributeToSelect('name')
        ->addAttributeToSelect('attribute_set_id')
        ->addAttributeToSelect('type_id')
        ->addAttributeToSelect('ref_text')
        ->joinTable('productreferences/reference',
            'product_id=entity_id',
            array('ref_text'),
            null,
            'left')
        ->joinField('qty',
            'cataloginventory/stock_item',
            'qty',
            'product_id=entity_id',
            '{{table}}.stock_id=1',
            'left')
        ->addStaticField('ref_text')
        ->addExpressionAttributeToSelect(self::$COLUMN_ID_TRADE_REFERENCES,
            'GROUP_CONCAT(ref_text SEPARATOR " ; ")',
            'ref_text')
        ->groupByAttribute('entity_id');

Ответы [ 5 ]

19 голосов
/ 03 ноября 2010

Я работал над этой проблемой несколько дней и наконец решил ее.Поскольку мое решение является лишь одной из нескольких разработок, которые я разработал, я не могу показать вам простое решение для вырезания и вставки.Вместо этого я сосредоточусь на , что сделать вместо , как , чтобы сделать это.Конечно, я предоставлю как можно больше фрагментов кода, но я не могу гарантировать, что они будут работать самостоятельно.Также обратите внимание, что решение, которое я описал, было протестировано только с Magento 1.3.2.4.

Прежде всего, атрибут category_ids ваших продуктов, скорее всего, будет бесполезен для вас.Это список разделенных запятыми идентификаторов категорий (например, 206,208,231).Я предполагаю, что большинству людей не понадобятся категории в этой форме.(Если вам повезет, вы просто добавите столбец, содержащий атрибут category_ids, в свою таблицу и все готово.) Кроме того, насколько я знаю, этот атрибут больше не существует в Magento 1.4.

Проблема с этим атрибутом состоит в том, что это просто избыточная копия фактического назначения категории.Официальные сведения о категориях хранятся в таблице catalog_category_product, по одной строке на пару продукт / категория.

Поскольку категории являются сущностями в Magento и на них нет прямой ссылки через атрибут продукта, выне может использовать joinAttribute() или joinField() с ними.Насколько я знаю, вы не можете объединить на всех объектах другого типа, отличных от коллекции, в него.

Однако вы можете использовать joinTable() для помещения идентификаторов категорий внабор результатов выглядит следующим образом:

$collection->joinTable(
    'catalog/category_product',
    'product_id=entity_id',
    array('single_category_id' => 'category_id'),
    null,
    'left'
);

Как вы уже узнали, это нужно добавить к функции Mage_Adminhtml_Block_Catalog_Product_Grid _prepareCollection().Как всегда, лучший способ сделать это - создать свой собственный модуль и добавить класс, который расширяет класс Magento.Поскольку нет способа аккуратно подключиться к исходному методу _prepareCollection(), вам придется скопировать весь метод в ваш переопределяющий класс и добавить туда код.(Не забудьте проверить наличие изменений кода в оригинале при обновлении Magento.)

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

Теперь получить имя категории немного сложно, поскольку мы не можем объединять другие типы сущностей в нашу коллекцию.Поэтому нам придется сделать это грязным путем и напрямую убрать имена из данных базы данных EAV для сущностей категорий.Я старался оставаться максимально чистым и не кодировать жестко идентификаторы типа атрибута или тому подобное в запросе.Вам понадобятся некоторые знания о структуре EAV Magento , чтобы понять, что происходит ниже.

Вот как это работает:

$res = Mage::getSingleton('core/resource');
$eav = Mage::getModel('eav/config');
$nameattr = $eav->getAttribute('catalog_category', 'name');
$nametable = $res->getTableName('catalog/category') . '_' . $nameattr->getBackendType();
$nameattrid = $nameattr->getAttributeId();

После этого $nametable будет содержатьимя таблицы базы данных, содержащей имя категории, $nameattrid будет содержать числовой идентификатор атрибута для «имени».

Имея эту информацию, мы теперь можем вручную присоединить правильную таблицу EAV к запросу:

$collection->joinTable(
    $nametable,
    'entity_id=single_category_id',
    array('single_category_name' => 'value'),
    "attribute_id=$nameattrid",
    'left'
);

Это добавит столбец single_category_name к нашим строкам результатов.

Помните, что у нас по-прежнему есть по одной строке на категорию для товаров нескольких категорий.Это то, что мы собираемся исправить дальше.Для этого нам нужно сгруппировать результирующие строки по идентификатору продукта и одновременно объединить все эти столбцы single_category_name.

Группировать относительно просто:

$collection->groupByAttribute('entity_id');

Однако выследует вставить этот перед кодом, который присоединяется к таблице названий категорий.Не волнуйтесь, я покажу вам правильно отсортированный кусок кода внизу.

Объединение названий категорий такчто сложнее. Поскольку мы вручную внесли таблицу EAV, мы не можем использовать addExpressionAttributeToSelect() в атрибуте имени категории. Вместо этого мы должны пройти весь путь до классов базы данных Zend Framework и манипулировать запросом там:

$collection->getSelect()->columns(
    array('category_names' => new Zend_Db_Expr(
        "IFNULL(GROUP_CONCAT(`$nametable`.`value` SEPARATOR '; '), '')"
)));

Это извлекает базовый Zend_Db_Select и добавляет к нему новый столбец выражений, который объединит имена категорий, разделенные точкой с запятой. Кроме того, IFNULL позаботится о продуктах, не имеющих никакой категории, установив для столбца category_names пустую строку вместо значения MySQL NULL.

Давайте подведем итоги здесь:

$collection->joinTable('catalog/category_product',
    'product_id=entity_id', array('single_category_id' => 'category_id'),
    null, 'left')
    ->groupByAttribute('entity_id')
    ->joinTable($nametable,
    "entity_id=single_category_id", array('single_category_name' => 'value'),
    "attribute_id=$nameattrid", 'left')
    ->getSelect()->columns(array('category_names' => new Zend_Db_Expr("IFNULL(GROUP_CONCAT(`$nametable`.`value` SEPARATOR '; '), '')")));

Чтобы показать столбец, вы должны добавить что-то вроде этого к prepareColumns():

$this->addColumn('category_ids',
        array(
            'header'   => Mage::helper('catalog')->__('Categories'),
            'index'    => 'category_names',
            'width'    => '150px',
            'filter'   => false,
            'sortable' => false,
));

Флаги filter и sortable не позволяют нажимать на заголовок столбца, а также удаляют текстовое поле фильтра для этого столбца. Поскольку мы проделали серьезный обходной путь для включения столбца категорий в таблицу, эти функции все равно не будут работать. Они мне не нужны, поэтому я не задумывался над тем, как трудно заставить их работать.

Теперь, если вы скопировали эти две порции кода в вашу установку, вы заметите, что хотя сетка будет правильно отображать первую страницу результатов, над таблицей будет сказано, что был возвращен только один продукт, и вы не сможет разбить результаты на страницы. Это связано с тем, что Magento использует отдельный автоматически сгенерированный запрос SQL для подсчета количества результатов, и этот метод не работает с предложениями GROUP BY . Чтобы исправить , что , нам придется переопределить класс коллекции и добавить обходной путь к нему.

Это класс с таким решением:

class Our_Catalog_Model_Resource_Eav_Mysql4_Product_Collection extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection {

    public $calculateSizeWithoutGroupClause = false;

    public function getSelectCountSql()
    {
        if (!$this->calculateSizeWithoutGroupClause) {
            return parent::getSelectCountSql();
        }
        $this->_renderFilters();
        $countSelect = clone $this->getSelect();
        $countSelect->reset(Zend_Db_Select::ORDER);
        $countSelect->reset(Zend_Db_Select::LIMIT_COUNT);
        $countSelect->reset(Zend_Db_Select::LIMIT_OFFSET);
        $countSelect->reset(Zend_Db_Select::COLUMNS);
        $countSelect->reset(Zend_Db_Select::GROUP);
        $countSelect->from('', 'COUNT(DISTINCT `e`.`entity_id`)');
        return $countSelect;
    }

}

Метод getSelectCountSql() основан на исходном методе (и даже вызывает его, если $calculateSizeWithoutGroupClause не установлен), но дополнительно сбрасывает предложение GROUP BY.

Сохраните этот новый класс как app/code/local/Our/Catalog/Model/Resource/Eav/Mysql4/Product/Collection.php (или замените Our на имя вашего модуля) и включите перезапись, изменив в app/code/local/Our/Catalog/etc/config.xml блок <models>:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <Our_Catalog>
            <version>1.2.3</version>
        </Our_Catalog>
    </modules>
    <global>
        <models>
            <catalog_resource_eav_mysql4>
                <rewrite>
                    <product_collection>Our_Catalog_Model_Resource_Eav_Mysql4_Product_Collection</product_collection>
                </rewrite>
            </catalog_resource_eav_mysql4>
        </models>
    </global>
</config>

Наконец, настройка

$collection->calculateSizeWithoutGroupClause = true;

в _prepareCollection() включит наш обходной путь для сетки администратора, и все в порядке.

4 голосов
/ 07 октября 2011

За цитату выше.

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

Все, что вам нужно сделать, это вставить код ниже

    $collection = Mage::getModel('catalog/category')->getCollection()->addAttributeToSelect('name');
$options = array();
foreach ($collection as $item){
    if($item->getId() != ''){
    $options[$item->getId()] = $item->getName();
}
}

$this->addColumn('category_ids',
        array(
            'header'   => Mage::helper('catalog')->__('Categories'),
            'index'    => 'single_category_id',
            'width'    => '150px',
            'type' => 'options',
             'options'  => $options
));

вместо

$this->addColumn('category_ids',
    array(
        'header'   => Mage::helper('catalog')->__('Categories'),
        'index'    => 'category_names',
        'width'    => '150px',
        'filter'   => false,
        'sortable' => false,

));

1 голос
/ 19 января 2012

для отображения названия всех категорий, которые вы можете использовать

$this->addColumn('category_ids',
        array(
                                    'header'=> Mage::helper('catalog')->__('Category'),
                                    'type'  => 'options',
                                    'index' => 'category_ids',
                                    'options' => $this->catOptions,
                                    'renderer'  => 'Your_Module_Block_Adminhtml_List_Cat',
));

в блоке вашего класса

 class Your_Module_Block_Adminhtml_List_Cat extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract
{
    public function render(Varien_Object $row)
    {
        $product = Mage::getModel('catalog/product')->load($row->getEntityId());
        $cats = $product->getCategoryIds();
        $allCats = '';
        foreach($cats as $key => $cat)
        {
            $_category = Mage::getModel('catalog/category')->load($cat);
            $allCats.= $_category->getName();
            if($key < count($cats)-1)
                $allCats.= ' ,';
        }
        return $allCats;
    }

}
1 голос
/ 21 октября 2010

, если вы просто хотите добавить категорию (не путь к категории) и если у продукта есть только одна категория, добавьте это в настройки коллекции:

$collection->joinAttribute('catname','catalog_category/name','category_ids',null,'left');
0 голосов
/ 07 октября 2016

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

Ссылка здесь: здесь

Вы должны создать расширение для отображения категории в сетке товаров.Пожалуйста, создайте следующие файлы, и это будет работать для вас:

Создайте новый файл в app/code/local/SoftProdigy/AdminGridCategoryFilter/Block/Catalog/Product/Grid/Render/Category.php расположении и добавьте следующий код:

<?php
class SoftProdigy_AdminGridCategoryFilter_Block_Catalog_Product_Grid_Render_Category extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract
{
    public function render(Varien_Object $row)
    {
        $product = Mage::getModel('catalog/product')->load($row->getEntityId());
        $cats = $product->getCategoryIds();
        $allCats = '';
        foreach($cats as $key => $cat)
        {
            $_category = Mage::getModel('catalog/category')->load($cat);
            $allCats.= $_category->getName();
            if($key < count($cats)-1)
                $allCats.= ',<br />';
        }
        return $allCats;
    }

}

Создайте новый файл в app/code/local/SoftProdigy/AdminGridCategoryFilter/etc/config.xml расположении идобавьте следующий код:

<?xml version="1.0"?>
<config>
    <modules>
        <SoftProdigy_AdminGridCategoryFilter>
            <version>0.0.0.1</version>
        </SoftProdigy_AdminGridCategoryFilter>
    </modules>
    <global>
        <models>
            <admingridcategoryfilter>
                <class>SoftProdigy_AdminGridCategoryFilter_Model</class>
            </admingridcategoryfilter>
        </models>
        <helpers>
            <admingridcategoryfilter>
                <class>SoftProdigy_AdminGridCategoryFilter_Helper</class>
            </admingridcategoryfilter>
        </helpers>
        <blocks>
            <admingridcategoryfilter>
                <class>SoftProdigy_AdminGridCategoryFilter_Block</class>
            </admingridcategoryfilter>
        </blocks>
    </global>
    <adminhtml>
        <events>
            <core_block_abstract_prepare_layout_before>
                <observers>
                    <admingridcategoryfilter>
                        <class>admingridcategoryfilter/observer</class>
                        <method>addCategoryFilterToProductGrid</method>
                    </admingridcategoryfilter>
                </observers>
            </core_block_abstract_prepare_layout_before>
        </events>
    </adminhtml>
</config>

Создайте новый файл в app/code/local/SoftProdigy/AdminGridCategoryFilter/Helper/Data.php расположении и добавьте следующий код:

<?php
class SoftProdigy_AdminGridCategoryFilter_Helper_Data extends Mage_Core_Helper_Abstract
{

}

Создайте новый файл в app/code/local/SoftProdigy/AdminGridCategoryFilter/Model/Observer.php расположении и добавьте следующий код:

<?php
class SoftProdigy_AdminGridCategoryFilter_Model_Observer
{

    public function addCategoryFilterToProductGrid(Varien_Event_Observer $observer)
    {   
        $block = $observer->getEvent()->getBlock();
        if( ($block instanceof Mage_Adminhtml_Block_Catalog_Product_Grid)  ) {
            $block->addColumnAfter('softprodigy_category_list', array(
                    'header'    => Mage::helper('admingridcategoryfilter')->__('Category'),
                    'index'     => 'softprodigy_category_list',
                    'sortable'  => false,
                    'width' => '250px',
                    'type'  => 'options',
                    'options'   => Mage::getSingleton('admingridcategoryfilter/system_config_source_category')->toOptionArray(),
                    'renderer'  => 'admingridcategoryfilter/catalog_product_grid_render_category',
                    'filter_condition_callback' => array($this, 'filterCallback'),
            ),'name');
        }
    }

    public function filterCallback($collection, $column)
    {
        $value = $column->getFilter()->getValue();
        $_category = Mage::getModel('catalog/category')->load($value);
        $collection->addCategoryFilter($_category);

        return $collection;
    }

}

Создайте новый файл в app/code/local/SoftProdigy/AdminGridCategoryFilter/Model/System/Config/Source/Category.php расположении и добавьте следующий код:

<?php
class SoftProdigy_AdminGridCategoryFilter_Model_System_Config_Source_Category
{
    public function toOptionArray($addEmpty = true)
    {
        $options = array();
        foreach ($this->load_tree() as $category) {
            $options[$category['value']] =  $category['label'];
        }

        return $options;
    }



    public function buildCategoriesMultiselectValues(Varien_Data_Tree_Node $node, $values, $level = 0)
    {
        $level++;

        $values[$node->getId()]['value'] =  $node->getId();
        $values[$node->getId()]['label'] = str_repeat("--", $level) . $node->getName();

        foreach ($node->getChildren() as $child)
        {
            $values = $this->buildCategoriesMultiselectValues($child, $values, $level);
        }

        return $values;
    }

    public function load_tree()
    {
        $store = Mage::app()->getFrontController()->getRequest()->getParam('store', 0);
        $parentId = $store ? Mage::app()->getStore($store)->getRootCategoryId() : 1;  // Current store root category

        $tree = Mage::getResourceSingleton('catalog/category_tree')->load();

        $root = $tree->getNodeById($parentId);

        if($root && $root->getId() == 1)
        {
            $root->setName(Mage::helper('catalog')->__('Root'));
        }

        $collection = Mage::getModel('catalog/category')->getCollection()
        ->setStoreId($store)
        ->addAttributeToSelect('name')
        ->addAttributeToSelect('is_active');

        $tree->addCollectionData($collection, true);

        return $this->buildCategoriesMultiselectValues($root, array());
    }
}

Создайте новый файл в app/etc/modules/SoftProdigy_AdminGridCategoryFilter.xml расположении и добавьте следующий код:

<?xml version="1.0"?>
<config>
    <modules>
        <SoftProdigy_AdminGridCategoryFilter>
            <active>true</active>
            <codePool>local</codePool>
            <depends>
                <Mage_Catalog />
                <Mage_Adminhtml />
            </depends>
        </SoftProdigy_AdminGridCategoryFilter>
    </modules>
</config>

Теперь очистите кеш от управления кешем, и вы увидите столбец категории в сетке продуктов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...