Magento Series: Running Code in a Specific Area

What are Magento 2 areas?

Magento (Adobe Commerce) uses areas, a “logical component that organizes code for optimized request processing,” to make web service calls more efficient by loading only the dependent code for the areas involved. It is possible for every one of the default areas defined by Magento to contain entirely different codes related to processing URLs and requests.

Each Magento 2 module has its own set of configuration files gathered into the module’s etc directory.

➡️ Additions you make to those directory configuration files are applied globally to your module.

➡️ Areas are registered in the Dependency Injection framework di.xml file.

Every Magento 2 module also has nested configuration directories in the etc directory for any required adminhtml, frontend, API REST, or API SOAP configuration, among others. Additions you make to files in these directories override the settings in the global configuration files for the respective functionality only.

List of areas

AreaFile locationDescription
global<module-dir>/etc/<file_name>allows the observer to run in all areas (adminhtml, crontab, frontend, graphql, webapi_rest, webapi_soap)
adminhtml<module-dir>/etc/adminhtml/<file_name>used for displaying modules and resources that are used in the admin panel
crontab<module-dir>/etc/crontab/<file_name>always loads the ‘crontab’ area 
frontend<module-dir>/etc/frontend/<file_name>
contains template and layout files that define the appearance of your storefront 
graphql<module-dir>/etc/graphql/<file_name>GraphQL provides an alternative to REST and SOAP web APIs for frontend development
webapi_rest<module-dir>/etc/webapi_rest/<file_name>
has a front controller that understands how to do URL lookups for REST-based URLs 
webapi_soap<module-dir>/etc/webapi_soap/<file_name>

How do areas work with modules?

Modules define which resources are visible and accessible in an area, as well as an area’s behavior. The same module can influence several areas. For instance, the RMA module is represented partly in the adminhtml area and partly in the frontend area.

If the configuration file is located in the directory of an etc/module, its values are located in the global scope. To specify the scope of, for example, admin.html or front-end configuration, you need to put the configuration file in the etc/frontend or etc/adminhtml folder respectively.

Each area declares itself within a module. All resources specific for an area are located within the same module as well.

➡️ Modules should not depend on other modules’ areas.

What are the best practices to follow when working with areas?

  • Never set an 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.
  • 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 dode where it is not necessary. Most operations can be done without setting an area code.

How do areas look in the configuration file?

Every module can have an area-specific and a global di.xml file. All the di.xml configuration files declared in the system are read by Magento (Adobe Commerce) and merged together by attaching all nodes.

The area-specific di.xml files configure dependencies for the presentation layer and the global di.xml file configures all the dependencies that are left. 

Consider the following <MAGENTO_DIR>/module-webapi/etc/di.xml configuration file:

<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>

Defining which resources are visible and accessible in an area allows you to control the behavior of that specific area if necessary.

 ➡️ If your extension works in several different areas, ensure that it has separate behavior and view components for each area.

How to emulate a specific area?

Area emulation refers to the reproduction of the action or function of another area. The most common problems with area code occur in the moment of using setup:upgrade and other CLI commands. Bringing up the console itself already sets the area code to the frontend. Therefore:

➡️ If we try to set an area code in the constructor of any of the commands, we will immediately get an exception.

Below, you will find an example code that creates problems. We cannot set the area code if it has already been set. We also cannot check if an area code is set if it isn’t.

/**
* 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;
}

To fix this issue, Magento (Adobe Commerce) can use the emulateAreaCode() method. It is especially useful when working via CLI. Emulation will enable you to perform operations on area codes regardless of whether they are set or not. If you look into the method’s code, you will notice that the area code property is hardcoded and setAreaCode() is omitted. After an operation is finished, the previously used area code is set.

For example:

public function someMethod()
{
   $id = 100;
   try {
       $this->appState->emulateAreaCode('frontend', function () use ($id) {
           // operations
       });
   } catch (\Exception $exception) {
       // handle exception
   }
}

Need help with Magento (Adobe Commerce) development? scandiweb is the most certified Magento team in the world—get your dedicated eCommerce growth team today. Or get in touch with one of our experts and find out how we can help you get the hassle out of web development, design, and the whole eCommerce optimization process.

If you enjoyed this post, you may also like