Magento 2 Area Code

What is Area Code?

Area Code is a component that organizes code with the aim of optimising query processes. Only code that is defined in a specific Area Code is fetched in a given situation. This helps, for example, to optimise REST queries. What is rendered is not the entire HTML, but only what is absolutely necessary to answer a REST query.

The way Area Codes operate is best visualized when creating routers. Routers cannot be defined globally - they have to be contained within a given Area Code. What this means is that we can create two routers with an identical path and the framework will know, by itself, which Area Code we have in mind (due to the fact that routers start with a different path depending on where they are located).

Di.xml files can be defined in a catalogue (globally) or in subfolders, the names of which reflect the names of specific Area Codes. These could be, for example, ‘frontend’, ‘adminhtml’ or ‘webapi_rest’. Plugins and observers can also work globally or for a specific Area Code only.

The example below is of a WebAPi module and it illustrates how Area Code is created. As is the case with everything in Magento, nothing is hardcoded. We can benefit from blessings of XML and Dependency Injection. We insert the array with a definition of our Area Code into the areas array.

html
1 2 3 4 5 6 7 8 9 10 11 12 13 // file: vendor/magento/module-webapi/etc/di.xml <type name="Magento\Framework\App\AreaList"> <arguments> <argument name="areas" xsi:type="array"> <item name="webapi_rest" xsi:type="array"> <item name="frontName" xsi:type="string">rest</item> </item> <item name="webapi_soap" xsi:type="array"> <item name="frontName" xsi:type="string">soap</item> </item> </argument> </arguments> </type>

Below, you can see a custom FrontController in the act of triggering the area code.

html
1 2 // file: vendor/magento/module-webapi/etc/webapi_rest/di.xml <preference for="Magento\Framework\App\FrontControllerInterface" type="Magento\Webapi\Controller\Rest" />

Below is an example of an area definition for adminhtml. FrontNameResolver is in use, because the backend path is configurable.

html
1 2 3 4 5 6 7 8 9 10 11 // file: vendor/magento/module-backend/etc/dix.xml <type name="Magento\Framework\App\AreaList"> <arguments> <argument name="areas" xsi:type="array"> <item name="adminhtml" xsi:type="array"> <item name="frontNameResolver" xsi:type="string">Magento\Backend\App\Area\FrontNameResolver</item> <item name="router" xsi:type="string">admin</item> </item> </argument> </arguments> </type>

Why does Area Code cause problems?

The most common problems with Area Code occur in the moment of using setup:upgrade and other CLI commands. When writing this article I was using versions 2.1.9 and 2.2.4. In 2.1.9, bringing up of the console itself already sets Area Code to frontend. Therefore, if we try to set an Area Code in the constructor of any of the commands, we will immediately get an exception.

In version 2.2.4 Area Code is not set automatically in the same situation. I’ve tested setting Area Code in the constructor and everything was okay. Of course, if we create another command with a set Area Code, we will see an exception.

Below you will find example code that creates problems. As you can see, we cannot set Area Code if it has already been set. We also cannot check if an Area Code is set if it isn’t.

php
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 // file: vendor/magento/framework/App/State.php /** * Set area code * * @param string $code * @return void * @throws \Magento\Framework\Exception\LocalizedException */ public function setAreaCode($code) { if (isset($this->_areaCode)) { throw new \Magento\Framework\Exception\LocalizedException( new \Magento\Framework\Phrase('Area code is already set') ); } $this->_configScope->setCurrentScope($code); $this->_areaCode = $code; } /** * Get area code * * @return string * @throws \Magento\Framework\Exception\LocalizedException */ public function getAreaCode() { if (!isset($this->_areaCode)) { throw new \Magento\Framework\Exception\LocalizedException( new \Magento\Framework\Phrase('Area code is not set') ); } return $this->_areaCode; }

How to avoid problems?

In order to avoid problems with exceptions you should stick with a number of rules:

  • Never set Area Code within the constructor. Regardless of where it is, the constructor is always triggered when classes are loaded.
  • If you want to set an Area Code in CLI, you should do it with an ‘execute’ method as it will be launched only after we trigger the command.
  • You should not use Area Code in the frontend or in admin. As I mentioned earlier, Area Code is set based on route, so every time a site is launched, it sets a specific Area Code.
  • If you want to set an Area Code, you should do it with try { } catch { } - there is no other way to check if an Area Code has already been set, because an exception is always thrown.
  • Do not use Area Code where it is not necessary. Most operations can be done without setting Area Code.

See the below example of using try { } catch { }

php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public function __construct(\Magento\Framework\App\State $state) { $this->appState = $state; } public function someMethod() { try { $this->appState->setAreaCode('frontend'); } catch (\Magento\Framework\Exception\LocalizedException $exception) { // do nothing } // operations }

We can also do it in a more elegant way. Magento can use the emulateAreaCode() method. It’s useful, especially when working via CLI. Emulation will enable you to perform operations on Area Codes regardless if they are set or not. If you look into the method’s code, you will notice that the areaCode property is hardcoded and setAreaCode() is omitted. After an operation is finished, the previously used areaCode is set.

See the below example:

php
1 2 3 4 5 6 7 8 9 10 11 public function someMethod() { $self = $this; try { $this->appState->emulateAreaCode('frontend', function () use ($self) { // operations }); } catch (\Exception $exception) { // handle exception } }

Summing up, Area Code is a very useful component of Magento 2. It helps to make work more efficient and lets you optimize code in large projects. I sincerely hope this article will let you avoid trouble with the ‘Area Code is already set’ exception.