Caution
The documentation you are viewing is for an older version of this component.
Switch to the latest (v3) version.
Features
Modular applications
Zend Framework 2+ applications have a concept of modules, independent units that can provide configuration, services, and hooks into its MVC lifecycle. This functionality is provided by zend-modulemanager.
Expressive provides similar functionality by incorporating two packages within the default skeleton application:
- zendframework/zend-config-aggregator,
which provides features for aggregating configuration from a variety of
sources, including:
- PHP files globbed from the filesystem that return an array of configuration.
- zend-config-compatible configuration files globbed from the filesystem.
- Configuration provider classes; these are invokable classes which return an array of configuration.
- zendframework/zend-component-installer,
a Composer plugin that looks for an
extra.zf.config-provider
entry in a package to install, and, if found, adds an entry for that provider to theconfig/config.php
file (if it uses zend-config-aggregator).
These features allow you to install packages via composer and expose their configuration — which may include dependency information — to your application.
Making your application modular
When using the Expressive installer via the skeleton application, the first question asked is the installation type, which includes the options:
- Minimal (no default middleware, templates, or assets; configuration only)
- Flat (flat source code structure; default selection)
- Modular (modular source code structure; recommended)
We recommend choosing the "Modular" option from the outset.
If you do not, you can still create and use modules in your application; however, the initial "App" module will not be modular.
Module structure
Expressive does not force you to use any particular structure for your module; its only requirement is to expose default configuration using a "config provider", which is simply an invokable class that returns a configuration array.
We generally recommend that a module have a PSR-4
structure, and that the module contain a src/
directory at the minimum, along
with directories for other module-specific content, such as templates, tests, and
assets:
src/
Acme/
src/
ConfigProvider.php
Container/
VerifyUserFactory.php
Helper/
AuthorizationHelper.php
Middleware/
VerifyUser.php
templates/
verify-user.php
test/
Helper/
AuthorizationHelperTest.php
Middleware/
VerifyUserTest.php
If you use the above structure, you would then add an entry in your
composer.json
file to provide autoloading:
"autoload": {
"psr-4": {
"Acme\\": "src/Acme/src/"
}
}
Don't forget to execute composer dump-autoload
after making the change!
Creating and enabling a module
The only requirement for creating a module is that you define a "config provider", which is simply an invokable class that returns a configuration array.
Generally, a config provider will return dependency information, and module-specific configuration:
namespace Acme;
class ConfigProvider
{
public function __invoke()
{
return [
'dependencies' => $this->getDependencies(),
'acme' => [
'some-setting' => 'default value',
],
'templates' => [
'paths' => [
'acme' => [__DIR__ . '/../templates'],
],
]
];
}
public function getDependencies()
{
return [
'invokables' => [
Helper\AuthorizationHelper::class => Helper\AuthorizationHelper::class,
],
'factories' => [
Middleware\VerifyUser::class => Container\VerifyUserFactory::class,
],
];
}
}
You would then add the config provider to the top (or towards the top) of your
config/config.php
:
$aggregator = new ConfigAggregator([
Acme\ConfigProvider::class,
/* ... */
This approach allows your config/autoload/*
files to take precedence over the
module configuration, allowing you to override the values.
Caching configuration
In order to provide configuration caching, two things must occur:
- First, you must define a
config_cache_enabled
key in your configuration somewhere. - Second, you must pass a second argument to the
ConfigManager
, the location of the cache file to use.
The config_cache_enabled
key can be defined in any of your configuration
providers, including the autoloaded configuration files. We recommend defining
them in two locations:
config/autoload/global.php
should define the value totrue
, as the production setting.config/autoload/local.php
should also define the setting, and use a value appropriate to the current environment. In development, for instance, this would befalse
.
// config/autoload/global.php
return [
'config_cache_enabled' => true,
/* ... */
];
// config/autoload/local.php
return [
'config_cache_enabled' => false, // <- development!
/* ... */
];
You would then alter your config/config.php
file to add the second argument.
The following example builds on the previous, and demonstrates having the
AppConfig
entry enabled. The configuration will be cached to
data/config-cache.php
in the application root:
$configManager = new ConfigManager([
App\AppConfig::class,
new PhpFileProvider('config/autoload/{{,*.}global,{,*.}local}.php'),
], 'data/config-cache.php');
When the configuration cache path is present, if the config_cache_enabled
flag
is enabled, then configuration will be read from the cached configuration,
instead of parsing and merging the various configuration sources.
Final notes
This approach may look simple, but it is flexible and powerful:
- You pass a list of config providers to the
ConfigAggregator
constructor. - Configuration is merged in the same order as it is passed, with later entries having precedence.
- You can override module configuration using
*.global.php
and*.local.php
files. - If cached config is found,
ConfigAggregator
does not iterate over provider list.
For more details, please refer to the zend-config-aggregator documentation.
Found a mistake or want to contribute to the documentation? Edit this page on GitHub!