Run module unit test

run all

../../phpunit/phpunit/phpunit –colors -c ‘../../../dev/tests/unit/phpunit.xml.dist’ ./Test/Unit

copied dev/tests/unit/phpunit.xml.dist to dev/tests/unit/phpunit.xml and used the following configuration:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
         colors="true"
         bootstrap="./framework/bootstrap.php"
        >
    <testsuite name="Magento Unit Tests">
        <directory suffix="Test.php">../../../vendor/vendorname/m2-module-name/Test/Unit</directory>
    </testsuite>
    <php>
        <ini name="date.timezone" value="America/Los_Angeles"/>
        <ini name="xdebug.max_nesting_level" value="200"/>
    </php>
</phpunit>

Then I ran the phpunit command:

vendor/bin/phpunit -c dev/tests/unit/phpunit.xml --coverage-html ./report vendor/vendorname/m2-module-name/

Increase grunt compile performance to 6 second

http://devdocs.magento.com/guides/v2.0/frontend-dev-guide/css-topics/css_debug.html

If you have a problem with slow response for grunt to manage that we changed somethings, here is a solution.

First of all we will stop rely on grunt watch itself and we will bring to work PHPStorm instead which is much faster in that case.

  1. Stop using “grunt watch” command, exit if it’s working.
  2. In PHPStorm go to “PhpStorm -> Preferences -> Tools -> File Watchers”
  3. Click on plus icon and add <custom>
  4. “Program” path is correct when you have your grunt installed globally so please do that or change to your grunt path.
  5. That same for for “Working directory”.
  6. Select options like on image below

 

5. Next to “Scope” please click “…”, select your theme folder if you have a module or folder in frontend directory and click “Include Recursively”, then click OK.

6. Now you can Apply, click OK and go back to editor.

7. Open your Gruntfile.js

8. Add grunt task to your default function like on the example below and change “sova” to your theme name.

default: function () {

    grunt.task.run(‘less:sova’);

},

9. Now when you will change anything in your theme, you will see console and your files will be compiled in something about 5-6second instead of 15-25.

Public Magento 2 Interfaces

  • Products
  • Product Attributes
  • Product Attribute Types
  • Product Attribute Media Gallery
  • Product Links
  • Categories
  • Category Attributes
  • Category Product Links
  • Directories
  • Files

It’s SAFE and highly encouraged to use these classes in your work injected to your own classes.

All developers can contribute to this page and it’s highly appreciated. When adding new items, please make sure your description is clear and consistent, it will help other developers in their work immensely and save hours of investigation.

Please be discrete; this page must not contain arbitrary “useful” classes and interfaces, only those which fit the following note.

This section mentions only STANDARD Magento 2 interfaces, marked with @api annotation (otherwise called Service Contracts), or classes PREGENERATED by Magento internally.

Products

Interface

Description

\Magento\Catalog\Api\Data\ProductInterface

A product entity interface. Represents the product model. You should NEVER instantiate implementations of this interface (for example, \Magento\Catalog\Model\Product) directly. You should always use the ProductFactory::create() method.

\Magento\Catalog\Api\ProductRepositoryInterface

Products repository is responsible for implementing CRUD and also to list a collection of products. Note that by default SKU is used to get an item, use getById() to fetch an item by the internal ID.

\Magento\Catalog\Api\ProductManagementInterface

An instance of this interface would have a product collection injected. The only method, getCount($status), would return a number of products filtered by a specific status, or not filtered at all. It’s impossible to modify a filter with something else directly.

\Magento\Catalog\Model\ProductFactory

This class doesn’t exist in the codebase, it’s being generated during code generation. Generates instances of \Magento\Catalog\Model\Product on demand.

\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory

This class doesn’t exist in the codebase, it’s being generated during code generation. A product collection factory that is used to instantiate concrete product collection instances.

Please note that product collection is not considered standard, it doesn’t have a service contract defined. In common cases, if you need to work with a list of products, use \Magento\Catalog\Api\ProductRepositoryInterface::getList(), otherwise instantiate product collection using this factory injected into your service class.

Product Attributes

Interface

Description

\Magento\Catalog\Api\Data\ProductAttributeInterface

A product attribute interface. Represents the product attribute model. You should NEVER instantiate implementations of this interface.

\Magento\Catalog\Api\ProductAttributeRepositoryInterface

Product attribute repository is responsible for implementing CRUD and also to list a collection of product attributes.

\Magento\Catalog\Api\ProductAttributeManagementInterface

This interface implements getting a list of attributes from an attribute set, assigning and un-assigning the attribute to/from specific attribute set.

Product Attribute Types

Interface

Description

\Magento\Catalog\Api\Data\ProductAttributeTypeInterface

A product attribute type interface.

\Magento\Catalog\Api\ProductAttributeTypesListInterface

Implements fetching a list of product attribute types. 

Product Attribute Media Gallery

Interface

Description

\Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface

Implements a media gallery entry for a gallery attribute. 

\Magento\Catalog\Api\ProductAttributeMediaGalleryManagementInterface

A media gallery entries management interface, implements methods to create entries, to fetch, update and remove them, as well as getting a list of media gallery entries by specific product SKU.

Product Links

Interface

Description

 

 

Categories

Interface

Description

\Magento\Catalog\Api\Data\CategoryInterface

A category entity interface. Represents the category model. You should NEVER instantiate implementations of this interface (for example, \Magento\Catalog\Model\Category) directly. You should always use the CategoryFactory::create() method.

\Magento\Catalog\Api\CategoryRepositoryInterface

Categories repository is responsible for implementing CRUD and also to list a collection of categories. It alternatively provides a way to delete by a category object, or by category ID.

\Magento\Catalog\Api\CategoryManagementInterface

An instance of this interface would have a category collection injected. There are three methods implemented:

  • getCount() — returns a number of categories with parentId > 0
  • getTree([$rootCategoryId], [$depth]) — builds a subtree of categories for specific parent and specific depth (if provided)
  • move($categoryId, $parentId, [$afterId]) — moves the category across the category tree. If $afterId is not specified, doesn’t rearrange the order.

\Magento\Catalog\Model\CategoryFactory

This class doesn’t exist in the codebase, it’s being generated during code generation. Generates instances of \Magento\Catalog\Model\Category on demand.

Category Attributes

Interface

Description

\Magento\Catalog\Api\Data\CategoryAttributeInterface

A category attribute interface. Represents the category attribute model. You should NEVER instantiate implementations of this interface.

\Magento\Catalog\Api\CategoryAttributeRepositoryInterface

Category attribute repository is responsible for getting an instance of an attribute and also to get a collection of category attributes. It does not provide full CRUD interface.

Category Product Links

Interface

Description

 

 

Test Quiz

