Proper Magento Class Overrides
The Good
Magento has a system that allows a developer to easily override a core class by introducing a rewrite into the moduleβs XML configuration. This works by utilising a string as an abstraction of the true class name, passed to the Mage::getModel($key)
method for class instantiation, instead of the traditional $object = new MyClassName();
.
It follows that we can then easily generate a lookup table mapping keys to class names, and return the corresponding class. This lookup table is populated and modified by the Magento initial configuration and rewrites.
This is great right? If I want to add some extra functionality to the getProduct()
method of the Mage_Product_Model_Product
class then I just create my own Nick_Rocks_Model_Product
class and change the functionality, and add a rewrite.
The Bad
Now what happens when I need some extra-extra functionality added to the getProduct()
method? I decide I donβt have enough time to rewrite the module myself, so I check out Magento Connect and find a module thatβs a perfect fit for my current requirements. I install, only the find that the extra functionality added by my initial module has been removed and only the extra-extra functionality remains. Dammit. Bad ju-ju.
The F-ugly How can we get around this problem? We have two situations.
- Overriding the class to only provide extra methods
- Overriding the class to change the functionality of new methods
In the first situation we can quite easily get around our problem by implementing multiple inheritance, of sorts. An implementation is offered by Josh Ribakoff. There is an obvious performance overhead introduced here β what if we have a long ass list of classes that are attempting to rewrite this class? We have to invoke every one of these classes and check the object for the existence of the method, or use some trΓ¨s clever reflection. Bad ju-ju.
The previous solution does not solve the problem of overriding specific methods. Consider our long ass list of classes all wanting to override the same method? Which one do we let do it?
The Solution
Itβs simple. Use event-listeners, helpers, or extend (not override) the core classes to form your own.
The only drawn back to performing these kinds of changes is that they may require a design change when overriding a core class would not. Big deal? Anyone serious about their store will hire someone to install the module and make the design changes themselves. There should be no cutting corners when confidential user information is involved.
Okay, so itβs not so simple. Sometimes the hooks for observing simply do not exist in the code. Some of this is down to the core Magento developers. Iβm sure theyβd agree that they donβt always code with a module developer in mind. Take the mass action section of the order screen for example. The only way to add another option to the dropdown there is to extend the class and modify the button yourself.
Here are some ideas.
When to (ideally) use event-listeners:
- Adding a button the admin area (not supported by Magento)
- Adding a value to a dropdown
- Performing an action after/before an important system event (adding/deleting/updating orders/invoices/products/configuration)
When to use helpers:
- Use case: Display the number of reward points obtained by completing this order (
Mage::helper('rewards')->getOrderRewardPoints($_order)
, instead of$order->getRewardPoints()
)
When to extend the core classes:
- When you need to add some more logic to the internal class functionality
- Use case:
Mage::getModel('my/order')->load($_orderId)->sendSMS()
As Magento continues to grow we need loosely couple our modules to the internal workings of Magento. Honestly, a module should be able to run without extending a single core class, even if it needs some changes to the design.
I think this is the way to do it. What do you think?