Magento - 扩展 Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection 类

11

好的,这个问题是从我最近在这里提出的另一个问题引申而来。基本上,我想扩展 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();

我已经设置好了我的模块,它正在加载(在管理/系统/配置/高级选项中显示)。文件夹的结构如下:

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文件的底部,并使用相同的调用,那么它可以正常工作。

2个回答

21

在之前的讨论中,我不是故意让你等待,但这个问题没有一个快速的答案,否则要么会看起来像魔法,要么会更加混淆人们的思路。

除非你要改变现有方法的行为,否则不需要覆盖类。你只需要创建一个新类,继承现有类即可。以下是如何做到这一点。

术语

  1. 模型是定义Magento中某个“事物”(产品等)行为的逻辑类/对象

  2. 模型包含模型资源。模型资源是实际从某些数据存储区(mysql等)获取数据的类。这是数据映射器模式。

  3. 集合是具有类似数组属性的对象,用于查询数据库并返回一组模型。有点令人困惑的是,集合也是模型资源。

因此,在正常情况下,您可能会说:

Mage::getModel('catalog/product')

获取产品型号和底层系统使用的方法

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

要获取查询单个产品的 Mode Resource 对象,可以使用以下任一方法:

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

获取查询多个模型的Collection对象。在当前版本的Magento中,每个Model对象都有一个名为“getCollection”的方法,该方法返回其相应的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')添加一些方法。他们通过扩展基类来实现这一点。

闭嘴,我只想让它工作

所以,你真正想做的是:

  1. 创建一个新类Samsnamespace_Samscatalog_Model_Mysql4_Product_Collection,该类扩展了基础Mage_Reports_Model_Mysql4_Product_Collection集合类。

  2. 通过配置我们的模块使用Models和Model Resources,确保调用Mage::getModelResource('samscatalog/product_collection')返回上述类的实例。

我们还将改变您的模块结构,以帮助减少命名混淆。我不喜欢给模块文件夹起与核心模块相同的名称(例如“Catalog”),而顶层文件夹(在local/之后)实际上是一个命名空间,而不是模块文件夹。(命名空间可以包含多个模块)

我们没有覆盖类。我们正在配置一个自定义模块,使其在命名空间下同时使用Models和Model Resources。然后,我们定义了一个模型资源,该资源扩展了系统中已经存在的一个PHP类。只有当您想要更改特定方法调用的行为时,才应使用覆盖。(对此我感到抱歉,但社区中已经有足够多的普遍混淆,值得一再强调。)

首先,我们将创建模块目录结构和文件。我们只需要两个文件。

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

(不要忘记在app/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_collectionsamscatalog/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');

如果你认为他后面可能会使用核心加载的集合,那么你会说覆盖更适用,还是仍然不适用?我的想法是确保所有这样的集合都继承所需的行为,以便以后更容易访问。如果你的回答比我好,请点个赞! - Joe Mastey
@joe,是的,如果你想让这些方法在核心加载的所有集合中都可用,那么覆盖/重写是一种解决方法。 - Alana Storm
哇,非常感谢您花时间详细解释。现在我已经填补了遗漏的空白,不仅代码可以运行,而且我真正理解了其中的原理。这对于 Magento 来说并不是每天都会发生的事情!我还要补充一点,我购买了您的 CommerceBug 扩展,它确实非常有用,可以帮助我们了解 Magento 加载特定页面时正在发生什么。强烈推荐给任何想掌握 Magento 的人(在此处查看:http://store.alanstorm.com/products/commerce-bug)。 - Marlon Creative
2
很棒的信息,确实帮助我扩充了我的收藏。@Alan Storm,你是Magento开发中的Jon Skeet :) - Neil Aitken
1
一年多以后,仍然非常有用,如果没有你 @AlanStorm ,我们该怎么办呢 ;) - Yaroslav

0

结果产品集合的类是什么?你的重载起作用了吗?

这部分看起来有点可疑,如果它真的能正常工作,我会感到惊讶:

<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 是一个模块,而 catalog_resource_eav_mysql4 不是。标签内指定了一个类句柄,它基本上是类名中 Mage_Catalog_Model_ 之后的所有内容。

希望这能帮到你!

谢谢, 乔


1
你的直觉不错,但我不确定那样会行得通。Sam 正试图通过 "Mage::getResourceModel" 实例化一个类,而不是通过 "Mage::getModel",这意味着有些不同的规则在起作用(此外,在这里覆盖并不是最好的选择,请参见下面/上面的答案)。 - Alana Storm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接