Magento Internals: Applications and Default Area code
Magento has concept of applications and application areas.
As of now, you can find 5 applications in Magento 2 and hence 5 different entry points to codebase.
- HTTP application ( \Magento\Framework\App\Http ) Entry point for end users. Found in pub/index.php
- Media Storage application ( \Magento\MediaStorage\App\Media ) (pub/get.php) This serves images that are not yet on the file system. It can resize images on the fly.
- Static Resource application (\Magento\Framework\App\StaticResource ) Entry point for static resources (JS, CSS, etc.). (pub/static.php)
- Cron (\Magento\Framework\App\Cron)
- Indexers (\Magento\Indexer\App\Indexer)
All of these implement \Magento\Framework\AppInterface . To my surprise console wasn’t an application in itself. It can lauch two application , cron and indexer.
HTTP application has concept of areas. You can have different dependency configurations,routing for different areas. Following is the list of areas found.
- admin
- frontend (Your regular storefront)
- Graphql
- Webapi
You can add your own areas by configuring `Magento\Framework\App\AreaList`. In pwa-studios upward-connector module does just that. Following snippet can be found in upward-connector module.
<type name="Magento\Framework\App\AreaList">
<arguments>
<argument name="areas" xsi:type="array">
<item name="pwa" xsi:type="array">
<item name="frontName" xsi:type="string">pwa</item>
</item>
</argument>
</arguments>
</type>
Snippet above adds a new application area named pwa. With this you can have your own folder inside etc directory named pwa. In that folder you can put your di.xml,events.xml that would apply only when current application area is pwa. Wait, but how does Magento know what area to load?
Magento looks at the request url. In tries to determine areacode based on url. If that can not be done, it will load the default areacode configured. This Logic can be found in \Magento\Framework\App\AreaList::getCodeByFrontName
public function getCodeByFrontName($frontName)
{
foreach ($this->_areas as $areaCode => &$areaInfo) {
if (!isset($areaInfo['frontName']) && isset($areaInfo['frontNameResolver'])) {
$resolver = $this->_resolverFactory->create($areaInfo['frontNameResolver']);
$areaInfo['frontName'] = $resolver->getFrontName(true);
}
if (isset($areaInfo['frontName']) && $areaInfo['frontName'] === $frontName) {
return $areaCode;
}
}
return $this->_defaultAreaCode;
}
See that last return statement. That’s what we are going to hack now.
If you look at the constructor signature of this class,
public function __construct(
\Magento\Framework\ObjectManagerInterface $objectManager,
Area\FrontNameResolverFactory $resolverFactory,
array $areas = [],
$default = null
) {
$this->objectManager = $objectManager;
$this->_resolverFactory = $resolverFactory;
if ($areas) {
$this->_areas = $areas;
}
if ($default) {
$this->_defaultAreaCode = $default;
}
}
Notice how $this->_defaultAreaCode can be configured using type configuration in di.xml. In fact that’s what Magento does in vendor/magento/module-store/etc/di.xml
<type name="Magento\Framework\App\AreaList">
<arguments>
<argument name="areas" xsi:type="array">
<item name="frontend" xsi:type="array">
<item name="frontName" xsi:type="null" />
<item name="router" xsi:type="string">standard</item>
</item>
</argument>
<argument name="default" xsi:type="string">frontend</argument>
</arguments>
</type>
Notice how default default is configured to be frontend. Now we can change this to adminhtml so that when we just hit our domain, admin login page opens up.
<type name="Magento\Framework\App\AreaList">
<arguments>
<argument name="default" xsi:type="string">adminhtml</argument>
</arguments>
</type>
When you put configuration above in di.xml of your module, the adminhtml router will be triggered. As it is, router will throw and error on following lines
TypeError: explode() expects parameter 2 to be string, null given in vendor/magento/framework/App/Router/Base.php:182
If you debug this, you can fix this by adding following snippet to app/etc/env.php
'system'=>[
'default'=>[
'web'=>[
'default'=>[
'admin'=>'admin/admin/auth/login'
]
]
]
],
After adding this to app/etc/env.php run
php bin/magento app:config:import
Then go the browser and just hit your domain and you should see something like following
Happy debugging!