What is the best way to override Magento2 core functions?

What_is_the_best_way_to_override_magento2_core_functions?

What is the best way to override Magento2 core functions?

Hey Everyone This is MO. Here we explain what are better ways to override the core functions. As Magento developers, we need the default functionalities of the framework and also to make changes in default Magento core functions. We can override the core classes or functions using three different strategies namely: 

  • Plugins
  • Events and observers
  • Preference

Plugins

Magento 2’s idea of plugins is, Every Public method can be intercepted, changed, or even circumvented. 

There are mainly three types of plugins:

  • Before Plugin: To modify the input arguments of the method 
  • After Plugin: To modify the return value of the method
  • Around Plugin: To modify both the input and the output or the return value of the method

How to create the Plugins and how does it work?

Plugins are declared in the 

etc\area\di.xml i,e app\code\Mo\Tutorial\etc\frontend\di.xml

Syntax

<config>
    <type name="{ObservedType}">
      <plugin name="{pluginName}" type="{PluginClassName}" sortOrder="1" disabled="false" />
    </type>
</config>

You must specify these elements:

  • type name: The class for which we are writing the plugin.
  • plugin name: An arbitrary plugin name that identifies a plugin. Also used to merge the configurations for the plugin
  • plugin type: The name of a plugin’s class. Use the following naming convention when you specify this 

         element: \vendorname\modulename\Plugin\<classname>

The following elements are optional:

  • plugin sort order: Plugins that call the same method run them using this order.
  • plugin disabled: To disable a plugin, set this element to true. The default value is false. 

 Example:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Catalog\Model\Product">
        <plugin name="MoPlugin" type="Mo\Tutorial\Plugin\Model\ProductAttributesUpdaterPlugin" sortOrder="1"
                disabled="false"/>
    </type>
</config>

While creating the plugin to the method we need to add the prefixes as before, after, or around accordingly.

For  example, to create a plugin for the setName method of some class:

Public function setName($name)
{
//Some code
}

In the plugin class, the  setName method may have one of the following names:

  • beforeSetName
  • aroundSetName
  • afterSetName

When you create a plugin Magento will automatically generate a class wrapper for the plugin target. 

For example, if you want to modify \Magento\Catalog\Model\Product, Magento will auto-generate the \Magento\Catalog\Model\Product\Interceptor class inside the generated directory. 

The auto-generated interceptor class will represent every function inside the target class.

Magento then handles locating the plugins and executing them in the Interceptor class: vendor/magento/framework/Interception/Interceptor.php

Before Plugin

We use the “before plugin” to modify the arguments of the public method. If there is more than one argument, the method should return an array of those arguments, If the method does not change the argument then it should return a null value. 

To modify the input arguments of the setName($name) method, create a before plugin. These methods must have the same name as the observed method with ‘before’ as the prefix.

<?php

namespace Mo\Tutorial\Plugin\Model;


class ProductAttributesUpdaterPlugin

{

    public function beforeSetName(\Magento\Catalog\Model\Product $subject, $name)

    {

        return ['(' . $name . ')'];

    }

}
?>

The method above is run before 

\Mo\Tutorial\Plugin\Model\ProductAttributesUpdaterPlugin::setName. The return value for the “before plugin” determines whether the arguments are going into the next plugin or the final targeted method.

After Plugin

We use the “after plugin” to modify the output or the return value of the public method. Magento requires these methods to have a return value and they must have the same name as the observed method with ‘after’ as the prefix.

To modify the output of the getName() method, create an after plugin. These methods must have the same name as the observed method with ‘after’ as the prefix.

<?php

namespace Mo\Tutorial\Plugin\Model;


class ProductAttributesUpdaterPlugin

{

    public function beforeGetName(\Magento\Catalog\Model\Product $subject, $result)

    {

        return '|' . $result . '|';

    }

}

?>

The after plugin includes the input parameters in addition to the return result.

Around Plugin

The “around plugin” provides full control over the input and output of a function. The original function is passed as a callback and the standard is named $proceed. Magento recommends against using these plugins whenever possible. 

This is because it is easy to alter major functions in the system by omitting a call to $proceed(). around methods must have the same name as the observed method with ‘around’ as the prefix.

It also adds the frame to the call stack to make debugging more cumbersome. Before the list of the original methods, arguments around methods receive a callable that will allow a call to the following method in the chain. 

When your code executes the callable, Magento calls the next plugin or the observed function. 

<?php

namespace Mo\Tutorial\Plugin\Model;


class ProductAttributesUpdaterPlugin

{

    public function aroundSave(\Magento\Catalog\Model\Product $subject, callable $proceed)

    {

        $someValue = $this->doSmthBeforeProductIsSaved();

        $returnValue = null;


        if ($this->canCallProceedCallable($someValue)) {

            $returnValue = $proceed();

        }


        if ($returnValue) {

            $this->postProductToFacebook();

        }


        return $returnValue;

    }

}

?>

If we have multiple plugins interaction then we can solve this using the sortOrder.The lower the sort order, the sooner it will be executed on the list. 

The greater the sort order, the execution is delayed. This allows a degree of control over how one plugin will interact with others.

Additionally, if you need to disable an existing plugin, you can reference it by the name attribute and add the disabled attribute.

How to debug a plugin?

  • Several ways can go wrong with plugins. Here are some to check:
  • Is the di.xml configuration correct? Are there any syntax errors?
  • Is the plugin marked as disabled?
  • Do you have the correct class specified in the <type name="..."> node?
  • Is it the target class?
  • Do you have the correct plugin class specified in the <plugin type="..."> node?
  • Is the class or method you are modifying marked as final? If so, plugins will not work.
  • Does your plugin class have a method to modify a method on the target class?
  • beforeMethodName or afterMethodName or aroundMethodName
  • NOT methodName

Limitations of plugins

  • Plugins only work on public methods (not protected or private).
  • Plugins do not work for the final methods or final classes.
  • Plugins do not work on static methods.
  • Plugins do not work for virtual types.
  • Plugins do not work for interfaces.
  • Plugins do not work for abstract classes or parent classes.

By now we know how plugins are useful to modify the input, output, or execution of an existing public method.

Plugins are best to be avoided in situations like where we have an event. Events work well when the flow of data does not have to be modified.

To know about Event Observers and Preferences check our blog How to override a non-public method in Magento2?. Also, We have given our answer to this question on this.

Thank you for reading. Are you fascinated to know more about Magento, What are you waiting for? Check out the other blogs in the Magento section and follow us through Youtube and Instagram to know more about us.

Post a Comment

0 Comments