Please DO NOT renumber any of the existing questions and don’t swap answers between themselves, the cheat sheet that is kept separately must refer properly to the numbers and letters here.

 

    1. Which of the following statements are true?
      1. Maintenance mode and standard mode can be active at the same time
      2. Production mode makes it impossible to check errors
      3. Production mode uses pub directory for web-accessible files
      4. There must be error_reporting(E_ALL) present in developer mode
    2. In which Magento modes static files materialization is enabled?
      1. developer
      2. default
      3. production
      4. maintenance
    3. Administrator can control which IP addresses will still have access to the instance during maintenance mode by…
      1. editing .htaccess
      2. modifying System Configuration
      3. using php bin/magento maintenance:allow-ips
      4. editing var/.maintenance.ip file
    4. In order to specify that your module depends on other modules, you need…
      1. mention them in <sequence> node in the <moduleDir>/etc/module.xml comma-separated
      2. mention them in <dependency> node in the <moduleDir>/etc/module.xml as a list of module subnodes
      3. mention them in <sequence> node in the <moduleDir>/etc/module.xml as a list of dependency subnodes
      4. mention them in <sequence> node in the <moduleDir>/etc/module.xml as a list of module subnodes and add dependencies to module’s composer.json
      5. mention them in <sequence> node in the etc/config.php as array elements
    5. Can there be several modules responsible for the same feature in your Magento application?
      1. Yes, there is no limitation
      2. Absolutely not
      3. Only if you declare all modules in the same namespace
    6. What dependencies should be declared as module dependencies?
      1. Only modules current module depends on
      2. Themes
      3. Language packs
      4. All of the above
    7. What are possible locations for the module directory for a module Vaimo_FancyModule?
      1. app/code/Vaimo/FancyModule
      2. app/code/Vaimo_FancyModule
      3. vendor/module-vaimo-fancymodule/Vaimo/FancyModule
      4. vendor/module-vaimo-fancymodule
    8. What is the minimal required content of a module directory?
      1. Model, Controller, etc/module.xml, config.xml
      2. etc/module.xml, registration.php
      3. etc/model.xml, Model
      4. registration.php
    9. Where Magento stores credentials for the database, cache, session and encryption key?
      1. app/etc/local.xml
      2. app/etc/config.xml
      3. app/etc/config.php
      4. app/etc/env.php
    10. What’s the sequence of merging configuration files across the system?
      1. Primary application config, global config files in every module, area-specific config files in every module, config values from database
      2. Primary application config, config values from database, for every module: { global config files, area-specific config files }
      3. Primary application config, for every module: { global config files, area-specific config files }, config values from database
      4. Config values from database, application config, global config files in every module, area-specific config files in every module
    11. You need to instantiate a product. What do you do?
      1. Configure \Magento\Catalog\Model\Product object to be injected into your class
      2. Access Object Manager and perform $om->get(‘Magento\Catalog\Model\Product‘)
      3. Inject the \Magento\Catalog\Api\ProductRepositoryInterface product repository, then perform $productRepository->get($sku)
      4. Access Object Manager and perform $om->create(‘Magento\Catalog\Model\Product‘)
    12. The third party module contains the following code: 
  • 1
    2
    3
    4
    5
    6
  • protected function getPriceInfo()
    {
    $priceModel = new \MageSuper\Price\Model\PriceModel($this);
     
    return $priceModel->calculate(true);
    }

  • You are told to override \MageSuper\Price\Model\PriceModel in order to change the calculation formula. Your action:

      1. You’re extending \MyCompany\Price\Model\PriceModel from \MageSuper\Price\Model\PriceModel and overwriting calculate() method
      2. You’re extending \MyCompany\Price\Model\PriceModel from \MageSuper\Price\Model\PriceModel and creating a plugin aroundCalculate() to modify the behavior
      3. You’re extending \MyCompany\Price\Model\PriceModel from \MageSuper\Price\Model\PriceModel and declaring preference to prefer your class instead of the original one in di.xml, then you override calculate() in your class
      4. You refuse the job, because you cannot do what you are told
    1. An action controller you’re working on requires a product collection. In order to get an instance of a product collection, you
      1. Configure your controller to be injected with a product collection with shared=”false”
      2. Fetch an instance of Object Manager, then do $om->get(‘\Magento\Catalog\Api\ProductRepositoryInterface’)->getList()
      3. Configure your controller to be injected with a product collection
      4. Fetch an instance of product collection from Registry

Practice Tasks

  1. Create a MINIMAL module. Describe what is the minimal code and declarations you need to add to accomplish that?
  2. Create a module and make it dependent on the module created in the previous task. then disable the first module and describe that will happen.
  3. For the class \Magento\Catalog\Model\Product, it’s getPrice() method:
    – create a plugin that will modify price
    – create a preference that will substitute the core class with your own
    – make sure that your plugin still works. 
  4. Create a custom module and do the following:
    – create an observer to the event “controller_action_predispatch”
    – get a URL from the request object and log it.
  5. Find a place in the code where output is flushed to the browser ($response->send()). Create an extension that captures the output, and logs the URL, the controller action name, and the content of the tag <title> in the rendered page.
  6. Create an extension that logs a list of all available routers to a log file. Modify it to render a page that shows that list.
  7. Create an extension with a custom router that understands URLs like /frontname-actionpath-action and converts them into /frontname/actionpath/action.
  8. Modify Magento so that “not found” state would forward to the home page.
  9. Modify the frontend catalog product view controller action so that each product has “EXCLUSIVE!” text as a prefix for the product name.
  10. Create an admin panel controller that allows access only if a GET parameter “secret” is equal to “yes”
  11. Create a block extended from \Magento\Framework\View\Element\AbstractBlock. Render it in a new controller action.
  12. Create and render a text block in a new controller.
  13. Customize the product view description block in order to modify the product description and have “Description:” being output before each description.
  14. Define which template is used in \Magento\Catalog\Block\Product\View\Attributes and override it in your extension.
  15. Create an additional content in the top of the content of every page (block content.top) with a custom template. Pass a background color as a block argument in the layout XML, and use that value in the template for rendering.
    Change the background color to a different one only for product detail pages.
    On category pages, move the block to the bottom of the left column.
  16. Create a custom controller action. For that page, set a one column layout, and set a title of the page using layout XML. For this page, remove the block created in the previous task. Add the link to this page to the top links.
  17. Create a custom page on the frontend that lists all store views and associated with them root categories.
    Use a Store collection to fetch all store views, Category collection filtered by specific root categories fetched from the stores.
  18. Create a custom module that adds logging of every product save, including the product ID, SKU and the data that has been changed
  19. Create a DB table with your custom module using install schema logic:
    – create a DB table using DDL
    – execute setup using console tools
    – check the module version within setup_module DB table
  20. Upgrade the DB table created in the previous task:
    – create an upgrade schema class
    – add an additional column to the table using DDL adapter methods
    – increase the module’s version
    – run the appropriate console command
    – verify that the field was added and the module version has increased in the setup_module DB table
  21. Add a data fixture to the data table created and upgraded in the two previous tasks:
  22. – make sure you have a model/resource model in your module that corresponds the table data structure
  23. – create an upgrade data class
  24. – increase the module’s version
  25. – run the appropriate console command
  26. – verify that the fixture data was added on the module upgrade and the module version has increased in the setup_module DB table
  27. Create a custom module that adds a new attribute to the product called “subtitle
  28. – add it to the default attribute set
  29. – give it a varchar type
  30. – make sure that it appears on the product edit page in admin panel and saves successfully
  31. – make it visible on the product view frontend page.
  32. Write an upgrade class for the module created in the previous task that adds another multiselect attribute to the product
  33. – create the attribute called  “alternatives
  34. – set a proper backend model that allows to handle an array of options in the admin panel
  35. – add several predefined options to the attribute
  36. – make it visible on the product view frontend page.
  37. Customize the frontend rendering for the attribute created in the previous task:
  38. – create a custom frontend model
  39. – make it that the attribute is being rendered as an HTML list rather than a comma-separated list
  40. – randomize the output.
  41. Create a custom select attribute for the customer:
  42. – use a data upgrade class for creating a custom attribute
  43. – name the attribute “priority” and make it of “select” frontend input type
  44. – assign a custom source model
  45. – implement a custom source model that allows to select a number from 1 to 10
  46. – test that the attribute works as expected

