January 19, 2009

product associations

Since it is now possible to inject methods into ZMObject based classes, I figured I might as well use it. In fact, this is how most new (framework) features come to exist.

So, what better place than to keep improving the unfinished product associations plugin. I decided to attach a new JSON/Ajax method to the catalog ajax controller. Of course, the devil is in the details and I soon found myself fixing some obscure things in ZMBeanUtil and the reflection code in ZMAjaxController to allow it to find injected methods :}

Once that was all sorted I really could use the existing catalog controller to access my new method :) ! The nice thing is that I do not have to inherit, but due to the fact that the injected method always has access to the original target object, it’s easy to access all relevant data/methods of  the original controller.

And, because it is so nice, another screenshot of the current state of the product picker. The image shows the picker on the second page of products of the ‘Big Linked’ category with one product selected in the current list and one from another category.

product-picker3

January 16, 2009

method injection

Tags: , , , , , , , ,
Filed under: PHP, ZenMagick — DerManoMann @ 12:11 am

I just checked in a fancy change to ZMObject that allows to dynamically add methods to any class (assuming the class extends from ZMObject) at runtime.

So, what’s the deal? you ask? Well, I always have been slightly uncomfortable about the fact that if multiple plugins wanted to extend/modify an existing core class, say, for example, ZMProduct, there could be only a single winner.

The alternative is to add new services and use them in templates. Of course, that is ok and all, but wouldn’t it be much cooler to just use the affected class directly without something like the following?

$value = MyService ::instance()->getFoo($product);

So, compare that with:

$value = $product->getFoo();

And here is how this can be done:

class MyService {
/**
* @param mixed target The instance the method was invoked on (instance of ZMProduct).
* @param var ... some Some single parameter.
*/
public function getFoo($target, $some) {
return "foo: ".$some.": ".$target->getName();
}
}

ZMObject::attachMethod(‘getFoo’, ‘ZMProduct’, array(new MyService (), ‘getFoo’));
$product = ZMProducts::instance()->getProductForId(3);
echo $product->getFoo(‘xx’);

So, what does it do?

  • First there is a new class that implements the calculation of the new property.
  • Next we attach an instance of MyService as handler of getFoo calls on ZMProduct objects
  • Load a product from the database
  • call getFoo('xx') on $product

The same works if the handler is a simple function:

ZMObject::attachMethod('getFoo', 'ZMProduct', create_function('$target, $some', 'return "foo: ".$some.': '.$target->getName();'));

Another of those things that are not strictly necessary, but nice to look at :)