The modular approach in software architecture allows you to logically divide a project into large composite fragments (modules).
A defining feature of a module is its self-sufficiency; in some sense, it’s a form of dividing a monolithic application into "microservices".
The key difference from microservices is that modules must exchange data through predefined contracts, which replace HTTP API (or message brokers), and they also share a common folder for routes, services, and external libraries from the /vendor/ directory.
It is recommended to design contracts in a way that would allow extracting a module into a full-fledged microservice if needed.
In the HLEB2 framework, a Module is essentially an MVC (Action-Domain-Responder for web) in miniature. The module has its own controller, its own folder for templates, and even its own configuration is permissible, all of which are located within the module’s folder. Its own logic is also assumed (as well as Models), but for this, it is recommended to create a separate structure in the project’s /app/ folder or within the module itself.
When using the approach of full autonomy of parts in the project, which is the essence of modular development, you may not use controllers, middleware, or models from /app/ at all, implementing everything within the modules.
The role of a module’s controller in the route differs from a regular controller in that the method is named 'module' instead of 'controller', and it contains an additional initial argument with the module’s name.
The module’s controller must inherit from Hleb\Base\Module.
For the Composer class loader to generate the class map for modules, add the module folder name ("modules/") to the "autoload" > "classmap" section of the /composer.json file.
A simple way to create the basic structure of a module using a console command:
$php console --create module example
This command will create a new module template in the /modules/example/ directory of the project. You can use another suitable name for the module, consisting of lowercase Latin letters, numbers, dashes, and the '/' symbol (indicating nesting). There is an option to override the original module files used during generation.
Structure of the module after creation (if there was no modules folder previously, the console command will create it in the project root):
The main.php file can contain settings similar to the /config/main.php file but with values used only in the module, meaning it will "override" them.
Initially, the main.php file contains no settings; all settings from /config/main.php are used.
Similarly, settings in the /config/database.php can be replaced by creating a file with the same name.
Settings of other configuration files always act globally.
The module controller is similar to the standard controller of the framework. When using the view() function, the path to the template will point to the module's 'views' folder, as it does for all built-in framework functions for template work.
There is an option to group modules into collections nested in different subfolders within /modules/. For this, modules are placed one level down, and the module name includes the group name. This creates a second level of module nesting.
Let's assume we need to place a module group named 'main-product', which will contain the modules 'first-feature' and 'second-feature'.
This is how it will look in the route map:
In the group named 'first-feature', there is a reassignment of settings, including for databases.
The example for 'second-feature' uses global settings, additionally, it has middleware for the controller.
It is possible that more controllers may appear there.
Similarly, a structure is created for the third level of nesting if it is necessary.
Initially, the folder with modules is called 'modules'; before creating modules, you can change this name in the settings, for example, to 'products'.
This is done in the file /config/system.php - setting 'module.dir.name'.
If the change is made with already existing module classes, you need to correct the namespace for modules that are PSR-0 compliant.
In a module, two configuration files can be overridden - /config/main.php and /config/database.php.
The values of the parameters are overridden recursively by key; otherwise, the parameter has a global value. New parameters that have no global counterpart will be available locally within the module.
When using modules as separate packages, it is not always necessary for the package to include View templates, as styling and result output may be a separate layer in the application structure.
Therefore, there can be two options for using templates.
"Using" refers to pointers to templates in the function view() as well as in special functions like insertTemplate().
If the module has a folder /views/, template paths will point to it.
However, if there is no such folder, the template search will occur in the project's /resources/views/ directory.