Releases: inpsyde/modularity
v1.10.0
What's Changed
New generic "init" hook
Before this release, the only way to act on the container to register services and such was a package-scoped init hook, a hook whose name is composed of a prefix plus the package's slug.
That meant one would need an instance of the package to be able to register services to that package.
As highlighted in #47, this was limiting when wanting to act "programmatically" act on multiple packages, e.g., all packages belonging to a specific project.
Moreover, even if the package creates a function to access its main Package
instance, we can never be sure the package is available (e.g., a plugin could be deactivated), so we need to rely on function_exists
and still always rely on other packages' developers to declare the function in the first place.
The newly introduced "static" Package::ACTION_MODULARITY_INIT
action hook allows developers to access all Modularity package initialization. It is up to consumers to determine whether they need to interact with that package or not. The hook passes the package slug as the first parameter to make it as easy and "cheap" as possible.
Package statuses and action hooks refactoring for completeness and consistency
Since the addition of Package::build()
(version 1.7.0), we have a pretty clear separation of two "phases" in the Package
lifecycle: the "building" and the "booting" phase.
However, the Package
statuses did not describe the phases in detail. For example, we had no status to describe when the "building" phase was completed, which is relevant because, at that point, it was already safe to access the container.
Besides that, we did not have enough hooks to access the container at relevant statuses.
For this reason, we decided to have a complete status list, plus actions at any relevant point. Some of the statuses and some of the action hooks were renamed (in a backward-compatible way) to ensure better consistency and a consistent "mapping" of statuses with related action hooks.
Now, we have a status to represent all relevant milestones of the Package
lifecycle and a way to hook at the most convenient place for different scopes. Moreover, we have a much more consistent naming of statuses and action hooks.
Status | Description | Action hook |
---|---|---|
STATUS_IDLE |
The package is just created. | No action hook |
STATUS_INITIALIZING |
The "building" phase is started. | ACTION_INIT hook can be used to register and extend services. |
STATUS_INITIALIZED |
The "building" phase is completed. | ACTION_INITIALIZED hook can be used to access services. |
STATUS_BOOTING |
The "booting" phase is started. | No action hook |
STATUS_BOOTED |
The "booting" phase is completed. | ACTION_BOOTED hook can be used to act on container after all executables services have been executed. |
STATUS_DONE |
Package lifecycle has completed successfully. | No action hook |
More flexible status checking and additional Package
API
Before this release, the only way to check a Package
's status was the Package::statusIs()
method. Often, even internally to Modularity, we wanted to check whether the Package
was at least at a given status. That meant checking the status at hand plus all the previous statuses and the "failed" status.
The new Package::hasReachedStatus()
and Package::hasFailed()
methods make these sorts of checks much easier and more reliable.
Moreover, the new Package::hasContainer()
method makes it possible and easy to determine if a Container is already available.
Package::boot()
and Package::build()
idempotency
Starting from this release, calling Package::build()
or Package::boot()
multiple times is eventless. We don't expect package authors to do that on their Package
instance. However, when holding an instance of another package, e.g. a connected package, it might be desirable to ensure it is built or booted. In such cases, an error was raised in previous versions. Now, there's no error, making it easy and safe to call, for example, Package::build()
to ensure a Package is built doing nothing in the case it already was.
Improvements around package connection
This release does nothing regarding how package connection works. However, due to the abovementioned changes, package connection has become more effective.
The PackageProxyContainer
was used when a package to connect was not "ready" yet was used more than needed. That was because it was impossible to precisely check the status of the Package
or if a container was already created. With the new Package
API and the new statuses, that is now possible, so the PackageProxyContainer
is not used only when strictly necessary.
Finally, when a package connection failed, an exception was immediately thrown. It is common to connect packages early in the application flow, but often, services from connected packages are accessed enough time later. It might have happened that an exception for a failed connection was raised early, even if, in that request, no services from connected packages were accessed. For example, because of a redirect, a hook removed, or any other reason. With this release, no immediate failure happens on a failed connection (a failure action hook is fired). Then, when a service from the expectedly connected package is accessed, that will fail because of the failed connection, and so an error will be thrown at the latest possible time when there is no alternative.
With all the changes above, plus the Package::boot()
and Package::build()
idempotency, using package connections to build cross-package relations is easier, safer, and more efficient.
Tests
Many new tests have been added to cover all newly added or updated functionalities.
Documentation
Even if there's still room for improvement, some effort has been made to improve documentation, especially in the range of the application flow and of the Package
class API and lifecycle.
Besides the user documentation, extensive inline documentation has been added to explain why many parts of the code are they way they are. This should be very useful for future maintainers as well as for integrators.
Deprecations
- The
Package::STATUS_MODULES_ADDED
constant has been deprecated and replaced byPackage::STATUS_BOOTING
- The
Package::ACTION_READY
constant has been deprecated and replaced byPackage::ACTION_BOOTED
- The
Package::ACTION_FAILED_CONNECTION
constant has been deprecated and replaced byPackage::ACTION_FAILED_CONNECT
Full Changelog: 1.9.0...1.10.0
1.9.0
1.8.0
Introduce service extensions by type
The ExtendingModule::extensions(): array
will allow you to return an array of Extensions for your Services. Those Extensions will be added to your Services after registration. Each Extension will return a callable function which will receive the original Service and the primary Container (read-only).
Sometimes it is desirable to extend a service by its type. Extending modules can do that now as well:
<?php
use Inpsyde\Modularity\Module\ExtendingModule;
use Psr\Log\{LoggerInterface, LoggerAwareInterface};
class LoggerAwareExtensionModule implements ExtendingModule
{
public function extensions() : array
{
return [
'@instanceof<\Psr\Log\LoggerAwareInterface>' => static function(
LoggerAwareInterface $service,
ContainerInterface $c
): ExtendedService {
if ($c->has(LoggerInterface::class)) {
$service->setLogger($c->get(LoggerInterface::class));
}
return $service;
}
];
}
}
This code will extend all Services which implement the Psr\Log\LoggerAwareInterface
-interface automatically.
Read more about the changes here: https://github.com/inpsyde/modularity/blob/1.8.0/docs/Modules.md#extending-by-type
psalm-types for complex service/extension/factory type hints
There were 2 new pslam-types
introduced and centralized to reuse them in several places via pslam-import-type
:
Service
-->callable(ContainerInterface $container):mixed
ExtendingService
->callable(mixed $service, ContainerInterface $container):mixed
Misc
Full Changelog: 1.7.4...1.8.0
1.7.4
1.7.3
1.7.2
ThemeProperties
- Fix referencing nonexistent header theme properties in
Inpsyde\Modularity\Properties\ThemeProperties
- see #38
QoL
- Fix PHPUnit tests not running in CI and failing test - see #37
- php-qa.yml // make use of
inputs.PHP_VERSION
props @meszarosrob @Chrico
1.7.1
1.7.0
Introduce Package::build()
The new method allows building a container out of the package without running any ExecutableModule::run()
, simplifying unit tests.
Passing default modules to Package::boot()
is now deprecated, for a better separation of the "building" and "booting" steps, but it continues to work while emitting a deprecation notice.
There's an edge case in which passing modules to Package::boot()
causes an exception, but one of the conditions is that Package::container()
was called before Package::boot()
which caused an exception before anyway, so the change is 100% backward compatible.
Two new package statuses have been added:
Package::STATUS_MODULES_ADDED
Package::STATUS_READY
The first is necessary to distinguish the status after build()
was called but boot()
was not. The second was a missing status between initialized and ready.
Documentation and tests were added: /docs/Applicaton-flow.md
QoL
- Update for phpunit with it's dependencies to 8 to 9 and correctly work with PHP8.*.
PluginProperties
- Add
PluginProperties::pluginMainFile()
method. - Fix plugin active state detection
1.6.1
1.6.0
Upgrade php-fig/container
to ^1.1.0 || ^2
This release will drop the support for php-fig/container
in version 1.0.0
. The new minimum required version is ^1.1.0 || ^2
.
This will also add support for typehints on ContainerInterface::get(string $id)
and ContainerInterface::has(string $id): bool;
.
QoL
- Introduce usage of
inpsyde/reusable-workflows
. (30246f9) - Update
psalm.xml
to remove the deprecatedtotallyTyped
attribute. (9b5c157) - Unify "inpsyde.com" spelling. (fde75bc)
- Improve documentation examples. (65bc3f8)
- Improve naming of parameters in
Package::moduleProgress()
(7284b74)
Props to @gmazzap @widoz @tyrann0us @nullbytes @Chrico