Magento-自定义(非eav)模型,按多个字段加载


15

我有一个自定义模型和资源模型。我想使用多个字段来加载模型的单个实例。

该模型具有以下字段:

id
tag_name
custom_name
group_name

我想基于tag_name,custom_name和group_name而不是id加载此模型。

目前,我正在为每个字段使用集合和addFilter。这行得通,但我想知道Magento中是否有针对此类事物的标准策略?

编辑

核心magento在这种情况下似乎不使用集合,而是在资源模型中使用直接sql查询。

一个例子是:

loadByAccountAndDate()Mage_Paypal_Model_Resource_Report_Settlement

当收集似乎是更简洁的方式时,就编写的代码量而言,这是否有原因?

我只是不知道为什么magento选择这样做

Answers:


22

我认为这是一个好方法。也许您需要在模型类中创建一个包装器,这样您就可以避免一遍又一遍地写相同的东西。
就像是:

public function loadByMultiple($tag, $customName, $group){
    $collection = $this->getCollection()
            ->addFieldToFilter('tag_name', $tag)
            ->addFieldToFilter('custom_name', $customName)
            ->addFieldToFilter('group_name', $group);
    return $collection->getFirstItem();
}

您可以在其他任何地方加载这样的项目:

$model = Mage::getModel('model/class_here')->loadByMultiple($tag, $customName, $group);
if ($model->getId()){
   //the instance exists
}
else{
    //not found
}

我已经在使用集合更新我的问题与我的顾虑
马蒂·华莱士

如果您真的想从逻辑中排除集合,请检查@mageUz在其答案中写了什么。我没有测试,但是接缝就像一个好主意。注意:在使用集合时,我仍然看不到任何问题。
Marius

不是我想排除它们,而是我想使用magento最佳实践。如果核心代码以某种特定方式执行某项操作,那么通常这应该是后续操作的标志。但是我要在这个论坛上寻求指导,因为在这种情况下,我真的不知道最好的方法
Marty Wallace

1
在这种情况下,我也担心使用集合。可能所讨论的集合具有_itemObjectClass与实际调用的模型相同的loadByMultiple。因此,结果将不是$x = Mage::getModel('some/model')模型的一个实例,而$x->loadByMultiple($tag, $customName, $group)实际上是另一个/新的实例吗?
kojiro 2014年

@kojiro 是的,这将是不同的实例,但是确实是这样loadByAttribute。参见以下问题以供参考:magento.stackexchange.com/q/5926/146
马吕斯

7

模块/模型/SomeModel.php

public function loadByAttributes($attributes)
{
    $this->setData($this->getResource()->loadByAttributes($attributes));
    return $this;
}

模块/模型/资源/SomeModel.php:

public function loadByAttributes($attributes)
    {
        $adapter = $this->_getReadAdapter();
        $where   = array();
        foreach ($attributes as $attributeCode=> $value) {
            $where[] = sprintf('%s=:%s', $attributeCode, $attributeCode);
        }
        $select = $adapter->select()
            ->from($this->getMainTable())
            ->where(implode(' AND ', $where));

        $binds = $attributes;

        return $adapter->fetchRow($select, $binds);
    }

最后,您可以加载以下模型:

$attributes = array('tag_name'=> 'any', 'custome_name'=> 'some','group_name'=>'some');
$model      = Mage::getModel('module/somemodel')->loadByAttributes($attributes);

更新

顺便说一句,您可以轻松地使用此(loadByAttributes)方法,而不是使用它,这更易于理解。Magento还会在加载集合或实体时调度一些事件,并且第三方扩展可以由观察者更新集合或实体。如果您通过资源(以我和您的示例为例)加载实体,则不会触发任何事件/观察者,并且您可以更快地获得“干净”的实体,而不是进行收集。Magento也不通过这种方式使用缓存的集合,而是直接从db表中加载它。
也许这就是Magento核心模块使用此方法的原因。


我认为您在此行上缺少一个getData(): $this->setData($this->getResource()->loadByAttributes($attributes));应该是: $this->setData($this->getResource()->loadByAttributes($attributes)->getData()); 对吗?
2015年

2

您使用正确addFilter。在Magento中,您可以一次加载任何属性,但不能一次加载多个属性。通过添加过滤器,您可以实现相同的效果,而不会产生额外的开销。


使用db select会不会比使用collection更好?
Marty Wallace

您认为addFilter正在做什么?:-)
user487772 2013年

您能在Mage_Paypal_Model_Resource_Report_Settlement中查看loadByAccountAndDate()的原因,因为它使用的是select而不是collection
Marty Wallace

实际上,核心代码中的这种情况几乎完全是这样,而且我看不到任何使用的集合
Marty Wallace 2013年

1
我已经更新了我对使用收藏
Marty Wallace

1

首先-您过滤集合的策略是正确的。由于Magento延迟加载中的集合,您可以在资源模型中创建方法来更严格地定义自定义加载的要求。

在没有示例代码的情况下,请在资源模型中考虑以下伪方法:

<?php


class Marty_Wallace_Model_Resource_Method extends Mage_Core_Model_Resource_Db_Abstract{

    protected function _construct()
    {
        $this->_init('yourmodel/table', 'entity_id');
    }

    public function loadByCriteria(array $filter)
    {

        //$filter should be array('columnname'=>'value','columname'=>'value')

        $collection = Mage::getModel('yourmodel/class')->getCollection();

        foreach($filter as $column=>$value){
            $collection->addFieldToFilter($column,$value);
        }

        return $collection;

    }
}

我已经更新了有关在此特定用例中使用集合的担忧的问题,但是我没有足够的知识去知道为什么magento会这样做-Marty
Wallace
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.