Module 4. Working with Database. EAV Explained

  • Database Overview
  • Detailed Workflow
    • $model->load()
    • $model->_beforeLoad()
    • $resourceModel->load()
    • $model->_afterLoad()
    • $model->afterLoad()
    • $model->save()
    • $resourceModel->save()
    • $model->isDeleted([$flag])
    • $model->validateBeforeSave()
    • $model->beforeSave()
    • $model->isSaveAllowed()
    • $model->afterSave()
    • $model->afterCommitCallback()
    • $model->delete()
    • $model->beforeDelete()
    • $model->afterDelete()
    • $model->afterDeleteCommit()
  • Setup Scripts and Resources
  • EAV Concepts
  • EAV Specifics in Load and Save
  • Attribute Management
    • $eavSetup->addAttribute($entityTypeId, $code, $attr)
    • $eavSetup->updateAttribute($entityTypeId, $id, $field, $value, $sortOrder)

Database Overview

Database layer in Magento 2 is very similar to one Magento 1.x had.

As model is just an object representation of a data entity, it’s not necessarily a part of the data layer. To make it storable, a developer should extend a model from \Magento\Framework\Model\AbstractModel or one of its descendants. That will provide basic functionality to handle data model fields, primary key field, as well as a mechanism to declare a resource model. There is no need anymore to define resource models in config, an appropriate resource model is simply initiated in the model’s _construct() protected method. Thus, developers should write something like this:

 /**

 * Initialize resource

 *

 * @return void

 */

protected function _construct()

{

    $this->_init(‘Magento\Catalog\Model\ResourceModel\Product\Link’);

}

Similarly as in Magento 1.x, \Magento\Framework\Model\AbstractModel provides $this->_eventPrefix / $this->_eventObject mechanism that is used to fire corresponding CRUD-related events. It also provides a domain-level validation (as opposed to the data structure validation, performed in resource model.

 

Below there is a diagram showing relationship between different elements of the data model layer, resource model and resource collection.

In Magento 2, there is exactly one resource model and one collection defined for every model.

It’s not a data model responsibility to know how to persist itself, it only goes as far as declare a resource model that is responsible for performing CRUD operations over the data stored in the model. Even though there are load(), save() and delete() methods, they are only functional through the declared resource model. As in Magento 1.x, when any of CRUD methods is called, the data model passes itself as a data container and delegates CRUD operations to the resource model along, which is using low level commands of resource adapter to perform them.

 

Therefore, the business logic is decoupled from the storage layer logic, and the storage schema is decoupled from the database driver implementation. 

All resource models that work with the DB storage layer are extended from \Magento\Framework\Model\ResourceModel\Db\AbstractDb. Resource models are responsible for the following:

  • processing CRUD operations (load/save/delete)
  • implementing all necessary additional logic that is needed to manipulate the storage data for the model
  • mapping object properties to the database fields and vice versa.

Unlike Magento 1.x, Magento 2 resource models provide a single entry point to access the storage adapter, getConnection(). Magento 2 Enterprise provides a module ResourceConnection that implements features that allow to utilize DB master/slave mode for better load balancing, performance and security.

Resource collection represents a list of model instances of specific type. All resource collections are extended from \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection and also can perform their internal logic through the resource adapter. Resource collections provide the following:

  • implementing EncapsulatedCollection pattern
  • implementing IterationAggregate, that allows to iterate the collection
  • representing entity groups
  • containing logic for group operations, such as filtering, sorting, paging.

Resource adapter used in all DB resource models and DB collections implements \Magento\Framework\DB\Adapter\AdapterInterface. By default, it’s \Magento\Framework\DB\Adapter\Pdo\Mysql (it also extends Zend_Db_Adapter_Pdo_Mysql).

 

There are a number of Model Type interfaces declared across Magento. Model Type interfaces make it easier for developers to work with the application without knowing low level details. Type interfaces define specific setters and getters, as well as allow using “magic” getters and setters implemented in \Magento\Framework\DataObject.

Detailed Workflow

$model->load()

  • requires a first argument as an ID to retrieve a record and map it to the model instance
  • a loaded instance is always returned, if loading fails, an exception is being thrown
  • an optional second attribute allows to specify the name of the field that should be used as fetching ID when loading

Categories and products, as EAV entities, can be loaded by an alternative attribute using loadByAttribute() method.

Anatomy of the load() method:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

/**

 * Load object data

 *

 * @param integer $modelId

 * @param null|string $field

 * @return $this

 */

public function load($modelId, $field = null)

{

    $this->_beforeLoad($modelId, $field);

    $this->_getResource()->load($this, $modelId, $field);

    $this->_afterLoad();

    $this->setOrigData();

    $this->_hasDataChanges = false;

    $this->updateStoredData();

    return $this;

}

$model->_beforeLoad()

  • dispatches model_load_before
  • dispatches $model->_eventPrefix . ‘_load_before’
  • possible use case: checking ACL to decide if reading from DB is appropriate
  • this WILL not be dispatched when loading models in a collection

$resourceModel->load()

  • dispatches load() request to the data mapper layer
  • $resourceModel->_getLoadSelect() uses ID and selection criterion

$model->_afterLoad()

  • dispatches model_load_after
  • dispatches $model->_eventPrefix . ‘_load_after’
  • possible use case: joining two domain items; for example, products and inventory objects
  • this WILL not be dispatched when loading models in a collection

$model->afterLoad()

  • this public method is provided for using in collections that load data outside of the $model->load() workflow. This is done for performance optimization.

$model->save()

  • Inserts or updates a database record mapped with the model properties
  • Determines the presence of a record by checking on an existence of a primary key
  • Composite key entities are best handled by adding an auto increment primary key

$resourceModel->save()

  • dispatches save() request to the data mapper layer

$model->isDeleted([$flag])

  • checks if an instance is marked for deletion, sets a deletion flag if specified

$model->validateBeforeSave()

  • initiates a validator factory to validate all validation rules that the model contains
  • is used in resource model before save

$model->beforeSave()

  • dispatches model_save_before
  • dispatches $model->_eventPrefix . ‘_save_before’
  • possible use case: can be used for business logic check of ACL check

$model->isSaveAllowed()

  • checks $model->_dataSaveAllowed flag
  • it can be helpful to control the saving process in case, for example, data validation failed

$model->afterSave()

  • dispatches model_save_after
  • dispatches $model->_eventPrefix . ‘_save_after’
  • dispatches clean_cache_by_tags
  • possible use case: can be used for post-processing logic

$model->afterCommitCallback()

  • dispatches model_save_commit_after
  • dispatches $model->_eventPrefix . ‘_save_commit_after’
  • is used for further operations after data has been committed
  • is called via call_user_func() in the resource model 
  • possible use case: can be used for post-processing logic

$model->delete()

  • is used for deleting database records that represent model entities
  • deletes a record based on the value of the primary key
  • dispatches delete() request to the data mapper layer

$model->beforeDelete()

  • dispatches model_delete_before
  • dispatches $model->_eventPrefix . ‘_delete_before’
  • existing events handlers are used to check if deletion is allowed for the current area, and to invalidate the object-related cache
  • possible use cases: can be used for various business logic

$model->afterDelete()

  • dispatches model_delete_after
  • dispatches $model->_eventPrefix . ‘_delete_after’
  • dispatches clean_cache_by_tags
  • possible use cases: can be used for various business logic

$model->afterDeleteCommit()

  • dispatches model_delete_commit_after
  • dispatches $model->_eventPrefix . ‘_delete_commit_after’
  • is used for further operations after delete has been committed
  • possible use case: can be used for various business logic, including post-delete cleanup

Setup Scripts and Resources

Setup scripts is a way to install or upgrade schema or predefined stored data when a module is installed afresh, or a new version of the module is updated.

Module version is set in the module’s module.xml file:

1

2

3

4

5

6

 <module name=“Magento_Cms” setup_version=“2.0.0”>

    <sequence>

        <module name=“Magento_Store”/>

        <module name=“Magento_Theme”/>

    </sequence>

</module>

Processed module versions are registered in the setup_module table:

In order to install (or upgrade) a module, the following commands must be ran:

  • php bin/magento cache:flush
  • php bin/magento setup:upgrade
  • php bin/magento module:enable <Your_ModuleName>

Then check if the module is present in the System Configuration under Advanced/Advanced.

Note that schema_version and data_version are always same unless an error occurred during running the setup script.

In order to install a new module, there should be install schema class created:

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

namespace Magento\Cms\Setup;

 

use Magento\Framework\Setup\InstallSchemaInterface;

use Magento\Framework\Setup\ModuleContextInterface;

use Magento\Framework\Setup\SchemaSetupInterface;

use Magento\Framework\DB\Adapter\AdapterInterface;

 

/**

 * @codeCoverageIgnore

 */

class InstallSchema implements InstallSchemaInterface

{

    /**

     * {@inheritdoc}

     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)

     */

    public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)

    {

        $installer = $setup;

        $installer->startSetup();

        $connection = $installer->getConnection();

 

        // …

 

        $installer->endSetup();

    }

}

