Link Search Menu Expand Document

Package

This is the central class, which will allow you to add multiple Containers, register Modules and use Properties to get more information about your Application.

Aside from that, the Package-class will boot your Application on a specific point (like plugins_loaded) and grants access for other Applications via hook to register and extend Services via Modules.

<?php
Inpsyde\Modularity\Package::new($properties)->boot();

The Package-class contains the following public API:

Package::moduleStatus(): array

Returns an array of all Modules and the current status.

Package::moduleIs(string $moduleId, string $status): bool

Allows to check the status for a given Module::id().

Following Module statuses are available:

Status Description
Package::MODULE_REGISTERED A ServiceModule was added and returned a non-zero number of services.
Package::MODULE_REGISTERED_FACTORIES A FactoryModule was added and returned a non-zero number of factories.
Package::MODULE_EXTENDED An ExtendingModule was added and returned a non-zero number of extension.
Package::MODULE_ADDED Any of the three statuses above applied, or a module implements ExecutableModule
Package::MODULE_NOT_ADDED None of the first three statuses applied for a modules that is non-executable. That might happen in two scenarios: a module only implemented base Module interface, or did not return any service/factory/extension.
Package::MODULE_EXECUTED An ExecutableModule::run() method was called and returned true.
Package::MODULE_EXECUTION_FAILED An ExecutableModule::run() method was called and returned false.

Package::hookName(string $suffix = ‘’): string

Allows to generate the hookName for Package-class (see below)

Package::properties(): PropertiesInterface

Access to Properties.

Package::container(): ContainerInterface

Access to the compiled Container after the booting process is finished.

Package::name():string

A shortcut to Properties::baseName() which contains the name of your Application

Package::addModule(Module $module): self

Allows adding Modules from outside via custom Hooks triggered.

Package::statusIs(int $status): bool

Retrieve the current status of the Application. Following are available:

  • Package::STATUS_IDLE - before Application is booted.
  • Package::STATUS_INITIALIZED - after first init action is triggered.
  • Package::STATUS_BOOTED - Application has successfully booted.
  • Package::STATUS_FAILED_BOOT - when Application did not boot properly.

Access from external

The recommended way to set up your Application is to provide a function in your Application namespace which returns an instance of Package. Here’s a short example of an “Acme”-Plugin:

<?php

declare(strict_types=1);

/*
 * Plugin Name:       Acme
 * Author:            Inpsyde GmbH
 * Author URI:        https://inpsyde.com/
 * Version:           1.0.0
 * Text Domain:       acme
 */

namespace Acme;

use Inpsyde\Modularity;

function plugin(): Modularity\Package {
    static $package;
    if (!$package) {
        $properties = Modularity\Properties\PluginProperties::new(__FILE__);
        $package = Modularity\Package::new($properties);
    }

   return $package;
}

add_action(
	'plugins_loaded',
	static function(): void {
		plugin()->boot();
	}
);

By providing the Acme\plugin()-function, you’ll enable externals to hook into your Application:

<?php

declare(strict_types=1);

namespace FooBarInc;

use Inpsyde\Modularity\Package;

if (! function_exists('Acme\plugin')) {
   return;
}

add_action(
    Acme\plugin()->hookName(Package::ACTION_INIT),
    static function (Package $plugin): void {
       $plugin->addModule(new MyModule());
    }
);

Connecting packages

Every Package has a separate container, however sometimes it might be desirable access another package’s services. For example from a plugin access one library services, or from a theme access a plugin’s services.

That can be done using the Package::connect() method.

For example:

// a theme functions.php

$properties = Properties\ThemeProperties::new('/path/to/theme/dir/');
$theme = Inpsyde\Modularity\Package::new($properties);

$theme->connect(\Acme\plugin());
$theme->boot();

To note:

  • Package::connect() must be called before boot. If called later, no connections happen and it returns false
  • The package to be connected might be already booted or not. In the second case the connection will happen, but before accessing its services it has to be booted, or an exception will happen.

Package connection is a great way to create reusable libraries and services that can be used by many plugins. For example, it might be possible to have a library that has something like this:

namespace Acme;

function myLibrary(): Package {
    static $lib;
    if (!$lib) {
        $properties = Properties\LibraryProperties::new('path/to/composer.json');
        $lib = Inpsyde\Modularity\: Package::new($properties);
        $lib->boot(new ModuleOne(), new ModuleTwo());
    }
    return $lib;
}

This would be autoloaded by Composer, but not being a plugin will not be called by WordPress.

However, many plugins in the same installation could do:

/** @var Package $plugin */
$plugin->connect(\Acme\myLibrary());

Thanks to that, all plugins will be able to access the library’s services in the same way they access own modules’ services.

Accessing connected packages’ properties

In modules, we can access package properties calling $container->get(Package::PROPERTIES). If we’d like to access any connected package properties, we could do that using a key whose format is: sprintf('%s.%s', $connectedPackage->name(), Package::PROPERTIES).

What happens on Package::boot()?

When booting your Application, following will happen inside:

0. Package::statusIs(Package::STATUS_IDLE);

Application is idle and ready to start.

1. Register default Modules

Default Modules which are injected before Package::boot() will be registered first by iterating over all Modules and calling Package::addModule().

2. Package::ACTION_INIT

A custom WordPress action will be triggered first to allow registration of additional Modules via Package::addModule() by accessing the Package-class. Application will change into Package::STATUS_INITIALIZED afterwards.

Newly registered Modules via that hook will be executed after the default Modules which are injected before the Package::boot()-method.

3. Compile read-only Container

The default primary PSR-Container is generated by the ContainerConfigurator by injecting all Factories, Extension and child PSR-Containers into it.

4. Execute all ExecutableModules

After collecting all ExecutableModules, the Package-class will now iterate over all ExecutableModules and execute them by injecting the default primary PSR-Container.

5. Package::ACTION_READY

Last but not least, Package::boot() will trigger custom WordPress Action which allows you to access the Package-class again for the purpose of debugging all Modules.

6. Done

The package was either successfully booted and state changed to Package::STATUS_BOOTED or failed booting due some exceptions and state was changed to Package::STATUS_FAILED_BOOT.