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