2

我正在尝试覆盖模型中的一些方法,并且我的任务是避免覆盖和重写模型以最大程度地与其他模块兼容。

我认为最好的方法是在从 Magento 加载模型后简单地装饰模型,但据我所知,由于 Magento 中观察者模式的编写方式,不可能做到这一点。(因为 Magento 总是返回对 的引用$this),并且缺少接口也可能在以后造成麻烦?请参阅 Mage/Core/Model/Abstract.php 的这一部分

/**
 * Processing object after load data
 *
 * @return Mage_Core_Model_Abstract
 */
protected function _afterLoad()
{
    Mage::dispatchEvent('model_load_after', array('object'=>$this));
    Mage::dispatchEvent($this->_eventPrefix.'_load_after', $this->_getEventData());
    return $this;
}

我的问题归结为标题,有没有一种体面的方法可以做到这一点?或者我只是坚持重写:(?

我想走的路是;

  • 活动现场[model]_load_after
  • 返回new Decorator($event->getObject())

在我的情况下,装饰器类会是这样的;

public function __construct(Mage_Sales_Model_Order_Invoice $model)
{
    parent::__construct($model); // sets $this->model on parent class, see below
}

// overwrite the getIncrementId method
public function getIncrementId()
{
    return '12345';
}

// partial of parent class

public function __call($method, array $args)
{
    return call_user_func_array(array($this->model, $method), $args);
}

并且只是一些用于额外说明的伪代码;

$model = Mage::getModel('sales/order_invoice')->load(1);
echo get_class($model);

Namespace_Decorator **INSTEAD OF** Mage_Sales_Model_...

echo $model->getIncrementId();
'12345' **INSTEAD OF** '1000001' ( or whatever the format might be )

感谢您花时间阅读/评论,我真的希望有一种方法可以在不使用代码覆盖或模型重写的情况下以干净的方式完成此任务。

编辑:额外说明

基本上我想要的是在少数情况下返回装饰器的一个实例,sales_invoice 是其中之一,而 customer 是另一个。因此,当对这些模型进行任何 load() 调用时,它将始终返回装饰器的实例而不是模型。只有装饰器覆盖的方法调用会被返回,任何其他方法调用都将通过 __call 对被装饰对象进行“代理”。

4

1 回答 1

1

I'm not sure if I got your question right but here goes.
I think you can use the event [model]_load_after and simply do this:

$object = $event->getObject();
$object->setIncrementId('12345');

Or if you want to use a decorator class make it look like this:

public function __construct(Mage_Sales_Model_Order_Invoice $model)
{
    parent::__construct($model);
    $model->setIncrementId($this->getIncrementId());
}
public function getIncrementId()
{
    return '12345';
}

I know that this is not exactly a decorator pattern but it should work.
I know that when adding a new method to the 'decorator' class you need to add it to attach data to the main model.
This is just my idea. I haven't got an other.

[EDIT]
You can try to rewrite the load method on the object to make it return what you need. But I wouldn't go that way. You can end up screwing a lot of other things.
I don't think there is an other way to do it because load always returns the current object no mater what you do in the events dispatched in the method. see Mage_Core_Model_Abstract::load()

public function load($id, $field=null)
{
    $this->_beforeLoad($id, $field);
    $this->_getResource()->load($this, $id, $field);
    $this->_afterLoad();
    $this->setOrigData();
    $this->_hasDataChanges = false;
    return $this;
}

By making it return new Decorator($this), you might achieve what you need, but just make sure that when calling $model->doSomething() and doSomething() is not a method in your decorator you still end up calling the original method on the model.

于 2013-10-30T12:17:34.353 回答