The syntax for DDL commands used for manipulating DB schema are the same as in Magento 1.x.

Once the module is successfully installed, and the both versions are updated in the setup_module table, the InstallSchema::install() method will never be run again (short of deleting the module’s record in the setup_module table). Instead, an upgrade class should be created. Upgrade schema class is very similar to the install schema class with a few key differences.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

namespace Magento\Catalog\Setup;

 

use Magento\Framework\Setup\UpgradeSchemaInterface;

use Magento\Framework\Setup\ModuleContextInterface;

use Magento\Framework\Setup\SchemaSetupInterface;

use Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\Media;

use Magento\Catalog\Model\Product\Attribute\Backend\Media\ImageEntryConverter;

 

/**

 * Upgrade the Catalog module DB scheme

 */

class UpgradeSchema implements UpgradeSchemaInterface

{

    public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context)

    {

        $setup->startSetup();

 

        / …

 

        $setup->endSetup();

    }

}

Install/upgrade data classes are for preparing, presetting and persisting model-level data at the moment the module is installed or upgraded. 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

namespace Magento\Catalog\Setup;

 

use Magento\Framework\Setup\InstallDataInterface;

use Magento\Framework\Setup\ModuleContextInterface;

use Magento\Framework\Setup\ModuleDataSetupInterface;

 

/**

 * @codeCoverageIgnore

 */

class InstallData implements InstallDataInterface

{

    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)

    {

        $setup->startSetup();

 

        // …

 

        $setup->endSetup();

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

namespace Magento\Catalog\Setup;

 

use Magento\Framework\Setup\UpgradeDataInterface;

use Magento\Framework\Setup\ModuleContextInterface;

use Magento\Framework\Setup\ModuleDataSetupInterface;

 

/**

 * Upgrade Data script

 * @codeCoverageIgnore

 */

class UpgradeData implements UpgradeDataInterface

{

    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)

    {

        $setup->startSetup();

 

 

        // …

 

        $setup->endSetup();

    }

}

Setup process provides a setup context to every install or upgrade script. The context object contains information necessary for the setup process.

It’s mandatory for schema setup classes and is considered a best practice with data setup classes to start your install/upgrade logic with $setup->startSetup() and end it with $setup->endSetup().

Even though it’s still possible to command setup logic to run SQL clauses directly, it’s highly recommended to avoid this in favor using DDL syntax to make the code unified and be in RDBMS-independent way.

The workflow Magento 2 uses for setting installs/upgrades, includes the following commands:

  • php bin/magento setup:db:status
  • php bin/magento setup:upgrade
  • php bin/magento setup:db-schema:upgrade
  • php bin/magento setup:db-data:upgrade

EAV Concepts

EAV in Magento is used to provide flexibility in storing variable amount of attributes to different entities, maintain different types of attributes and store attribute values across different stores. It also allows developers to encapsulate attribute-related business logic and manage attributes by adding new and removing unused ones.

EAV storage is separated into meta information and content parts.

Meta Information contains:

  • Entity types
  • Attributes per entity type
  • Attribute sets and groups

Content part contains:

  • Entity records
  • Attribute values

