Home » Magento tutorial for developer » Magento tutorial for developer – Part 11 – Magento System Overrides and Upgradability

Magento tutorial for developer – Part 11 – Magento System Overrides and Upgradability

An oft-touted and often overused feature of The Magento Ecommerce System is the ability to override core system behavior. Another oft-discussed topic for Magento developers is upgradability, and how overrides get in the way of that. Today we’re going to look at the various ways overrides make switching versions difficult with Magento tutorial for developer – Part 11 – Magento System Overrides and Upgradability.

Before we begin, it’s important to point out we’re talking about changing the core “Business Logic” of Magento. Changes to phtml templates are both expected and common in all but the simplest of stores.

Hacking the Source

The “least upgradable” way to change the behavior of Magento (or any PHP based system) is to alter the source code directly. If you want to change the behavior of the the Product Model, you edit the Product Model file

When you do this, you’ve forked the Magento code base. Anytime you upgrade the system you’ll need to do a file by file merge with your forked version. This rarely goes well.

Also, your run the risk of changing expected behavior of methods by having them return different values, not taking actions that the system may depend on, or alter data in unexpected, (rather than expected), ways. We’ll talk more about this below.

Unfortunately, despite its inadvisability, this is the easiest and most understandable way for many PHP developers to start working with Magento. Before starting any new project I always download a clean version of the source and run a diff against both lib and app/code/core to see what sort of changes have been made to the core.

Including Different Classes

Magento, or more accurately PHP, searches for class files in the following Magento folders.

Because of this, and because of the order Magento constructs PHP’s include paths, placing a copy of a core file in the app/code/local folder means PHP will include it first. So if you wanted to change the functionality of the Product Model, you’d add your own copy

Your file defines the class instead of the core file, and therefore the core file never needs to be included. This avoids the problem of merging files that hacking the source creates, and also centralizes all your customizations in one directory structure.

However, this is still only marginally better, and a solution you should avoid. Similar to hacking the core system files, you’re risking a changing the behavior of vital class methods.

For example, consider the getName method on the afformentioned Product Model

While overriding this method, you might inadvertently add a code path in your override where this method returns null

If other parts of the system rely on this method to return a string, your customizations might break those other parts of the system. This gets even worse when methods are returning objects, as trying to call a method on null will result in a fatal error (this is part of what Java and C# programmers are harping on about w/r/t type safety in PHP)

Next, consider the validate method in the same Model.

Here, you might inadvertently remove the dispatching events.

Other parts of the system that rely on these events being fired would stop working.

Finally, you’re still not out of the woods during an upgrade. If the methods of any class change during an upgrade, Magento will still be including your old, outdated class with the old, outdated methods. Practically speaking, this means you still need to perform a manual merge during your upgrade.

Using the Override/Rewrite System

Magento’s class override/Rewrite system relies on the use of a factory pattern for creating Models, Helpers, and Blocks. When you say

you’re telling Magento

“Hey, go lookup the class to use for a “catalog/product” and instantiate it for me.

In turn, Magento then consults its system configuration files and says

“Hey, config.xml tree! What class am I supposed to use for a “catalog/product”?

Magento then instantiates and returns the Model for you.

When you override a class in Magentoo, you’re changing the configuration files to say

“hey, if a “catalog/product” Model is instantiated, use my class (Myp_Mym_Model_Product) instead of the core class

Then, when you define your class, you have it extend the original class

This way, your new class has all the old functionality of the original class. Here you avoid the problem of merging files during an upgrade and the problem of your class containing outdated methods after an upgrade.

However, there’s still the matter of changing method behavior. Consider, again, the getName and validate methods. Your new methods could just as easily forget/change-the-type-of a return value, or leave out a critical piece of functionality in the original methods.

The override/rewrite system won’t protect you from this, but it will give you ways to avoid it. Because we’re actually extending the original class, we can call the original method using PHP’s parent:: construct

By calling the original methods, you’ve ensured that any actions that need to take place will take place. Also, by getting the original return value, you’ve reduced the chances that your method will return something unexpected.

That’s reduced, not eliminated. It’s still up to you as the developer to ensure that your custom code returns objects or primitives that are the same as the original method’s. That means even if you use the provided override system, it’s still possible to break the system.

Because of this, when I have control of the architecture of a solution I try to keep my overrides to a minimum. When I do have to override I always try to end my methods with a

If my overrides need that original method to run first, I used a construct something like

The 'mymodule/immutable' URI points to a simple immutable object implementation.

This doesn’t prevent someone (including me) from overwriting $original_return with something else, but it does discourage it and makes it obvious when someone has. If there’s a method in my override class that doesn’t end in either $original_return->getValue(); or parent::method my eyes are immediately drawn to it as a possible culprit for whatever problem I’m debugging.

Finally, there are times where you want, (or think you want) to change the return value of a core method. When the need for this arrises, I find it’s much safer to define a new method that calls the original, and then change your theme to call this new method.

This ensures any additional side effects created by the original method still occur, the original return type/result is the same, and you can still add your custom logic to specific parts of the system.

Wrapup

Upgradability to any major, or even minor, version of a software package you don’t control is always going to be a bumpy ride. Apple and Microsoft spend millions of dollars testing their upgrade paths during new OS releases, and the Internet is still filled with horror stories of the edge cases they miss. Even inside organizations where everyone’s working towards the same goal new versions often bring unspoken assumptions to the surface quickly as builds break and developers are forced to acknowledge the reality that they work with other human beings.

As a user of the Magento Ecommerce System, your job is to ensure that changes to the core system are kept to a minimum, and that when those changes are needed they’re done in a clean, easily diagnosable matter. Leveraging the Magento override/rewrite system is a powerful tool towards this end.

About Alan Storm

avatar
Alan Storm is a technology strategist, software developer and writer living and working in Portland, OR. He publishes articles on his website http://alanstorm.com and is the creator of the Magento development extension Commerce Bug.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Scroll To Top