Book Image

Magento 2 Development Quick Start Guide

By : Branko Ajzele
Book Image

Magento 2 Development Quick Start Guide

By: Branko Ajzele

Overview of this book

Magento is an open-source, enterprise-level e-commerce platform with unlimited scope for customization. This makes it a great choice not only for vendors but for developers as well. This book guides you through Magento development, teaching you how to develop modules that extend or change its functionality, leading to more ?exible and profitable Magento stores. You start with a structural overview of the key Magento development components. You will learn where things such as plugins, events, models, controllers, layouts, and UI components ft into the development landscape. You will go through examples of using these components to extend Magento. As you progress, you will be building a diverse series of small but practical Magento modules. By the end of this book, you will not only have a solid foundation in the Magento development architecture; but you will also have practical experience in developing modules to customize and extend Magento stores.
Table of Contents (11 chapters)

Plugins

Plugins are likely one of the most powerful features of Magento. They allow us to modify the behavior of public class functions by intercepting a function call and running code before, after, or around that function call.

Before we eagerly start using them, it is worth emphasizing how plugins can't be used on the following:

  • Final methods
  • Final classes
  • Non-public methods
  • Class methods (such as static methods)
  • __construct
  • Virtual types
  • Objects that are instantiated before Magento or Framework\Interception is bootstrapped

Plugins can be used on the following:

  • Classes
  • Interfaces
  • Abstract classes
  • Parent classes

By doing a lookup for the <plugin string across the entire <MAGENTO_DIR> directory's di.xml files, we can see hundreds of plugin examples spread across the majority of Magento's modules.

The before plugin

The before plugin, as its name suggests, runs before the observed method.

When writing a before plugin, there are a few key points to remember:

  1. The before keyword is appended to the observed instance method. If the observed method is called getSomeValue, then the plugin method is called beforeGetSomeValue.
  2. The first parameter of the before plugin method is always the observed instance type, often abbreviated as $subject or directly by the class type which is $processor in our example. We can typecast it for greater readability.
  3. All other parameters of the plugin method must match the parameters of the observed method.
  4. The plugin method must return an array with the same type and number of parameters as the observed method's input parameters.

Let's take a look at one of Magento's before plugin implementations, the one specified in the <MAGENTO_DIR>module-payment/etc/frontend/di.xml file:

<type name="Magento\Checkout\Block\Checkout\LayoutProcessor">
<plugin name="ProcessPaymentConfiguration"
type="Magento\Payment\Plugin\PaymentConfigurationProcess"/>
</type>

The original method this plugin is targeting is the process method of the Magento\Checkout\Block\Checkout\LayoutProcessor class:

public function process($jsLayout) {
// The rest of the code...
return $jsLayout;
}

The implementation of the before plugin is provided via the beforeProcess method of the Magento\Payment\Plugin\PaymentConfigurationProcess class, as per the following partial example:

public function beforeProcess(
\Magento\Checkout\Block\Checkout\LayoutProcessor $processor,
$jsLayout) {
// The rest of the code...
return [$jsLayout];
}

The around plugin

The around plugin runs around the observed method in a way that allows us to run some code before and after the original method call. This is a very powerful concept, as we get to change the incoming parameters as well as the return value of a function.

When writing the around plugin, there are a few key points to remember:

  1. The first parameter coming into the plugin is the observed type instance.
  2. The second parameter coming into the plugin is a callable/Closure. Usually, this parameter is typed and named as callable $proceed. We must make sure to forward the same parameters to this callable as the original method signature.
  3. All other parameters are parameters of the original observed method.
  4. The plugin must return the same value as the original function, ideally return $proceed(…) or $returnValue = $proceed(); followed by $returnValue; for cases where we need to modify the $returnValue.

Let's take a look at one of Magento's around plugin implementations, the one specified in the <MAGENTO_DIR>module-grouped-product/etc/di.xml file:

<type name="Magento\Catalog\Model\ResourceModel\Product\Link">
<plugin name="groupedProductLinkProcessor" type="Magento\GroupedProduct\Model\ResourceModel\Product\Link\RelationPersister" />
</type>

The original method of this plugin is targeting the deleteProductLink method of the Magento\Catalog\Model\ResourceModel\Product\Link class:

public function deleteProductLink($linkId) {
return $this->getConnection()
->delete($this->getMainTable(), ['link_id = ?' => $linkId]);
}

The implementation of the around plugin is provided via the aroundDeleteProductLink method of the Magento\GroupedProduct\Model\ResourceModel\Product\Link\RelationPersister class, as per the following partial example:

public function aroundDeleteProductLink(
\Magento\GroupedProduct\Model\ResourceModel\Product\Link $subject,
\Closure $proceed, $linkId) {
// The rest of the code...
$result = $proceed($linkId);
// The rest of the code...
return $result;
}

The after plugin

The after plugin, as its name suggests, runs after the observed method.

When writing the after plugin, there are a few key points to remember:

  1. The first parameter coming into the plugin is an observed type instance.
  2. The second parameter coming into the plugin is the result of the observed method, often called $result or called after the variable returned from the observed method (as in the following example: $data).
  3. All other parameters are parameters of the observed method.
  4. The plugin must return the same $result|$data variable of the same type, as we are free to modify the value.

Let's take a look at one of Magento's after plugin implementations, the one specified in the module-catalog/etc/di.xml file:

<type name="Magento\Indexer\Model\Config\Data">
<plugin name="indexerProductFlatConfigGet"
type="Magento\Catalog\Model\Indexer\Product\Flat\Plugin\IndexerConfigData" />
</type>

The original method this plugin is targeting is the get method of the Magento\Indexer\Model\Config\Data class:

public function get($path = null, $default = null) {
// The rest of the code...
return $data;
}

The implementation of the after plugin is provided via the afterGet method of the Magento\Catalog\Model\Indexer\Product\Flat\Plugin\IndexerConfigData class, as per the following partial example:

public function afterGet(Magento\Indexer\Model\Config\Data, $data, $path = null, $default = null) {
// The rest of the code...
return $data;
}

Special care should be taken when using plugins. While they provide great flexibility, they also make it easy to induce bugs, performance bottlenecks, and other less obvious types of instabilities – even more so if several plugins are observing the same method.