Major difference between a classic EAV and Magento EAV implementation:

  • In Magento, core EAV tables are prefixed with “eav_
  • A backend type is assigned to each attribute (examples: varchar, int, decimal, text…)
  • EAV tables store entity data in separate tables. There entity-specific tables (catalog_category_entity, catalog_product_entity, customer_entity, etc.) and common eav_entity table that contains meta data
  • Special unique attributes with global scope are integrated into the entity-specific tables and are called static attributes, they have a static backend type
  • Attribute value tables are also split by entity_type and backend type
  • Certain information is duplicated between tables for performance reason (for example, entity_type_id is included into three different tables)

In Magento, it’s also possible to group attributes into groups and sets. While there can be only one attribute set assigned to a specific entity type, the groups are used only for clarity, so that developers could group attributes for better end user perception.

There can be different groups in each attribute set, but there is always a default group with a code “general“.

As it was mentioned before, the storage of attribute values is distributed across several DB tables. For example, for the entity type catalog_product:

Table name

Description

catalog_product_entity

The main entity table, among other things contains values for static attributes

catalog_product_entity_int

Stores integer values for attributes

catalog_product_entity_decimal

Stores decimal value types for attributes

catalog_product_entity_datetime

Stores attribute values of timestamp type

catalog_product_entity_text

Stores values for attributes with big string values

catalog_product_entity_varchar

Stores values for one-line text fields

References to the models related to each attribute are stored in the eav_attribute table and correspond the following:

Field

Description

backend_model

A name of PHP class used to process the attribute data before and after CRUD operations

source_model

A name of PHP class used for providing options for select and multiselect input type attributes

frontend_model

A name of PHP class used for formatting attribute value before display

Comparing to a flat table model structure processing, EAV makes it more complex. Both backend and source models are playing significant role in pre- and post-CRUD operations in EAV models. When displaying attributes for EAV models like catalog_product, catalog_category and customer, the attribute set model and group model are used. The attribute set model is also used when loading all the attributes associated to a specific product for a frontend detail view.

EAV Specifics in Load and Save

There are significant differences in how EAV model CRUD mechanisms work. As the EAV model is still extended from \Magento\Framework\Model\AbstractModel, the resource collection it uses should be extended from \Magento\Eav\Model\Entity\AbstractEntity (let the class name not fool you, it’s a special case of resource model, not data model).

In addition to the standard arsenal of resource model methods, EAV resource model implements additional methods that makes working with attributes easier:

  • getAttribute() — allows to get an attribute instance by a code
  • saveAttribute() — allows to save an attribute value to the EAV entity without going through the whole model saving process. You have to set the attribute value to the entity instance first.
  • unsetAttributes() — allows to unset specified attributes from the entity model
  • getEntityTable() — implemented in contrast to getMainTable() of flat table resource models

EAV collection also has additional distinct methods which influence the load process  that are worth mentioning:

  • addAttributeToSelect()
  • addAttributeToFilter()
  • joinAttribute()

They work same way as in Magento 1.x.

Unlike Magento 1.x, where attribute values were fetched from EAV tables using complex JOINs, in Magento 2 UNION construct is used that is much faster. It applies for both the attributes loaded for the collection, and for the process of loading a single entity.

Attribute Management

Below are the most important field within an attribute record with description. Note that some of those fields are stored in the main attribute table, eav_attribute, some will be stored in additional attribute table.

Field

Description

attribute_id

Unique attribute ID

entity_type_id

Entity type ID to associate the attribute with a specific entity type

attribute_code

Unique human-readable attribute code, must be unique within same entity type

attribute_model

Optional alternative model to use. It defaults to \Magento\Eav\Model\Entity\Attribute if not specified.

backend_model

Optional alternative backend model. It defaults to \Magento\Eav\Model\Entity\Attribute\Backend\DefaultBackend if not specified.

backend_type

Data type of the attribute. It’s either “static“, or corresponds to the postfilx of an attribute value table specific for each entity type

backend_table

Optional name of the attribute value table. If not specified, the name is formed as <entity_type_code>_<backend_type>.

frontend_model

Optional alternative frontend model. It defaults to \Magento\Eav\Model\Entity\Attribute\Frontend\DefaultFrontend if not specified.

frontend_input

Input type for the attribute in case the admin HTML form is being rendered automatically

frontend_label

Default label in case the admin HTML form is being rendered automatically

frontend_class

Optional CSS class name which will be added to the admin HTML input element for the attribute in case the admin HTML form is being rendered automatically. Useful for JS validation.

source_model

Optional alternative source model. Should only be specified for the attributes with select and multiselect frontend input type. Each source model must be extended from \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource and implement \Magento\Eav\Model\Entity\Attribute\Source\SourceInterface.

is_required

Enabled JS validation in case the admin HTML form is being rendered automatically. It is also evaluated during the DataFlow and ImportExport processes.

default_value

Optional default value, it is being displayed by the frontend model if the attribute doesn’t have a value.

When an access to the meta info of the EAV system is accessible through \Magento\Eav\Model\Config. It aggregates the meta information about entity types and attributes.

As it was mentioned before, there are a number of standard backend types for attributes. Starting with “static“, which defines an attribute that is stored in the main entity data table, and completing the list with “varchar“, “text“, “int“, “decimal“, “datetime“. However, custom backend types are possible, too.

The EAV setup model \Magento\Eav\Setup\EavSetup must be used to work with attributes and entity types in the module setup classes. It’s a very important class for this reason.

$eavSetup->addAttribute($entityTypeId, $code, $attr)

  • adds an attribute with a specific code to a specific entity type
  • fields in the $attr argument are being mapped before applied to the attribute table fields
  • if the default values are sufficient, there is no need to specify a field in the array of parameters

$eavSetup->updateAttribute($entityTypeId, $id, $field, $value, $sortOrder)

  • updates a specific field of an attribute
  • the $value goes directly to a database table column that corresponds to $field

The fields mapper is different for different EAV entity implementations, for example this is how it looks for \Magento\Catalog\Model\ResourceModel\Setup\PropertyMapper:

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

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

namespace Magento\Catalog\Model\ResourceModel\Setup;

 

use Magento\Eav\Model\Entity\Setup\PropertyMapperAbstract;

 

class PropertyMapper extends PropertyMapperAbstract

{

    /**

     * Map input attribute properties to storage representation

     *

     * @param array $input

     * @param int $entityTypeId

     * @return array

     * @SuppressWarnings(PHPMD.UnusedFormalParameter)

     */

    public function map(array $input, $entityTypeId)

