Magento 2 : Why use rewrites when you can use plugins?

Remember class rewrites? That nifty little feature from Magento 1 where you could override any given class in Magento with your own implementation? Of course you do!
Well, then you also might remember the problem with rewrites: that as soon as more than 1 module tries to rewrite the same class you had a problem. In that case, you needed to add dependencies and rewrite the rewritten class (or even worse: edit community code so they would rewrite your rewritten class). Magento 2 also has rewrites. But it also has plugins. In this article I’ll cover both.

Class rewrites in Magento 2

If you want to rewrite a class in Magento 2, just like you would have done in Magento 1, you can do this in the file di.xml :

XHTML

1

2

<preference for="Magento\Catalog\Model\Product"

type="Gielberkers\Example\Rewrite\Magento\Catalog\Model\Product"/>

With this line, every time the Magento\Catalog\Model\Product -class is instantiated, Magento actually returns Gielberkers\Example\Rewrite\Magento\Catalog\Model\Product. The rest is the same as in Magento 1; you can make your new class extend the original class and rewrite some of the functions declared in the original class. You can even use constructor injection in your new class. However, like in Magento 1, it has the same big problem: it’s not very flexible when multiple models try to modify the behaviour of the same class.
And that’s where plugins come in!

Plugins

Plugins are a concept in Magento that allow you to modify the behaviour of (almost) any given method in (almost) every class without having to rewrite them. Multiple vendors can register their plugins for the same class without having to worry about collisions. With a Magento plugin, you are able to do the following:

Manipulate the class or arguments before a method gets executed.

Manipulate the class or results of a method after it gets executed.

Perform actions ‘around’ the execution of a method (before and after in one method call).

So how does this actually work?

Register your plugin

Please note that i’ll be using the boilerplate module from the article ‘Creating a module in Magento 2‘ as the entry point for this article.
To register your plugin, we open our di.xml file again and add the following line:

XHTML

1

2

3

4

5

6

7

<type name="Magento\Catalog\Model\Product">

<plugin name="my_product_plugin"

type="Gielberkers\Example\Plugin\Magento\Catalog\Model\Product"

sortOrder="1"

disabled="false"

/>

</type>

In the above we declared the following plugin for the type Magento\Catalog\Model\Product :

It has the name ‘my_product_plugin’. This is actually arbitrary and it doesn’t follow any convention. It just should be unique.

type points to the class in which our plugin resides.

sortOrder can be used to give a priority. This way, multiple plugins can be registered for the same class, and you can control the order in which they are executed.

disabled can be used if you want to disable your plugin, but why would you ever want to disable something cools like this?

Create the class

So lets just create our class shall we? In this example I follow the convention to keep the folder structure intact of the classes I write plugins for. I’m not sure if that’s the proper convention to follow, but it works for me. So in your folder where you store your plugin (Plugin/Magento/Catalog/Model for example), create a file called Product.php and add the following:

PHP

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

namespaceGielberkers\Example\Plugin\Magento\Catalog\Model;

classProduct

{

publicfunctionbeforeSetName(

\Magento\Catalog\Model\Product$product,string$name)

{

returnstrtolower($name);

}

publicfunctionafterGetName(

\Magento\Catalog\Model\Product$product,string$name)

{

returnstrtoupper($name);

}

publicfunctionaroundSave(

\Magento\Catalog\Model\Product$product,\Closure$proceed)

{

$this->doSomethingBeforeSave();

$result=$proceed();

if($result){

$this->doSomethingAfterSave();

}

return$result;

}

}

Now we have a very simple class but it immediately shows us some of the magic that is happening under the hood:

When a call is made to Product::setName($name) , the beforeSetName() of our plugin is executed, making the $name -parameter lowercase.

Similar, when a call is made to Product::getName() , the result return from that method is passed to our plugins’ afterGetName() -method, and made uppercase in this example.

Last but not least, when a call is made to Product::save() , a call is made to the aroundSave() -method of our plugin that does something before and after the actual save-method. Note in the argument list of this method we have the callable argument $proceed . In this example this is the save-method of our product model, but with multiple plugins registered to the same class/method, this can also be the method of another plugin.

In conclusion

In Magento 1, a lot of times when you had to rewrite a class, this was mostly not because you drastically had to change the inner workings of a method, but in 95% of the cases you had to be able to manipulate the income or output of that specific method. With plugins you now have a more convenient and safer method to do such manipulations.
There will however still be situations where the rewriting of an entire class is desirable, but as with many things in Magento: when you want to achieve something there are more than often multiple ways in doing so.

One thought on “Magento 2 : Why use rewrites when you can use plugins?”

This is the blog Giel Berkers,
a fulltime web developer from The Netherlands with a passion for the web.
I want to share ideas, knowledge, but also learn from
my readers. If you got any questions, or need help with something, feel free to drop me a
line.If I think that more people can benefit from the answer on your question, I'll write a blog post about it.