Magento - расширение класса Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection

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

$_bs_productCollection = Mage::getResourceModel('reports/product_collection')
->addAttributeToSelect('name')
->addAttributeToFilter('visibility', $visibility)
->addOrderedQty()
->setOrder('ordered_qty', 'desc')
->setPageSize(6);
$_bs_productCollection->load();

Итак, я настроил свой модуль и загрузился (он отображается в файле admin/system/config/advanced). Структура папки выглядит следующим образом:

etc/modules/Samsmodule.xml
local/Samsmodule
local/Samsmodule/Catalog
local/Samsmodule/Catalog/etc
   local/Samsmodule/Catalog/etc/config.xml
local/Samsmodule/Catalog/Model
   local/Samsmodule/Catalog/Model/Resource/Eav/Mysql4/Product/Collection.php
local/Samsmodule/Catalog/Helper (not sure if this is needed or not)

Мой Samsmodule.xml:

<config>
<modules>
    <Samsmodule_Catalog>
        <active>true</active>
        <codePool>local</codePool>
    </Samsmodule_Catalog>
</modules>
</config>

Мой config.xml:

<config>
<modules>
    <Samsmodule_Catalog>
        <version>0.1.0</version>
    </Samsmodule_Catalog>
</modules>
<global>
    <models>
        <catalog_resource_eav_mysql4>
            <rewrite>
                <product_collection>Samsmodule_Catalog_Model_Resource_Eav_Mysql4_Product_Collection</product_collection>
            </rewrite>
        </catalog_resource_eav_mysql4>
    </models>
</global>
</config>

И мой Collection.php:

<?php

class Samsmodule_Catalog_Model_Resource_Eav_Mysql4_Product_Collection extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection

{
public function filterbyBestSelling($attribute,$visibility,$_category,$no_of_items)
{
    $this->addAttributeToSelect($attribute)->addOrderedQty()->setOrder('ordered_qty', 'desc')->addAttributeToFilter('visibility', $visibility)->addCategoryFilter($_category)->setPageSize($no_of_items);
    return $this;
}
}

И затем из моего template.phtml я вызываю его так:

$_bs_productCollection = Mage::getResourceModel('reports/product_collection')
->filterbyBestSelling('name',$visibility,$_category,6);

Но он не работает - чего я не хватает? Если я просто добавлю код из моего Collection.php в конец моего основного файла Collection.php и использую тот же вызов, он отлично работает.

Ответ 1

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

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

Терминология Для нормального состояния вещей

  • Модели - это логические классы/объекты, которые определяют поведение некоторой "вещи" (продукта и т.д.) в Magento

  • Модели содержат ресурсы модели. Ресурсы модели - это классы, которые выполняют фактическую выборку данных из некоторого хранилища данных (mysql и т.д.). Это шаблон Data Mapper.

  • Коллекции представляют собой объекты с массивом, подобные свойствам, которые запрашивают базу данных и возвращают группу моделей. Несколько смутно, Коллекции также Ресурсы модели.

Итак, в нормальном состоянии вещей вы можете сказать что-то вроде

Mage::getModel('catalog/product')

чтобы получить модель продукта, а базовая система использует

Mage::getResourceModel('catalog/product');

чтобы получить объект ресурса Mode, который запрашивает один продукт, и либо из следующих

Mage::getResourceModel('catalog/product_collection');
Mage::getModel('catalog/product')->getCollection();

чтобы получить объект Collection, который запрашивает для многих моделей. В текущих версиях Magento каждый объект модели имеет метод с именем "getCollection", который возвращает свой соответствующий Resource Collection.

Отчеты о рельсах

Отчеты идут немного боком, но все еще находится в пределах той же самой вселенной, как описано выше. Оказывается, нет такой модели, как

Mage::getModel('reports/product');

Но имеется коллекция

Mage::getResourceModel('reports/product_collection')

Если вы посмотрите на класс (который вы расширите ниже), вы увидите, что коллекция 'reports/product_collection'

class Mage_Reports_Model_Mysql4_Product_Collection extends Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection

расширяет класс коллекции базовых продуктов. Другими словами, клиентский программист, работающий над секцией отчетов, имел то же самое, что и вы. "Я хочу добавить некоторые методы к Mage::getModelResource('catalog/product_collection'). Они сделали это с помощью расширения базового класса.

Заткнись, я просто хочу, чтобы это работало