    {

        return [

            ‘frontend_input_renderer’ => $this->_getValue($input, ‘input_renderer’),

            ‘is_global’ => $this->_getValue(

                $input,

                ‘global’,

                \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL

            ),

            ‘is_visible’ => $this->_getValue($input, ‘visible’, 1),

            ‘is_searchable’ => $this->_getValue($input, ‘searchable’, 0),

            ‘is_filterable’ => $this->_getValue($input, ‘filterable’, 0),

            ‘is_comparable’ => $this->_getValue($input, ‘comparable’, 0),

            ‘is_visible_on_front’ => $this->_getValue($input, ‘visible_on_front’, 0),

            ‘is_wysiwyg_enabled’ => $this->_getValue($input, ‘wysiwyg_enabled’, 0),

            ‘is_html_allowed_on_front’ => $this->_getValue($input, ‘is_html_allowed_on_front’, 0),

            ‘is_visible_in_advanced_search’ => $this->_getValue($input, ‘visible_in_advanced_search’, 0),

            ‘is_filterable_in_search’ => $this->_getValue($input, ‘filterable_in_search’, 0),

            ‘used_in_product_listing’ => $this->_getValue($input, ‘used_in_product_listing’, 0),

            ‘used_for_sort_by’ => $this->_getValue($input, ‘used_for_sort_by’, 0),

            ‘apply_to’ => $this->_getValue($input, ‘apply_to’),

            ‘position’ => $this->_getValue($input, ‘position’, 0),

            ‘is_used_for_promo_rules’ => $this->_getValue($input, ‘used_for_promo_rules’, 0),

            ‘is_used_in_grid’ => $this->_getValue($input, ‘is_used_in_grid’, 0),

            ‘is_visible_in_grid’ => $this->_getValue($input, ‘is_visible_in_grid’, 0),

            ‘is_filterable_in_grid’ => $this->_getValue($input, ‘is_filterable_in_grid’, 0),

        ];

    }

}

Module 3. View Layer. Rendering

  • Overview
    • Templates
    • Blocks
    • Design Layout XML Schema
  • Rendering flow
    • Rendering Flow Aspects: View
    • Rendering Flow Aspects: Pages and Result Object
  • View elements
  • Block Architecture and Lifecycle
    • Block Inside
    • Lifecycle
  • Templates
    • Templates Initiation
    • Conventional Templates Location
    • Overriding Templates
    • Root template
    • Argument Values from Layout
  • Layout XML structure
    • <block>
    • <container>
    • The before and after attributes
    • <action>
    • <referenceBlock> and <referenceContainer>
    • <move>
    • <update>
    • <argument>

Overview

Templates

Magento 2 still uses PHTML files for templates. Unlike Magento 1.x, using PHTML is no longer the only option, any template system can be used, but for we will stick with PHTML for now as they come by default and cover all available themes.

Blocks

Blocks are classes to encapsulate reusable functionality responsible for rendering. Blocks usually instantiate models to trigger some rendering-related business logic, or to fetch necessary data for rendering.

Design Layout XML Schema

Layout XML files pull together the entire set of blocks template files to be rendered in browser. It also declares block hierarchy that allows to build a layout tree before rendering. Layout XML format evolved since Magento 1.x.

Rendering flow

The chart below shows a general process flow for rendering pages within a website. 

Rendering Flow Aspects: View

The \Magento\Framework\App\ViewInterface contains the following main methods:

  • loadLayoutUpdates()
  • renderLayout()
  • loadLayout()
  • getPage()
  • getLayout()

This interface now encapsulates logic that belonged to the action controller class in Magento 1.x. You have an access to the View object in the action controller by using $this->_view.

The \Magento\Framework\View\Layout class is an analog of the Mage_Core_Model_Layout class in Magento 1.x. This class together with a Processor class (\Magento\Framework\View\Layout\ProcessorInterface) implements the whole logic of loading, parsing and filtering layout XML files, generating layout XML for the current page, generating block instances, and setting the right parameters into them.

This mechanism is somewhat deprecated, Magento 2 has another rendering mechanism based on a Page object, that is going to substitute View infrastructure in the future releases.

There are two phases of rendering.

Phase One, loading layout, makes Magento load all XML layout, render them to build a list of instructions for block creation. Then, Magento creates a layout structure and instantiates blocks in it

Phase Two, when it’s time to render the loaded layout, Magento executes toHtml() methods of the root blocks and concatenates the result.

Rendering Flow Aspects: Pages and Result Object

A concept of result object is to use page object returned to the Application inside Application::launch() as a result of the rest of the request flow. The idea is to create a \Magento\Framework\View\Result\Page object in the action controller using \Magento\Framework\View\Result\PageFactory. If the Page object is returned in Application, it then is rendered using renderPage() method. 

This part of training is a bit inconsistent and incomplete at the moment, there was a contradictory information in the Fundamentals training, no info in the Developers documentation or any other resource. Use with care, and check the view rendering flow yourself on the first opportunity. Sorry for inconvenience!

View elements

There are three types of view elements in Magento 2:

  • Containers are logical wrappers very similar to \Magento\Framework\View\Element\Text\ListText, except there can be an instance of container, they are abstract concept
  • Blocks — almost same as in Magento 1.x
  • UiComponents — responsible for representing and rendering form elements. Implementation is in \Magento\Framework\View\Element\UiComponentInterface. Note that \Magento\Framework\View\Element\UiComponentInterface extends \Magento\Framework\View\Element\BlockInterface, which means UI components are blocks, too.

A containers:

  • doesn’t have any classes related to it
  • renders all its children
  • allows configuration of some attributes (e.g. wrapping tag, CSS class)

Block Architecture and Lifecycle

Every page consists of hierarchical structure of blocks. Layout does not define a location and shape of the blocks on a page, it just defines their sequence and hierarchy. How the blocks actually look on the page, depends on how they are rendered.

The role of the blocks in layout is adding content within the layout structure. Blocks are put to the layout as children to containers and to other blocks.

Block Inside

Every block in Magento 2 implements \Magento\Framework\View\Element\BlockInterface and is extends \Magento\Framework\View\Element\AbstractBlock.

The interface commands a block to implement public toHtml() method which is always called if the block needs to be rendered.

The AbstractBlock also introduces a number of important methods:

 

 

_prepareLayout()

A specific method that is executed when block is created. It is often redeclared in a specific block and contains init operations that happen at the moment layout is being built. It’s important to know it is called before toHtml()

addChild()

Adds a child block. Since block structure is hierarchical, there needs to be methods to add, remove, find and sort children.

_toHtml(), _beforeToHtml(), _afterToHtml()

These are methods that are executed right before, at the moment and after the rendering, they are called in toHtml() and are redeclared quite often in concrete blocks implementation.

toHtml()

This method is an implementation of rendering initially declared in BlockInterface.

This is how toHtml() method implemented in the AbstractBlock:

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

28

29

30

31

32

33

34

35

/**

 * Produce and return block’s html output

 *

 * This method should not be overridden. You can override _toHtml() method in descendants if needed.

 *

 * @return string

 */

public function toHtml()

