Skip to content

Releases: inpsyde/modularity

v1.10.0

03 Sep 12:51
2119d0e
Compare
Choose a tag to compare

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 by Package::STATUS_BOOTING
  • The Package::ACTION_READY constant has been deprecated and replaced by Package::ACTION_BOOTED
  • The Package::ACTION_FAILED_CONNECTION constant has been deprecated and replaced by Package::ACTION_FAILED_CONNECT

Full Changelog: 1.9.0...1.10.0

1.9.0

27 Aug 08:02
d4ea195
Compare
Choose a tag to compare

What's Changed

  • Services on connected packages can now be retrieved after build(). See #49 Props @gmazzap

  • Improved QA. More tests were added, and better static analysis checks in automated workflows. Props @gmazzap


Full Changelog: 1.8.0...1.9.0

1.8.0

14 May 06:14
c6855a6
Compare
Choose a tag to compare

Introduce service extensions by type

by @gmazzap in #44

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

by @Chrico in #46

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

22 Mar 07:03
ef0143d
Compare
Choose a tag to compare

What's Changed

  • PluginProperties: Add support for Requires Plugins header by @tfrommen in #41

Full Changelog: 1.7.3...1.7.4

1.7.3

07 Mar 13:45
df169cb
Compare
Choose a tag to compare

What's Changed


Full Changelog: 1.7.2...1.7.3

1.7.2

16 Nov 11:22
43f4b3a
Compare
Choose a tag to compare

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

03 Jul 15:57
20f81d9
Compare
Choose a tag to compare

What's Changed

  • Remove unnecessary and expensive hasService check by @tfrommen in #36

Full Changelog: 1.7.0...1.7.1

1.7.0

26 May 10:08
0bde4d1
Compare
Choose a tag to compare

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

props to @gmazzap @shvlv @esurov @Biont @Chrico

1.6.1

16 Feb 09:38
eb14a9b
Compare
Choose a tag to compare

Fix child theme base path property

  • fix: Use get_stylesheet_directory instead of get_template_directory
  • chore: Update ThemeProperties test

See more details in #27


props to @o-samaras

1.6.0

03 Feb 12:59
dd2ac0d
Compare
Choose a tag to compare

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


Props to @gmazzap @widoz @tyrann0us @nullbytes @Chrico