Magento 2 Certified Professional Developer Guide
Section 1: Magento Architecture and Customization Techniques
1.1. Describe Magento’s module-based architecture
Magento 2 modules are realized with MVVM architecture:
MVVM has three layers:
- Model
The Model contains the application’s business logic and depends on an associated class—the ResourceModel – for database access. Models depend on service contracts to disclose their functionality to other application layers. - View
The View is both structure and layout of what is seen on a screen – the actual HTML. This is achieved in the PHTML files distributed with modules. Such files are associated with each ViewModel in the Layout XML files, sometimes referred to as binders. The layout files can as well assign JavaScript files to be used on the final page. - ViewModel
The ViewModel works together with the Model layer and exposes only necessary information to the View layer. In Magento 2, this is handled by the module’s Block classes. Note that this was usually part of the Controller role of an MVC system. On MVVM, the controller is only responsible for handling the user flow, meaning that it receives requests and either tells the system to render a view or to redirect the user to another route.
Magento 2 architecture consists of 4 layers:
- Presentation Layer
Presentation Layer is the top layer that contains view elements (layouts, blocks, templates) and controllers.
Presentation Layer usually calls the service layer using service contracts. But, depending on the implementation, it may cross over with the business logic. - Service layer
Service layer is the layer between presentation and domain layers. It executes service contracts, which are implemented as PHP interfaces. Service contracts allow to add or change the business logic resource model using the dependency injection file (di.xml). The service layer is also used to provide API access (REST / SOAP or other modules). The service interface is declared in the / API namespace of the module.
Data (entity) interface is declared inside / Api / Data. Data entities are the structures of data passed to and returned from service interfaces. - Domain layer
The domain layer is responsible for business logic that does not contain information about resources and the database. Also, the domain layer may include the implementation of service contracts. Each data model at the domain layer level depends on the resource model, which is responsible for the database access. - Persistence layer
The persistence layer describes a resource model that is responsible for retrieving and modifying data in a database using CRUD requests.
It also implements additional features of business logic, such as data validation and the implementation of database functions.
Describe module limitations
- Certain modules can come in conflict with each other if the dependencies in module.xml (sequence) are specified incorrectly.
- Not all classes can be overridden with modules.
How do different modules interact with each other?
Different modules interact with each other via dependency injection and service contracts. They can also be dependent on other modules when they apply other modules’ logic.
What side effects can come from this interaction?
If modules contain di.xml files, such files may sometimes load in the wrong order or try to override the already overridden module functionality. To resolve this situation, use sequence in module.xml.
When modules use other modules’ logic and this very module is deleted, the dependencies would be unable to load and an error at the code execution will occur.
1.2 Describe Magento’s directory structure
Determine how to locate different types of files in Magento. Where are the files containing JavaScript, HTML, and PHP located?
The whole Magento structure can be divided into the following types:
- Magento root structure
- Modules structure
- Themes structure
To begin with, Magento has various areas that allow to determine configuration, view files, etc. for a certain area. Adminhtml (applied to the administration panel) and frontend (applied to frontend parts of the website) are examples of area. From this point, we will use <area> to denote any of the available areas.
Magento root partition structure:
- app – the directory recommended for Magento components development. It consists of:
- design – contains themes
- code – contains modules
- etc – contains Magento framework settings
- i18n – contains the language package. Example:
- bin – there the executed Magento file is located that allows to manage the website via CLI.
- dev – the directory for Magento test scripts (for more information, follow the link https://devdocs.magento.com/guides/v2.3/mtf/mtf_quickstart.html).
- generated – contains the generated php files (Factories, Proxies, Interceptors, DI configuration).
- lib – used for Magento library files.
- phpserver – contains the router file “router.php” for the php Built-in web server. Allows to use Magento without a third-party web server, like nginx and apache. Here is the example of php Built-in web server launch: php -S 127.0.0.1:8082 -t ./pub/ ./phpserver/router.php
- pub – the directory used to access Magento static files. It contains the following directories:
- errors – stores the error pages,
- media – stores all media files (product, pages, etc.),
- static – stores Magento themes generated files.
This directory can be specified as web root in nginx config or in apache config. Numerous Magento directories contain “.htaccess” files (including root and pub), which allow you to configure apache for a specific directory. Nginx does not support .htaccess. For nginx, Magento has a nginx.conf.sample file, which is an example of Magento configuration for nginx. This file can be copied, modified, and include the main nginx configuration file.
- setup – contains Setup Wizard
- update – contains Magento Updater
- var – contains all the temporary files. Consists of:
- cache – contains cache files if cache utilizes file system as a storage
- page_cache – contains FPC (Full Page Cache) files, if FPC utilizes file system as a storage
- log – contains Magento logs
- report – contains Magento error/exception files that were not intercepted by code
- session – contains session files
- view_preprocessed – contains style generated files and minified HTML
- vendor – contains the installed composer packages. When Magento is installed via composer or using official site’s archive, then all the standard Magento modules and Magento Framework are located in this folder. In case you install via the official GIT repository, which is recommended only for contributing, then Magento Framework will be located in lib/internal folder, while the default modules – in app/code folder.
Next, we will proceed with module structure.
Modules can be located in /app/code and /vendor directories.
The modules in /app/code can be found at a similar path – /app/code/BelVG/MyModule, where BelVG is vendor name, MyModule – module name (in capitals). PSR-0 standard is used for php classes loading in /app/code directories (https://www.php-fig.org/psr/psr-0/). Example: on request, \BelVG\MyModule\Model\MyModel class will be automatically loaded with app/code/BelVG/MyModule/Model/MyModel.php file.
Modules in /vendor are located at the similar /vendor/belvg/module-my-module path, where belvg/module-my-module is the composer package name. Package name contains the names of a vendor and a project. In theory, there are no strict requirements to the package name because it does not impact the module operation. But, for your own comfort, it is better to specify package name as “{vendor-name}/module-{module-name}”. Package name should be in lowercase, with words separated by dashes. PSR-4 standard is applied in /vendor directory for loading php classes (https://www.php-fig.org/psr/psr-4/).
Example: when requested, \BelVG\MyModule\Model\MyModel class is automatically loaded from the file inside the /vendor/belvg/module-my-module/Model/MyModel.php composer package.
Hereinafter <module_dir> will be used to specify module root directory, for this directory can be located both in app/code and in vendor.
It is recommended to install the third-party modules via composer.
Inside the module directory, the following directories and files are located:
- etc – required directory where the module configuration is stored.
- Block – the directory with php class blocks.
- Model – the directory with models and resource models
- Controller – contains all actions for the module. Controller\<Controller>\<Action> is the php classes template for all module actions. For instance, for <front_name>/<controller>/<action>/ query the Controller/<Controller>/<Action>.php file will be requested.
- Helper – contains helper classes
- Console – contains php classes for CLI calls via /bin/magento.
- Api – contains API interfaces.
- Observer – contains php files of observer classes.
- i18n – localization files directory
- Setup – php classes directory that executes certain actions during module installation, upgrade, refresh or deletion. From Magento 2.3 version and further, the directory also contains data and schema patches.
- Plugins – the directory, containing plugins for classes and interfaces.
- Ui – contains auxiliary php classes for UI components, like modifies, data providers, etc.
- view – contains templates, CSS, JS, images, layouts, UI components files. The internal structure of this directory consists of <area> and base, with base storing the files that relate to all areas. <area> and base have the similar file structures.
To make an example, we will give examples of two areas’ contents :
This is the internal structure of the directories:
- email – contains email templates. For example, order_new.html
- layout – contains layouts xml files. Commonly, the layout name is formed according to this template: {route_id}_{controller}_{action}.xml
- templates – contains phtml templates’ files
- page_layout – contains files, describing Magento page types (1column.xml, 2columns-left.xml, etc,)
- ui_component – contains .xml files with UI components description
- web – contains static files, template files for KnockoutJS, JS, theme files and images. Below is web directory example:
css – contains css styles
images – contains images
js – contains JavaScript files
template – contains .html templates for KnockoutJS
n. registration.php – the required file that registers the module in Magento.
o. composer.json – contains composer package configuration.
Next we will describe the design structure.
Magento 2 templates are located in app/design/ and vendor folders. Each Magento 2 theme is connected to a certain area.
Themes for admin panel are located at app/design/adminhtml folder, while app/design/frontend contains themes for frontend.
Themes in app/design are located at <area>/<ThemeVendor>/<theme_name> folders, where <ThemeVendor> is written in capital letter, <theme_name> in lowercase. For example: app/design/frontend/BelVG/my_theme.
Themes in /vendor are located at the following path /vendor/belvg/theme-frontend-my-theme, where belvg/theme-frontend-my-theme is composer package name. Similar to modules, there are no requirements to composer package name, but for simplicity, it is better so name them as “<vendor-name>/theme-<area>-<theme-name>”.
Further in the text, we will use <theme_dir> to define the theme root directory, for this directory can be located both in app/design and in vendor.
The following directories and files are located in the directory together with the theme:
- <ModuleVendor>_<ModuleName> – common template for override view module files. For example, BelVG_CustomModule.
Inside the directories and files, the structure is similar to view/<area>/ folder inside the module (for example, app/code/BelVG/CustomModule/view/frontend). - etc – contains theme configuration files.
- media – contains theme media files.
- web – contains theme css/js/fonts files.
- file theme.xml – a mandatory file with the theme configurations, like the name of the theme and its parent.
- requirejs-config.js – contains RequireJS config
- registration.php – a mandatory file that registers a theme in Magento.
- composer.json – contains composer package configuration.
How do you find the files responsible for certain functionality?
To find the files responsible for certain functionality, search among di.xml files (Dependency Injection configuration). Another way is to search in a module or theme layout files, if you need to find certain blocks. The hints, enabled in the store settings (Stores -> Configuration -> Advanced -> Developer), can also prove helpful for this type of search.
For actions search, use the directories structure, because actions are located at the module directory the following way: <module_dir>/Controllers/<Controller>/<Action>). Front Name is specified in <module_dir>/etc/<area>/routes.xml, so finding it via the file search is a relatively simple task.
To search for the model functionality, use the full class or interface name (including namespace). Conduct the file search, specifying the full name of the class or the interface (without leading backlash).
In case of SSH access, you can use `grep` to search files with particular content:
grep -r 'String that you are looking' [path/to/search]
Example (search files with content “Catalog\Model\ProductRepository” in vendor/magento/module-catalog folder):
grep -r 'Catalog\\Model\\ProductRepository' vendor/
In case you know the file name, you can use `find`:
find [path/to/search] -name 'FileNameMask'
Example (search all webapi.xml files in `vendor` folder):
find vendor/ -name webapi.xml
When you know both the filename and its contents:
find [path/to/search] -name 'FileNameMask' -exec grep 'String that you are looking' {} +
Example (search *.xml files with content “Catalog\Model\ProductRepository” in vendor folder):
find vendor/ -name '*.xml' -exec grep 'Catalog\\Model\\ProductRepository' {} +
1.3 Utilize configuration XML and variables scope
Determine how to use configuration files in Magento 2. Which configuration files correspond to different features and functionality?
In Magento 2, the configuration is stored at the following locations:
- In xml files of modules, themes, languages and app/etc folder.
- In the database in core_config_data table.
- In app/etc/config.php and app/etc/env.php files.
- In the framework variables.
One can modify the configuration from the admin panel only when it is stored in core_config_data and is not overridden in pp/etc/config.php, app/etc/env.php or via environment variables. In case it is overridden, it is disabled at the admin panel:
app/etc/config.php and app/etc/env.php files contain Magento basic configuration (for instance, modules list, scopes, themes, database credentials, cache config, override core_config_data config and other). They are generated at the Magento 2 installation. app/etc/config.php file has shared configuration settings, while app/etc/env.php contains settings that are specific to the installation environment. As of the 2.2 release, the app/etc/config.php file is no longer an entry in the .gitignore file. This was done to facilitate pipeline deployment.
Below is the list of xml files inside the module:
- etc/config.xml – contains the default values of the options from Stores > Configuration in admin panel menu, as well as other options, like class names (for instance, <model>Amazon\Payment\Model\Method\AmazonLoginMethod</model>) and attributes (for example, <account backend_model=”Magento\Config\Model\Config\Backend\Encrypted” />).
- etc/di.xml and etc/<area>/di.xml – contains the configuration for dependency injection
- etc/events.xml and etc/<area>/events.xml – the list of the events and observers
- etc/<area>/routes.xml – routers’ list.
- etc/acl.xml – adds module resources into the resource tree, allowing to set up access for different users.
- etc/crontab.xml – adds and configures tasks for cron.
- etc/module.xml – declares module name and version, as well as its dependencies from other modules.
- etc/widget.xml – stores widget configuration.
- etc/indexer.xml – declares a new indexation type. There, view_id is specified, which denotes the views described in etc/mview.xml.
- etc/mview.xml – is used to track database changes for a certain entity.
- etc/webapi.xml – stores configurations for WEB API (REST/SOAP).
- etc/view.xml – stores product images’ values.
- etc/product_types.xml – describes product types in a store.
- etc/product_options.xml – describes the types of options that products can have and the classes that render options in the admin.
- etc/extension_attributes.xml – the ability to add custom attribute, introduced in Magento 2 version. The file describes the attribute and its type, which can be simple, or complex, or have the form of an interface.
- etc/catalog_attributes.xml – adds attributes to the groups. quote_item, wishlist_item, catalog_product, catalog_category, unassignable, used_in_autogeneration are the standard groups. To learn more, follow the link: https://www.atwix.com/magento-2/how-to-access-custom-catalog-attributes/
- etc/adminhtml/system.xml – can relate to admin section solely, adds Stores > Configuration settings and describes form sections and fields.
- etc/adminhtml/menu.xml – can relate to admin area solely, adding the menu option in the admin panel.
Magento loads different areas and files separately; it also has different file loaders for each file type.
In Magento 2, XML configuration files have areas: global, frontend and adminhtml, crontab, graphql, webapi_rest, webapi_soap. You can find a list of them at Magento\Framework\App\AreaList class, defined via di.xml. Certain xml files can be specified for each area separately and some may not. For instance, event.xml file can be specified for each area (global, frontend, adminhtml, etc.), while module.xml can be specified only for global.
If config file is located at the module etc directory, its values are located in the global area. To specify configuration area, place the config file into etc/<area> folder. This is a new concept, introduced in Magento 2. Previously, in the first version of Magento, the visibility area was defined by a separate branch in XML file. This introduction allows to load configurations for various visibility areas separately. If the same parameters are specified for global and non-global areas (for instance, frontend or adminhtml), they will be merged and loaded together. The parameters, specified in non-global area, or located in etc/<area> folder, have the priority.
Configuration upload is executed in three steps:
- System level configurations upload. Loading of the files, necessary for Magento 2 launch (like config.php).
- Global area configurations upload. Loading of the files, located in app/etc/ Magento 2 directory, such as di.xml, as well as files that relate to the global area and are directly located in modules’ etc/ folders.
- Specific areas configurations upload. Loading of the files, located at etc/adminhtml or etc/frontend folders.
Configuration files are merged according to their full xPaths. Specific attributes are defined in the $ idAttributes array as identifiers. When two files are merged, they contain all the nodes and values from the original files. The second XML file either adds or replaces the nodes of the first XML file.
Each XML file type is validated by the corresponding XSD validation scheme. All validation schemes are in etc / directories of the module. The most important schemes are located in the Magento framework-e (vendor / magento / framework); for example, XSD for acl.xml is located in vendor/magento/framework/Acl/etc/acl.xsd directory.
All Magento 2 configuration files are processed by the Magento\Framework\Config\ *classes. These classes load, combine, validate and process configurations, converting them into the needed format array. If one needs to modify the standard loading procedure, they must create a single or several classes that inherit the interfaces:
- \Magento\Framework\Config\DataInterface – allows to get configuration value and merge two configurations together. \Magento\Framework\Config\Data class realizes this interface and saves the configuration in cache in order to speed up the repeated website upload.
- \Magento\Framework\Config\ScopeInterface – allows to specify and get the current scope.
- \Magento\Framework\Config\FileResolverInterface – runs the config files search, returns the array or iterator. Keys are the absolute paths, the value is their content.
- \Magento\Framework\Config\ReaderInterface – reads configuration data. \Magento\Framework\Config\Reader\Filesystem is the standard reader.
- \Magento\Framework\Config\ConverterInterface – converts Merged DOM object into the array.
- \Magento\Framework\Config\SchemaLocatorInterface – specifies the path to validation schemes.
- \Magento\Framework\Config\ValidationStateInterface – defines whether DOM validation with schema is needed.
Magento 2 has two types of validation for XML configuration files: before and after the merge. The schemes can be the same or differ from each other.
One can create the following elements for a custom configuration file:
- XML file
- XSD schema
- Config PHP file
- Config reader
- Schema locator
- Converter
Not all those elements are necessary. Instead of creating them, one can use virtualType in di.xml and create only the following elements:
- XML file
- XSD schema
- Converter
To make an example of configuration file creation, let us examine product_types.xml file from Magento_Catalog module. This file allows each module to add a custom product type; afterwards, the files will get validated and merge.
- We begin with XSD file creation. Before the merger, Magento_Catalog uses product_types.xsd validation scheme and product_types_merged.xsd scheme for the merged XML file.
- Create the configuration PHP file for access to the file data; in our case, it will be Config.php. To provide access to the product_types.xml file data, it implements the Magento\Catalog\Model\ProductType\ConfigInterface interface and realizes all its methods.
- We should get reader class in Config.php in the constructor. In our case, it’s Magento\Catalog\Model\ProductType\Config\Reader. This is a small class with a certain $_idAttributes attribute. In $fileName variable at the constructor we define the XML file name.
- Magento\Catalog\Model\ProductType\Config\SchemaLocator implements two methods: getSchema and getPerFileSchema return the path to merged XSD and common XSD files. In the constructor, we define these paths in $_schema and $_perFileSchema attributes.
- Convertor class creation. In our case: Magento\Catalog\Model\ProductType\Config\Converter it implements \Magento\Framework\Config\ConverterInterface and realizes convert method that converts the merged DOM tree of nodes into the array.
1.4 Demonstrate how to use dependency injection
Describe Magento’s dependency injection approach and architecture. How are objects realized in Magento?
Dependency Injection is a design pattern based on the inversion of control principle. This pattern centers around relations between the objects and its dependencies. Instead of creating dependencies manually, all the necessary dependencies are passed into the object with the help of external container. This approach allows to avoid strong components coupling, for the object is not required to create custom dependencies. The dependencies container, in its turn, determines which implementations should be passed to the objects at their creation, depending on the necessary behavior or configuration.
Dependency inversion principle claims that high-level classes should use low level objects’ abstractions instead of working with them directly.
Object Manager
Magento 2 applies dependency injection for the functionality, which was offered by Mage class in Magento 1.
namespace Magento\Backend\Model\Menu; class Builder { public function __construct( Magento\Backend\Model\Menu\ItemFactory $menuItemFactory, Magento\Backend\Model\Menu $menu ) { $this->_itemFactory = $menuItemFactory; $this->_menu = $menu; } }
ObjectManager is used as dependencies container, configured with di.xml files. ObjectManager is responsible for:
- Objects’ creation in factories and proxys
- Return of one and the same object instance at the continuous requests*
- Selection of the suitable implementation at the interface query
- Automatic class creation depending on constructor arguments.
* If shared=false attribute is specified for a certain type in di.xml, then a new object will be created at the future requests.
Why is it important to have a centralized process creating object instances?
A centralized process creating object instances decreases code coherency and lowers the incompatibility risk in case the object realization changes.
Identify how to use DI configuration files for customizing Magento
Each module can have a global and an area-specific di.xml file. Area-specific di.xml files are recommended to be applied for dependencies configuration for presentation layer, while global file – for all the rest.
How can you override a native class, inject your class into another object, and use other techniques available in di.xml (such as virtualTypes)?
Abstraction-implementation mappings and class rewrites
Abstraction-implementation mappings and class rewrites are applied in case the constructor requests the object by its interface. ObjectManager utilizes this configuration to resolve which implementation should be used for the current area.
<config> <preference for="Magento\Core\Model\UrlInterface" type="Magento\Core\Model\Url" /> </config>
A similar approach can be used to substitute not only the interfaces, but the classes themselves.
<config> <preference for="Magento\Core\Model\Url" type="Vendor\Module\Model\NewUrl" /> </config>
Virtual Types
Virtual Type allows to modify any dependencies arguments and therefore modify class behavior without changing the operation of other classes that depend on the original.
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <virtualType name="moduleConfig" type="Magento\Core\Model\Config"> <arguments> <argument name="type" xsi:type="string">system</argument> </arguments> </virtualType> </config>
ObjectManager should never be called directly, because Magento Framework makes the call automatically. Factory or proxy classes, as well as unit texts or static and magic methods (wakeup, sleep) can be considered exceptions, for they are majorly generated by the framework automatically.
Magento 2 code contains direct ObjectManager calls, which exist only for backward compatibility and should not be used as an example.
Dependencies compilation
bin/magento setup:di:compile
Magento 2 applies a specific utilita for compiling dependencies of all classes. The utilita creates a file that contains the dependencies of all objects for ObjectManager, based on constructor arguments with the help of php reflection features. Such service classes as factories, proxies and plugins, are generated as well.
1.5 Demonstrate ability to use plugins
Demonstrate how to design complex solutions using the plugin’s life cycle. How do multiple plugins interact, and how can their execution order be controlled?
Magento 2 Plugin (Interceptor) is the class that allows to alter the behavior of other classes by calling the custom mode before, after or instead of conflict method call, allowing to minimize the probability of conflicts between various pieces of code that concern the same functionality.
Plugin Configuration
<module_dir>/etc/di.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <type name="{ObservedType}"> <plugin name="{PluginName}" type="{PluginClassName}" sortOrder="1" disabled="false"/> </type> </config>
, where:
{ObservedType} – class name, the method that must be altered
{PluginName} – plugin name
{PluginClassName} – plugin class name
sortOrder – plugin call order
disabled – ability to disable the plugin
Plugin Methods
Before Methods
Before methods allow to modify target class method arguments before the method is called.
Namespace Vendor\Module\Plugin;
class Plugin { public function beforeMethodName(\Vendor\Module\Model\TargetClass $subject, $arg1, $arg2, $arg3 = null) { return [$arg1, $arg2, $arg3]; } }
The name of the plugin method is concatenated ‘before’ and the method name, which arguments must be altered. The first argument of this method is the class, the method of which is called. The rest of the arguments correspond to the called methods arguments, including default values. It is also possible to use “…” token to get all the arguments (https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list.new). Example:
public function beforeMyMethod($subject, ...$args) { return $args; }
Before methods should return the arguments array, if they need to be overridden, or null, if there is no need for that.
After Methods
After methods allow to modify the result of the target method.
Namespace Vendor\Module\Plugin;
class Plugin { public function afterMethodName(\Vendor\Module\Model\TargetClass $subject, $result) { return $result; } }
The first argument, the same as before methods, is target class instance, the second is the returned value of the original method, while the third and further are the original method arguments.
Around Methods
Namespace Vendor\Module\Plugin;
class Plugin { public function aroundMethodName(\Vendor\Module\Model\TargetClass $subject, callable $proceed, $arg1, $arg2, $arg3) { $result = $proceed($arg1, $arg2, $arg3); return $result; } }
Around methods allow to execute the code before and after the target method in one place.
$proceed argument is PHP closure, that in its turn calls the target method.
Such methods allow to completely substitute the target method.
Plugin Sorting
Plugin sortOrder parameter allows to identify what the order plugin methods will be called in case multiple plugins are observing the same method.
Plugin1 | Plugin2 | Plugin3 | |
sort order | 10 | 20 | 30 |
before | beforeMethod() | beforeMethod() | beforeMethod() |
around | aroundMethod() | aroundMethod() | |
after | afterMethod() | afterMethod() | afterMethod() |
In this case, plugin processing is executed in the following order:
- Plugin1::beforeMethod()
- Plugin2::beforeMethod()
- Plugin2::aroundMethod() (Magento calls the first half until callable)
- Plugin3::beforeMethod()
- Plugin3::aroundMethod() (Magento calls the first half until callable)
- TargetClass::method()
- Plugin3::aroundMethod() (Magento calls the second half after callable)
- Plugin3::afterMethod()
- Plugin2::aroundMethod() (Magento calls the second half after callable)
- Plugin1::afterMethod()
- Plugin2::afterMethod()
How do you debug a plugin if it doesn’t work? Identify strengths and weaknesses of plugins
Magento 2 generates an Interceptor class for each class that has plugins. This class inherits the original plugins and contains the code that calls the plugins in the assigned order. Therefore, any plugin debug can be started with the Interceptor class.
Plugins enable to modify the application behavior without the need to modify or substitute the original classes, which allows to flexibly impact the application flow.
On the other hand, application of plugins, around methods in particular, complicates code readability and increases stack trace, as well as the non-functioning application, if the plugins are applied without due accuracy. If you do not call $proceed() in around plugin, the plugins whose sortOrder is larger than the current plugin will not be called. The original method will not be called as well.
What are the limitations of using plugins for customization? In which cases should plugins be avoided?
Compared to Magento 1, class rewrites plugins do not inherit the target class, allowing several plugins that modify one and the same method to have no conflicts with each other. However, due to the same reasons, plugins have certain limitations.
Plugins can not be used with:
- Final methods and classes
- Protected/private methods
- Static methods
- __construct methods
- Virtual types
- Objects that are instantiated before Magento\Framework\Interception is bootstrapped
- Objects that were initialized not with ObjectManager
The main purpose of plugins is to modify the certain method input, output or execution. In case the data is not modified (for instance, when order details are sent to the 3rd party ERP), then it is recommended to apply observers instead of plugins.
1.6 Configure event observers and scheduled jobs
Events are commonly used in applications to handle external actions or input. Each action is interpreted as an event.
Events are part of the Event-Observer pattern. This design pattern is characterized by objects (subjects) and their list of dependents (observers). It is a very common programming concept that works well to decouple the observed code from the observers. Observer is the class that implements Magento\Framework\Event\ObserverInterface interface.
According to https://devdocs.magento.com/guides/v2.3/coding-standards/technical-guidelines.html:
All values (including objects) passed to an event MUST NOT be modified in the event observer. Instead, plugins SHOULD BE used for modifying the input or output of a function.
Therefore, if there is a need to modify the input data, use plugins instead of events.
Demonstrate how to configure observers. How do you make your observer only be active on the frontend or backend?
In Magento 2 there is a special event manager class – Magento\Framework\Event\Manager that fires events. This class can be obtained through dependency injection by defining the dependency in your constructor.
Look for the mentioned notes in the code Magento 2:
$this->eventManager->dispatch(‘event_name’, ['myEventData' => $event_arguments]);
Event Observers in Magento 2 can be configured in a separate file events.xml. It should be created in <module_dir>/etc directory, if observer is associated with globally events, or in <module_dir>/etc/<area> (like <module_dir>/etc/frontend or <module_dir>/etc/adminhtml) if observer to only watch for events in specific area.
<?xml version="1.0" encoding="UTF-8"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> <event name="my_module_event"> <observer name="observer_name" instance="Namespace\Modulename\Observer\MyObserver" /> </event> </config>
In instance attribute we declare observer class name. This class has to implement Magento\Framework\Event\ObserverInterface::execute(Observer $observer) method. The $observer object has an $event object (available through $observer->getEvent()
), which contains the event’s parameters.
namespace Namespace\Modulename\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Event\Observer; class MyObserver implements ObserverInterface { public function __construct() { //You can use dependency injection } public function execute(Observer $observer) { ... } }
Demonstrate how to configure a scheduled job
To demonstrate how to configure a scheduled job, we create in the module a crontab.xml file with the similar content:
<?xml version="1.0" encoding="UTF-8"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd"> <group id="default"> <job name="my_module_cron_job" instance="Vendor\Module\Model\Cron" method="run"> <!-- Use schedule or config_path, not both --> <schedule>0 * * * *</schedule> <config_path>my_module/my_group/my_setting</config_path> </job> </group> </config>
Group element determines to which group cron jobs should be tied. Group is declared in cron_groups.xml file and contains group configurations. The events inside the group have a general queue, while several groups can be launched simultaneously. Example:
<?xml version="1.0" encoding="UTF-8"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/cron_groups.xsd"> <group id="default"> <schedule_generate_every>15</schedule_generate_every> <schedule_ahead_for>20</schedule_ahead_for> <schedule_lifetime>15</schedule_lifetime> <history_cleanup_every>10</history_cleanup_every> <history_success_lifetime>60</history_success_lifetime> <history_failure_lifetime>4320</history_failure_lifetime> <use_separate_process>0</use_separate_process> </group> </config>
Job element contains name (name of the job), instance (job class name) and method (job method name in the class) attributes. Also, job contains schedule element (http://www.nncron.ru/help/EN/working/cron-format.htm) or config_path (configuration path to the schedule value).
Which parameters are used in configuration, and how can configuration interact with server configuration?
Magento 2 stores database configuration in core_config_data table. This configuration can be overridden:
- In app/etc/config.php file
- In app/etc/env.php file
- In the area variables
To learn more, follow the link: https://devdocs.magento.com/guides/v2.3/config-guide/prod/config-reference-var-name.html
Identify the function and proper use of automatically available events, for example *_load_after, etc.
In Magento1 we can use of automatically available events. For example:
protected function _beforeSave() { ... Mage::dispatchEvent($this->_eventPrefix.'_save_before', $this->_getEventData()); ... } protected function _getEventData() { return array( 'data_object' => $this, $this->_eventObject => $this, ); }
This event is triggered before saving object, if it extends Mage_Core_Model_Abstract class. When we create a new class, which extends Mage_Core_Model_Abstract, we can declare $eventPrefix = “namespace_modulename” and use new event namespace_module_save_before.
We have the same ability in Magento2. In class Magento\Framework\Model\AbstractModel:
public function beforeSave() { ... $this->_eventManager->dispatch($this->_eventPrefix . '_save_before', $this->_getEventData()); …. }
In Magento1 and Magento 2 we have the same automatically available events.
Models:
[$eventPrefix]_load_before
[$eventPrefix]_load_after
[$eventPrefix]_save_before
[$eventPrefix]_save_after
[$eventPrefix]_save_commit_after
[$eventPrefix]_delete_before
[$eventPrefix]_delete_after
[$eventPrefix]_delete_commit_after
Controllers:
controller_action_predispatch_[ROUTE_NAME]
controller_action_predispatch_[FULL_ACTION_NAME]
controller_action_postdispatch_[ROUTE_NAME]
controller_action_postdispatch_[FULL_ACTION_NAME]
controller_action_layout_render_before_[FULL_ACTION_NAME]
1.7 Utilize the CLI
Describe the usage of bin/magento commands in the development cycle. Which commands are available? How are commands used in the development cycle?
Magento 2 allows to execute numerous operations using command line interface. It also contains a large number of commands that allow to flush the cache, change deployment mode or reindex the necessary index quickly. To apply the following commands, you should:
- Login into your Magento 2 server via SSH as Magento file system owner
$ ssh [email protected]
- Change directory to Magento 2 installation directory
$ cd /var/www/magento/
Afterward, we can use Magento CLI the following way:
$ bin/magento COMMAND
For example, list command will put out a list of available actions:
$ bin/magento list
Demonstrate an ability to create a deployment process
A standard Magento 2 deployment process includes the following steps and commands:
- Enable maintenance mode –
$ bin/magento maintenance:enable
- Perform database migrations –
$ bin/magento setup:upgrade
- Compile necessary code –
$ bin/magento setup:di:compile
- Publish static files –
$ bin/magento setup:static-content:deploy
- Disable maintenance mode –
$ bin/magento maintenance:disable
How does the application behave in different deployment modes, and how do these behaviors impact the deployment approach for PHP code, frontend assets, etc.?
Magento 2 can operate in three possible modes:
- Default – is enabled by default. It is aimed for neither development nor production use. This is an average mode between developer and production modes.
- At the request, static files are copied into pub/static directory and afterwards are put out from it.
- Exceptions are not put out at the screen and not recorded in log files
- Enabled automatic code compilation
- X-Magento-* HTTP response headers are hidden.
- Developer – the mode for development. Static files are generated on demand. The mode also increases the amount of debug information. Static files caching is also disabled and static files are put out with symlinks.
- Exception and backtraces are put out at the screen
- Automatic code compilation is enabled
- X-Magento-* HTTP response headers are enabled
- XML schema validation is enabled
- Slow application operation due to automatic code compilation on the fly.
- Production – is applied for working in production environment. Only in this mode, the maximum operation speed is available due to the required static files generation during the deployment, not at the request, like in other modes.
- Exceptions are recorded only in log files and not put out at the screen
- Static files are put out from cache (the files are generated in advance with
$ php bin/magento setup:static-content:deploy command
) - Automatic code compilation is disabled (it is executed in advance with
$ php bin/magento setup:di:compile command
) - X-Magento-* HTTP response headers are hidden.
To learn the current deployment mode, enter the command:
$ bin/magento deploy:mode:show
Changing Deployment Mode
To change the current deployment mode, enter the command:
$ bin/magento deploy:mode:set {mode} [-s|--skip-compilation]
where:
- {mode} is the required mode (default, developer or production)
- –skip-compilation – is an optional parameter that allows to skip code compilation after the deployment mode is changed.
When the deployment mode is changed, the var/cache folders will be cleared, except for generated/metadata, generated/code, var/view_preprocessed, pub/static files .htaccess. To avoid this, apply –skip-compilation flag.
1.8 Demonstrate the ability to manage the cache
Describe cache types and the tools used to manage caches. How do you add dynamic content to pages served from the full page cache?
Magento stores several cache types to prevent repeated data calculation or loading:
- config – Various XML configurations that were collected across modules and merged
- layout – Layout building instructions
- block_html – Page blocks HTML
- collections – Collection data files
- reflection – API interfaces reflection data
- db_ddl – Results of DDL queries, such as index list, foreing keys, columns
- compiled_config – Compilation configuration. It is used for caching by Magento\Framework\Interception\PluginList\PluginList class and works with the compiled di configuration only (generated/metadata/<area>.php).
- eav – Entity types declaration cache. Stores information about entity types and their attributes.
- customer_notification – Customer Notification. At the moment, it is applied to provide the customer with updated session.
- config_integration – stores information about php interfaces
- config_integration_api – stores the information about integrations (deprecated)
- full_page – stores full html code of the pages with http headings
- config_webservice – REST and SOAP configurations, generated WSDL file
- translate – applied for data caching for Magento 2 Translate library
Out-of-the-box Magento supports two FPC types: built-in and Varnish. Varnish is recommended to be installed and applied for production use. Before the page gets into FPC, all its personalized contents are deleted; this also applies for both built-in FPC and Varnish.
There are two methods to add dynamic contents for FPC:
First. For this purpose use in layout attribute cacheable=false in any block:
<referenceContainer name="content"> <block class="Magento\Checkout\Block\Onepage\Success" name="checkout.success" template="success.phtml" cacheable="false"/> <block class="Magento\Checkout\Block\Registration" name="checkout.registration" template="registration.phtml" cacheable="false"/> </referenceContainer>
Attribute cacheable=false makes page with this block uncacheable by FPC. But be careful with this parameter, because if this block is located in all pages, then all these pages will not be cached by FPC.
Second. You could use ajax for this purpose. Commonly, Magento has two types of content:
- Public. Public content is stored server side in your reverse proxy cache storage (e.g., file system, database, Redis, or Varnish) and is available to multiple customers. Examples of public content include header, footer, and category listing.
- Private. Private content is stored client side (e.g., browser) and is specific to an individual customer. Examples of private content include shopping cart, message and customer. The data is loaded from the server and saved to localStorage of user’s browser. In case the sections are invalidateв, they are loaded from the server repeatedly. This is realized by customer data JS module.
The strategy of deferring private content is perhaps best demonstrated by the following example. Starting in Magento_Theme::view/frontend/templates/html/header.phtml, we see the following:
<li class="greet welcome" data-bind="scope: 'customer'"> <!-- ko if: customer().fullname --> <span class="logged-in" data-bind="text: new String('<?= $block->escapeHtml(__('Welcome, %1!', '%1')) ?>').replace('%1', customer().fullname)"> </span> <!-- /ko --> <!-- ko ifnot: customer().fullname --> <span class="not-logged-in" data-bind='html:"<?= $block->escapeHtml($welcomeMessage) ?>"'></span> <?= $block->getBlockHtml('header.additional') ?> <!-- /ko --> </li>
Magento has different FPC for each group of customers, applying X-Magento-Vary Cookie for this. If the page with the specified URL and X-Magento-Vary Cookie is stored in FPC, then it is put out to the user, saving loading time. X-Magento-Vary Cookie value is generated using Magento\Framework\App\Http\Context class. In order to add a custom FPC division (for instance, according to age: < 18 и >= 18), one must call \Magento\Framework\App\Http\Context::setValue($name, $value, $default method.
Describe how to operate with cache clearing. How would you clean the cache?
There are three ways to clean the cache:
- From Admin
- Use bin/magento CLI
bin/magento cache:clean
bin/magento cache:flush
Execute thebin/magento setup:config:set --http-cache-hosts=SOME_HOST1,SOME_HOST2:PORT2
command beforehand in order to enable cache clearing in varnish. In this command, SOME_HOST1,SOME_HOST2:PORT2 are the addresses of varnish services, divided by a comma.
- Clean manually
- File cache: “rm -rf var/cache/*”, “rm -rf var/page_cache/*”
- Redis: “redis-cli flushall”
- Restart services (Varnish, Redis)
In which case would you refresh cache/flush cache storage?
When you clean cache, you do it by tags, and if in cache item is not associated with cache type tag, it will never be removed from storage.
When you flush cache, you remove all cache records in storage. Sometimes it’s more preferred than clean cache.
Describe how to clear the cache programmatically
To clean cache for specific model object, you can use:
\Magento\Framework\Event\ManagerInterface->dispatch(‘clean_cache_by_tags’, [‘object’ => $model]);
To clean entire cache type, you can use:
\Magento\Framework\App\Cache\TypeListInterface->cleanType($typeCode)
To invalidate entire cache type, you can use:
\Magento\Framework\App\Cache\TypeListInterface->invalidate($typeCode)
The cache tags are generated at block level, with each block class implementing the IdentityInterface which means they must implement a getIdentities method, which must return a unique identifier. For example:
... namespace Magento\Cms\Block; ... use Magento\Framework\View\Element\AbstractBlock; use Magento\Framework\DataObject\IdentityInterface; ... class Page extends AbstractBlock implements IdentityInterface { ... public function getIdentities() { return [\Magento\Cms\Model\Page::CACHE_TAG . '_' . $this->getPage()->getId()]; } ... }
When the front controller response is ready, the FPC combines all the block tags from the layout, and then adds them to the response in a X-Magento-Tags custom HTTP header. The different FPC options then handle the header differently. Varnish stores the header along with the rest of the page when it is cached, so no additional work is required. The built-in option however needs some additional code to pull the tags back out of the X-Magento-Tags header so that they can be associated with the response when it is stored in the configured storage (e.g. Redis).
What mechanisms are available for clearing all or part of the cache?
You can clean cache from admin panel. System->Cache Management
In this page you can clean/enable/disable cache by cache types or full cache. Also you can clean cache from console:
bin/magento cache:clean
– clean cache,
bin/magento cache:clean <cache_type>
– clean cache only for <cache_type>
bin/magento cache:status
– you could see statuses and types of cache
bin/magento cache:enable <cache_type>
– enable cache
bin/magento cache:flush
– flush cache
Let’s connect
Have a project? Fill out the form and we’ll reach out to you. Get a free proposal now.