{

    $this->_eventManager->dispatch(‘view_block_abstract_to_html_before’, [‘block’ => $this]);

    if ($this->_scopeConfig->getValue(

        ‘advanced/modules_disable_output/’ . $this->getModuleName(),

        \Magento\Store\Model\ScopeInterface::SCOPE_STORE

    )) {

        return ;

    }

 

    $html = $this->_loadCache();

    if ($html === false) {

        if ($this->hasData(‘translate_inline’)) {

            $this->inlineTranslation->suspend($this->getData(‘translate_inline’));

        }

 

        $this->_beforeToHtml();

        $html = $this->_toHtml();

        $this->_saveCache($html);

 

        if ($this->hasData(‘translate_inline’)) {

            $this->inlineTranslation->resume();

        }

    }

    $html = $this->_afterToHtml($html);

 

    return $html;

}

While toHtml() method is declared as final in Magento 1.x, in Magento 2 it is not (in order to be able to write plugins, most probably). However, you must avoid redeclaring toHtml() directly.

The most important block type a developer should be aware of are as follows:

Block class

Description

\Magento\Framework\View\Element\Text

Text block, it allows you to add various portions of text using addText() and then render that text concatenated

\Magento\Framework\View\Element\Text\ListText

Text list block. All it does when being rendered is render its own children. It’s quite similar to the behavior of containers

\Magento\Framework\View\Element\Messages

Messages block. It provides an interface to set a collection of messages, or add messages one by one, and then it renders them with special wrapping based on a specific template

\Magento\Framework\View\Element\Redirect

Redirect block, it handles various browser-side redirections

\Magento\Framework\View\Element\Template

A very basic template block. Sometimes it’s just enough to have a block that can render itself based on a template you specify.

There are many ways to pass template to a block that is extended from \Magento\Framework\View\Element\Template. You can do it by

  • passing [‘template’ => ‘your-template.phtml’] as a second argument in the block constructor
  • calling $block->setTemplate(‘your-template.phtml’)
  • specifying a template as an attribute within <block> construct in the layout XML file. 

Lifecycle

It was already mentioned that block has two separate stages of its life. 

Block generation

Block rendering

  • Instances of all blocks declared in the layout are created
  • Structure is built and block children are set
  • Block’s _prepareLayout() is called for every block
  • Nothing is rendered at this point

As containers are not blocks and don’t have own instance, all that happens to a container at this point is assigning attributes from layout XML declaration

  • starts with calling Layout::getOutput()
  • a loop through every root block and container defined in the empty.xml layout XML file
  • every block’s toHtml() method is called
  • in case of containers, the process loops through all container’s children and concatenates their resulting rendering output
  • result of rendering is being concatenated into one string

Templates

Templates are snippets of HTML code provided as PHTML files that contain PHP instructions, local variable declarations and calls of class methods.

Templates Initiation

Templates are usually initiated in layout files. Each layout block has an associated template. The template is specified in the templateattribute of the layout instruction. For example, from <Magento_Catalog_module_dir>/view/frontend/layout/catalog_category_view.xml:

Example

<block class=“Magento\Catalog\Block\Category\View” name=“category.image” template=“Magento_Catalog::category/image.phtml”/> 

This means that the category.image block is rendered by the image.phtml template, which is located in the category subdirectory of the Magento_Catalog module templates directory.

The templates directory of Magento_Catalog is <Magento_Catalog_module_dir>/view/frontend/templates.

Conventional Templates Location

Templates are stored in the following locations:

  • Module templates: <module_dir>/view/frontend/templates/<path_to_templates>
  • Theme templates: <theme_dir>/<Namespace>_<Module>/templates/<path_to_templates>

Here <path_to_templates> might have several levels of directory nesting, or might be empty.

Examples:

  • <Magento_Catalog_module_dir>/view/frontend/templates/product/widget/new/content/new_grid.phtml
  • <Magento_Checkout_module_dir>/view/frontend/templates/cart.phtml

Overriding Templates

For template files with the same name, the following is true:

  • Theme templates override module templates
  • Child theme templates override parent theme templates.

This mechanism is the basis of the template customization concept in Magento application, to change the output defined by a certain default template, you need to overriding one in your custom theme.

Root template

Magento 2 has a special template which serves as root template for all pages in the application: <Magento_Theme_module_dir>/view/base/templates/root.phtml. Unlike other templates, root.phtml contains the doctype specification and contributes to <head> and <body> sections of all pages rendered by Magento application.

Similarly to other templates, root.phtml can be overridden in a theme.

Argument Values from Layout

Arguments values set in a layout file can be accessed in templates using the get{ArgumentName}() and has{ArgumentName}() methods.

Layout XML structure

<block>

Defines a block.

Details: A block is a unit of page output that renders some distinctive content – a piece of information, a user interface element – anything visually tangible for the end-user. Blocks employ templates to generate HTML. Examples of blocks include a category list, a mini cart, product tags, and product listing.

Attribute

Description

Values

Required?

class

Name of a class that implements rendering of a particular block. An object of this class is responsible for actual rendering of block output.

class name

yes

name

Name that can be used to address the block to which this attribute is assigned. The name must be unique per generated page. If not specified, an automatic name will be assigned in the format ANONYMOUS_n

0-9, A-Z, a-z, underscore (_), period (.), dash (-). Should start with a letter. Case-sensitive.

no

before

Used to position the block

before an element under the same parent. The element name or alias name is specified in the value. Use dash (-) to position the block before all other elements of its level of nesting.

Possible values: element name or dash (-)

no

after

Used to position the block after an element under the same parent. The element name or alias name is specified in the value. Use dash (-) to position the block after all other elements of its level of nesting.

Possible values: element name or dash (-)

no

template

A template that represents the functionality of the block to which this attribute is assigned.

template file name

no

as

An alias name that serves as identifier in the scope of the parent element.

0-9, A-Z, a-z, underscore (_), period (.), dash (-). Case-sensitive.

no

cacheable

Defines whether a block element is cacheable. This can be used for development purposes and to make needed elements of the page dynamic.

true or false

no

To pass parameters use the <argument> instruction.

<container>

A structure without content that holds other layout elements such as blocks and containers.

Details: A container renders child elements during view output generation. It can be empty or it can contain an arbitrary set of <container>and <block> elements.

Attribute

Description

Values

Required?

name

A name that can be used to address the container in which this attribute is assigned. The name must be unique per generated page.

A-Z, a-z, 0-9, underscore (_), period (.), dash (-). Should start with a letter. Case-sensitive.

yes

label

An arbitrary name to display in the web browser.

any

no

before

Used to position the container before an element under the same parent. The element name or alias name is specified in the value. Use dash (-) to position the block before all other elements of its level of nesting.

Possible values: element name or dash (-).

no

after

Used to position the container after an element under the same parent. The element name or alias name is specified in the value. Use dash (-) to position the block after all other elements of its level of nesting.

Possible values: element name or dash (-).

no

as

An alias name that serves as identifier in the scope of the parent element.

0-9, A-Z, a-z, underscore (_), period (.), dash (-). Case-sensitive.

