Introduction
The concept of dependencies, or using and being dependent upon another module鈥檚 features, is important in Magento.
In the Magento system, all modules are partitioned into logical groups, each one of which is responsible for a separate feature. In practice this means that:
- Several modules cannot be responsible for one feature.
- One module cannot be responsible for several features.
- A module declares explicit dependency, if any, on another module. Any dependency upon other components (theme, language pack, or library) must also be declared.
- Removing or disabling a module does not result in disabling other modules.
Modules can be dependent upon the following components:
- other modules
- PHP extensions
- Libraries (either Magento Framework Library or 3rd party libraries)
When using Magento's modularity, you can lose historical information contained in a module if this module is removed or disabled. We recommend considering storage of such information before you remove or disable a module.
Module dependencies tasks
At a high level, there are three main steps for managing module dependencies:
- Name and declare the module (do this in the
module.xml
file) - Declare any dependencies that the module has, whether on other modules or a different component. (do this in the module鈥檚
composer.json
file) - (Optional) Define the desired load order of config files, .css files, etc. (do this in the
module.xml
file)
EXAMPLE: Module A declares a dependency upon Module B. Thus, in Module A鈥檚 module.xml
file, Module B is listed in the <sequence> list, so that B鈥檚 files are loaded before A鈥檚. Additionally, in A鈥檚 composer.json
file, a dependency upon Module B will need to be declared. Furthermore, in the deployment configuration, Modules A and B must both be defined as enabled.
Declare the module's dependencies
A module鈥檚 dependencies (that is, all of the components upon which the module is dependent upon) are listed in the module鈥檚 composer.json
file.
As an example, see the Magento_Catalog module鈥檚 composer.json.
Define the load order for a module's dependencies
The load order of any dependencies on a module are declared using the <sequence> element in the module.xml file.
The <sequence> element is optional, and is used only if 1) you care in what order components are loaded/installed, and 2) only for modules. No other type of component is entered in the <sequence> section. Furthermore, listing a module in the <sequence> list doesn鈥檛 mean that everything about that module is used; only config files and certain files under the /etc and the /view directories are considered for load order. Classes within a module are not impacted by their module being in the <sequence> list.
Basic syntax using the <sequence> element:
<sequence> <module name="Vendor_Module"/> </sequence>
Usage example
Magento\Customer\etc\module.xml
<config> <module name="Magento_Customer" schema_version="1.11.0"> <sequence> <module name="Magento_Adminhtml"/> <module name="Magento_Customer"/> <module name="Magento_Sales"/> </sequence> </module> </config>
Remember that the <sequence> element in the module.xml file is used to define the load order of dependencies, but the actual dependency declarations are made in composer.json file.
Dependency Injection Overview
Dependency injection means that all object dependencies are passed (that is, injected) into an object instead of being pulled by the object from the environment.
A dependency (sometimes referred to as coupling) implies the degree that one component relies on another component to perform a function. A large amount of dependency limits code reuse and makes moving components to new projects difficult.
The object manager specifies the dependency environment for constructor injection. The object manager must be present only when composing code.
For more information about using dependency injection, refer to the Developer鈥檚 Guide.
Types of module dependencies
Module dependencies in Magento could be of two types: hard and soft dependencies.
-
A hard dependency implies that a module cannot function without the modules upon which it depends. Specifically:
- The module contains code that uses logic from another module directly, that is, the latter鈥檚 instances, class constants, static methods, public class properties, interfaces, and traits.
- The module contains strings that include class names, method names, class constants, class properties, interfaces, and traits from another module.
- The module deserializes an object declared in another module.
- The module uses or modifies the database tables used by another module.
-
A soft dependency implies that a module can function without other modules, on which it depends. Specifically:
- The module directly checks another module鈥檚 availability.
- The module extends another module鈥檚 configuration.
- The module extends another module鈥檚 layout.
If a module uses code from another module, it should declare the dependency explicitly.
Modules are installed in the following sequence: first, a module serving as dependency for another module will be installed, followed by the module dependent on it.
Inappropriate dependencies
You should avoid the following dependencies:
- Circular dependencies (both direct and indirect)
- Undeclared dependencies
- Incorrect dependencies
Dependencies in different layers
There are peculiarities of building the dependencies between the modules belonging to different layers.
Dependencies in the framework layer
Modules belonging to the framework layer can be used in the application layer via an explicit dependency.
In this case using interfaces is preferable to using classes.
You can build dependencies between classes in the framework layer even if they belong to different modules.
Dependencies in the application layer
Modules belonging to the application layer cannot be used in the framework layer.
You can build dependencies between classes in the application layer, but these classes must belong to the same module. Dependencies between the modules of the application layer should be built only via the service layer or the service provider interface (SPI).
API- and SPI-specific interfaces
To facilitate building correct dependencies between the modules, the Magento system has both API (Application Programming Interface) and SPI (Service Provide Interface) interfaces.
Interfaces marked as API-specific can be used by other modules; and interfaces marked as SPI-specific can be implemented by other modules.
To be considered API-specific, an interface should be declared with @api
annotation:
/** * @api */ interface RouterInterface { public function match(); } final class Mage_Core_Controller_Varien_Router_Base implements RouterInterface { //... }
Thus, an interface and its implementations automatically become a part of the API, unlike other elements, which remain module-private. All classes considered a part of the API must be declared final
to prevent the implicit use of them in the SPI.
To be considered SPI-specific, an interface should be declared with @spi
annotation:
/** * @spi */ interface RouterInterface { public function match(); }
Thus, an interface automatically becomes a part of the SPI, while its implementations are part of neither the SPI nor the API. Other interfaces and their implementations, which are not marked as SPI-specific, remain module-private.
The SPI-specific interfaces can be implemented by third party developers and used in dependency injection configurations.
To be marked as both API- and SPI-specific, an interface should be declared with @api
and @spi
annotations:
/** * @api * @spi */ interface Magento_AuthorizationInterface { public function isAllowed($resource); }
Thus, a class can be used and reimplemented by third party developers. To ensure correct behavior, a class should be split into a final class, which becomes a part of the API, and an implementation interface, which becomes a part of the SPI.
Find us on