The order of the scoped config files
-
01-10-2020 - |
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.
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.