no

output

Defines whether to output the root element. If specified, the element will be added to output list. (If not specified, the parent element is responsible for rendering its children.)

Any value except the obsoletetoHtml. Recommended value is1.

no

htmlTag

Output parameter. If specified, the output is wrapped into specified HTML tag.

Any valid HTML 5 tag.

no

htmlId

Output parameter. If specified, the value is added to the wrapper element. If there is no wrapper element, this attribute has no effect.

Any valid HTML 5 <id> value.

no

htmlClass

Output parameter. If specified, the value is added to the wrapper element. If there is no wrapper element, this attribute has no effect.

Any valid HTML 5 <class> value.

no

Sample of usage in layout:

1

2

3

4

5

<!– … –>

<container name=“div.sidebar.additional” htmlTag=“div” htmlClass=“sidebar sidebar-additional” after=“div.sidebar.main”>

    <container name=“sidebar.additional” as=“sidebar_additional” label=“Sidebar Additional”/>

</container>

<!– … –>

This would add a new column to the page layout.

The before and after attributes

To help you to position elements in a specific order suitable for design, SEO, usability, or other requirements, Magento software provides the before and after layout attributes.

These optional attributes can be used in layout XML files to control the order of elements in their common parent. The following tables give a detailed description of the results you can get using the before and after attributes. The first table uses a block a as positioned element.

Attribute

Value

Description

before

Dash (-)

The block displays before all other elements in its parent node.

before

[element name]

The block displays before the named element.

before

empty value or [element name] is absent

Use the value of after. If that value is empty or absent as well, the element is considered as non-positioned.

after

Dash (-)

The block displays after all other elements in its parent node.

after

[element name]

The block displays after the named element.

after

empty value or [element name] is absent

Use the value of before. If that value is empty or absent as well, the block is considered as non-positioned.

Examples:

Situation

Result

Both before and after attributes are present

after takes precedence.

Both before and after attributes are absent or empty

The element is considered as non-positioned. All other elements are positioned at their specified locations. The missing element displays at a random position that doesn’t violate requirements for the positioned elements.

Several elements have before or after set to dash (-)

All elements display at the top (or bottom, in case of the after attribute), but the ordering of group of these elements is undefined.

The before or after attribute’s value refers to an element that is not located in the parent node of the element being defined.

The element displays at a random location that doesn’t violate requirements for the correctly positioned elements.

<action>

The <action> instruction is deprecated. If the method implementation allows, use the <argument> for <block> or <referenceBlock> to access block public API.

Calls public methods on the block API.

Details: Used to set up the execution of a certain method of the block during block generation; the <action> node must be located in the scope of the <block> node.

Example

1

2

3

4

5

6

7

8

<block class=“Magento\Module\Block\Class” name=“block”>

    <action method=“setText”>

        <argument name=“text” translate=“true” xsi:type=“string”>Text</argument>

    </action>

    <action method=“setEnabled”>

        <argument name=“enabled” xsi:type=“boolean”>true</argument>

    </action>

</block>

The <action> child nodes are translated into block method arguments. Child nodes names are arbitrary. If there are two or more nodes with the same name under <action>, they are passed as one array.

In the previous example, the value of <arg1> is passed as the first argument and <arg2> values are passed as array(‘one’, ‘two’). The list of all available methods depends on the block implementation (for example, the public method of the block class).

Attribute

Description

Values

Required?

method

Name of the public method of the block class this tag is located in that is called during block generation.

block method name

yes

To pass parameters, use the <argument> instruction.

<referenceBlock> and <referenceContainer>

Updates in <referenceBlock> and <referenceContainer> are applied to the corresponding <block> or <container>.

For example, if you make a reference by <referenceBlock name=”right”>, you’re targeting the block <block name=”right”>.

To pass parameters to a block use the <argument> instruction.

Attribute

Description

Values

Required?

remove

Allows to remove or cancel the removal of the element. When a container is removed, its child elements are removed as well.

The remove attribute is optional and its default value is false.

This implementation allows you to cancel removal of a block or container in your layout by setting remove attribute value to false. 

Example

1

<referenceBlock name=“block.name” remove=“true” />

true/false

no

display

Allows you to disable rendering of specific block or container with all its children (both set directly and by reference). The block’s/container’s and its children’ respective PHP objects are still generated and available for manipulation.

The display attribute is optional and its default value is true.

You are always able to overwrite this value in your layout. In situation when remove value is true, the display attribute is ignored. 

Example

1

<referenceContainer name=“container.name” display=“false” />

true/false

no

<move>

Sets the declared block or container element as a child of another element in the specified order.

Example

1

<move element=“name.of.an.element” destination=“name.of.destination.element” as=“new_alias” after=“name.of.element.after” before=“name.of.element.before”/>

The <move> is skipped if the element to be moved is not defined.

If the as attribute is not defined, the current value of the element alias is used. If that is not possible, the value of the name attribute is used instead.

During layout generation, the <move> instruction is processed before the <remove> instruction. This means if any elements are moved to the element scheduled for removal, they will be removed as well.

Attribute

Description

Values

Required?

element

Name of the element to move.

element name

yes

destination

Name of the target parent element.

element name

yes

as

Alias name for the element in the new location.

0-9, A-Z, a-z, underscore (_), period (.), dash (-). Case-sensitive.

no

after | before

Specifies the element’s position relative to siblings. Use dash (-) to position the block before or after all other siblings of its level of nesting. If the attribute is omitted, the element is placed after all siblings.

element name

no

<update>

Includes a certain layout file. Used as follows:

Example

1

<update handle=“{name_of_handle_to_include}”/>

The specified handle is “included” and executed recursively.

<argument>

Used to pass an argument.

Attribute

Description

Values

Required?

name

Argument name.

unique

yes

xsi:type

Argument type.

string|boolean|object|number|null|array

yes

translate

 

true|false

no

To pass multiple arguments use the following construction:

<arguments>

   <argument></argument>

   <argument></argument>

   

</arguments>

To pass an argument that is an array use the following construction:

<argument>

   <item></item>

   <item></item>

   

</argument>

Arguments values set in a layout file can be accessed in templates using the get{ArgumentName}() and has{ArgumentName}() methods. The latter returns a boolean defining whether there’s any value set. {ArgumentName} is obtained from the name attribute the following way: for getting the value of <argument name=”some_string”> the method name is getSomeString().

Example: Setting a value of css_class in the <Magento_Theme_module_dir>/view/frontend/layout/default.xml layout file:

Example

1

2

3

4

5

<!– … –>

<arguments>

    <argument name=“css_class” xsi:type=“string”>header links</argument>

</arguments>

<!– … –>

Using the value of css_class in <Magento_Theme_module_dir>/view/frontend/templates/html/title.phtml:

Example

1

2

3

// …

$cssClass = $this->getCssClass() ? ‘ ‘ . $this->getCssClass() : ;