Question

In Magento 2, you can have some config files be scoped.
For example di.xml can be present in the etc folder of a module and/or etc/frontend and/or etc/adminhtml.
Same goes for events.xml and maybe others.
I know that the one from etc/frontend does not get loaded in the admin area and etc/adminhtml is not loaded in the frontend.
But what is the order of loading them in an area?

  • etc/di.xml
  • etc/frontend/di.xml

or

  • etc/frontend/di.xml
  • etc/di.xml

Please support your answer with some code or at least a link to the code. Don't provide a simple "this way/that way" answer.

Was it helpful?

Solution

Pretty sure the system merges the configuration with no explicit order.

In Magento/Framework/App/Utility/Files there's the following methods that gets all the di.xml from the module and merge them, according to the code the etc/di.xml is always first in the merge process:

public function getDiConfigs($asDataSet = false)
{
    $primaryConfigs = Glob::glob(BP . '/app/etc/{di.xml,*/di.xml}', Glob::GLOB_BRACE);
    $moduleConfigs = [];
    foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) {
        $moduleConfigs = array_merge(
            $moduleConfigs,
            Glob::glob($moduleDir . '/etc/{di,*/di}.xml', Glob::GLOB_BRACE)
        );
    }
    $configs = array_merge($primaryConfigs, $moduleConfigs);
    if ($asDataSet) {
        $output = [];
        foreach ($configs as $file) {
            $output[$file] = [$file];
        }
        return $output;
    }
    return $configs;
}

The system loads the config based on the area: https://github.com/magento/magento2/blob/6ea7d2d85cded3fa0fbcf4e7aa0dcd4edbf568a6/lib/internal/Magento/Framework/App/Area.php#L229

The ConfigLoaderInterface is the interface that implements the load method based on the area

OTHER TIPS

Whenever we have created two di.xml file for different area like, one di.xml file in etc base folder and one di.xml file are call inside {area}/di.xml file.

Final outcomes are come from base di.xml file not from area di.xml file.

Below result are outcomes of override files,

This code for override topmenu block,

app/code/Package/Module/registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Package_Module',
    __DIR__
);

app/code/Package/Module/etc/di.xml file,

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Theme\Block\Html\Topmenu" type="Package\Module\Block\Topmenu"/>
</config>

same Topment.php file override by area file like in frontend di.xml file,

app/code/Package/Module/etc/frontend/di.xml file,

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Theme\Block\Html\Topmenu" type="Package\Module\Block\Fronttop"/>
</config>

app/code/Package/Module/Topmenu.php

<?php
namespace Package\Module\Block;

class Topmenu extends \Magento\Theme\Block\Html\Topmenu
{
    protected $categoryFactory;

    protected $_filterProvider;

    public function __construct(        
        \Magento\Framework\View\Element\Template\Context $context,      
        \Magento\Catalog\Model\CategoryFactory $categoryFactory,
        \Magento\Framework\Data\Tree\NodeFactory $nodeFactory,
        \Magento\Framework\Data\TreeFactory $treeFactory,
        \Magento\Cms\Model\Template\FilterProvider $filterProvider,
        array $data = []    
    ){    
        echo 'final file call base area...';      
        $this->categoryFactory = $categoryFactory;  
        $this->_filterProvider = $filterProvider;
        parent::__construct($context,$nodeFactory,$treeFactory,$data);    
    }

    public function test1(){
        //code goes here...
    }
}

app/code/Package/Module/Fronttop.php

<?php
namespace Package\Module\Block;

class Fronttop extends \Magento\Theme\Block\Html\Topmenu
{
    protected $categoryFactory;

    protected $_filterProvider;

    public function __construct(        
        \Magento\Framework\View\Element\Template\Context $context,      
        \Magento\Catalog\Model\CategoryFactory $categoryFactory,
        \Magento\Framework\Data\Tree\NodeFactory $nodeFactory,
        \Magento\Framework\Data\TreeFactory $treeFactory,
        \Magento\Cms\Model\Template\FilterProvider $filterProvider,
        array $data = []    
    ){  
        echo 'final file call frontend area...';    
        $this->categoryFactory = $categoryFactory;  
        $this->_filterProvider = $filterProvider;
        parent::__construct($context,$nodeFactory,$treeFactory,$data);    
    }

    public function test1(){
        //code goes here...
    }
}

After checking inside frontend,

you have to see at top, message are display from construct with final file call base area.. from etc/di.xml file override method. in our case Fronttop.php file;

Here we have create two di.xml file with calling same Topmenu.php file and final result are comes from base di.xml file.

Override file using frontend di.xml in our case, Package\Module\Block\Topmenu.php file is not call at all.

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top