4

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.

  • Last 2 lines of question is really awesome :-) – Baby in Magento Aug 1 '16 at 6:09
  • Are you ask for same method call in both files and loading order of files? – Rakesh Jesadiya Aug 1 '16 at 6:55
  • @Rakesh As far as I know, the files are merged into a big config and the same lines in both files are overwritten. I'm asking what overwrites what and where does that happen. – Marius Aug 1 '16 at 6:58
5

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

4

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.

  • good example, but I was looking for the core code that loads the di.xml files and maybe get an idea from there about how the order of the files is. – Marius Aug 1 '16 at 7:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.