Итак, что вы действительно хотите сделать, это

  • Создайте новый класс Samsnamespace_Samscatalog_Model_Mysql4_Product_Collection, который расширяет базовый класс коллекции Mage_Reports_Model_Mysql4_Product_Collection.

  • Убедитесь, что вызов Mage::getModelResource('samscatalog/product_collection') возвращает экземпляр вышеуказанного класса, настроив наш модуль на использование моделей и ресурсов модели.

Мы также немного изменим структуру модуля, чтобы облегчить путаницу. Я не большой поклонник предоставления папок модулей тем же именам, что и основные модули (т.е. "Каталог" ), а папка верхнего уровня (после local/) на самом деле является пространством имен, а не папкой с модулем. (Пространство имен может содержать много модулей)

Мы не переопределяем класс. Мы настраиваем пользовательский модуль под вашим пространством имен, чтобы использовать как Модели, так и Ресурсы Модели. Затем мы определяем ресурс модели, который расширяет существующий класс PHP уже в системе. Переопределения должны использоваться только тогда, когда вы хотите изменить поведение конкретного вызова метода. (Пристрастия к тому, чтобы помогать в этом, но в общем сообществе есть общая путаница в том, что он стоит задуматься над ним и далее.)

Сначала мы создадим структуру и файлы каталога модулей. Нам просто нужно два

local/Samsnamespace/Samscatalog/etc/config.xml
local/Samsnamespace/Samscatalog/Model/Mysql4/Product/Collection.php

(и не забудьте включить модуль в приложении /etc/modules. Если вы не знаете, что это значит, начать чтение)

Файл Collection.php должен содержать

<?php
class Samsnamespace_Samscatalog_Model_Mysql4_Product_Collection extends Mage_Reports_Model_Mysql4_Product_Collection    
{
    /* your custom methods go here*/
}

И файл конфигурации должен содержать

<config>
    <modules>
        <Samsnamespace_Samscatalog>
            <version>0.1.0</version>
        </Samsnamespace_Samscatalog>
    </modules>
    <global>
        <models>
            <samscatalog>
                <class>Samsnamespace_Samscatalog_Model</class>
                <resourceModel>samscatalog_mysql4</resourceModel>
            </samscatalog>

            <samscatalog_mysql4>
                <class>Samsnamespace_Samscatalog_Model_Mysql4</class>
            </samscatalog_mysql4>
        </models>
    </global>
</config>

С этими файлами на месте и включенным модулем вы можете позвонить

$test = Mage::getResourceModel('samscatalog/product_collection');           
var_dump(get_class($test));

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

Что происходит

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

Когда вы говорите

Mage::getResourceModel('samscatalog/product_collection');

В базовых системах системных кодов говорится "ОК, поэтому эта модель ресурсов"

samscatalog/product_collection

является частью

samscatalog/product

(не совсем верно в этом случае, но это то, что думает система).

Итак, поскольку модель ресурса samscatalog/product_collection является частью модели samscatalog/product, рассмотрим конфигурацию в

global/models/samscatalog/resourceModel

Чтобы получить URI модели ресурсов

samscatalog_mysql4

а затем используйте это, чтобы посмотреть конфигурацию в

global/models/samscatalog_mysql4/class

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

Samsnamespace_Samscatalog_Model_Mysql4

Это означает, что модель ресурсов samscatalog/product_collection называется

Samsnamespace_Samscatalog_Model_Mysql4_Product_Collection

а затем его просто автоматическая загрузка Magento, которая делает

include('Samsnamespace/Samscatalog/Model/Mysql4/Product/Collection.php');

Ответ 2

Что представляет собой класс получаемой коллекции? Работает ли ваше переопределение?

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

<global>
    <models>
        <catalog_resource_eav_mysql4>
            <rewrite>
                <product_collection>Samsmodule_Catalog_Model_Resource_Eav_Mysql4_Product_Collection</product_collection>
            </rewrite>
        </catalog_resource_eav_mysql4>
    </models>
</global>

Попробуйте это вместо:

<global>
    <models>
        <catalog>
            <rewrite>
                <resource_eav_mysql4_product_collection>Samsmodule_Catalog_Model_Resource_Eav_Mysql4_Product_Collection</resource_eav_mysql4_product_collection>
            </rewrite>
        </catalog>
    </models>
</global>

Тег внутри относится к модулю. Каталог - это модуль, а catalog_resource_eav_mysql4 - нет. Тег внутри задает дескриптор класса, который по сути является всего после Mage_Catalog_Model_ в имени класса.

Надеюсь, что это поможет!

Спасибо, Джо