Implementing custom Plugin types
Though we believe that the built-in Plugin types will satisfy the majority of use cases it is possible that you need to implement plugin-like functionality that isn't covered by any of the existing interfaces. In that case you should implement your own Plugin interface and adjust your Application to properly load it.
In our example we're going to create a ConfigurationPlugin
that allows different configuration values to be set during
the Plugin loading process and unset when the Plugin is removed. In the example below we'll assume that the Acme\Configuration
type is already implemented.
Step 1 - Implement your new interface
<?php
namespace Acme;
use Amp\Promise;
use Cspray\Labrador\Plugin\Plugin;
interface ConfigurationPlugin extends Plugin {
public function setConfiguration(Configuration $configuration) : Promise;
public function unsetConfiguration(Configuration $configuration) : void;
}
Step 2 - Adjust the Application to load your Plugin
During the Plugin loading process, which we cover in more detail in [Deep Dive: Plugins][plugins-deep-dive], you can
run your own custom code for specific Plugin types. Just add the appropriate closuers to the Application
in your
bootstrapping code.
<?php
namespace Acme;
use Cspray\Labrador\DependencyGraph;
use Cspray\Labrador\Engine;
use Amp\Log\StreamHandler;
use Monolog\Logger;
use function Amp\ByteStream\getStdout;
$logger = new Logger('labrador.code-example');
$logger->pushHandler(new StreamHandler(getStdout()));
$injector = (new DependencyGraph($logger))->wireObjectGraph();
$app = $injector->make(MyApplication::class);
$config = $injector->make(Configuration::class);
$app->registerPluginLoadHandler(ConfigurationPlugin::class, function(ConfigurationPlugin $configurationPlugin) use($config) {
$configurationPlugin->setConfiguration($config);
});
$app->registerPluginRemoveHandler(ConfigurationPlugin::class, function(ConfigurationPlugin $configurationPlugin) use($config) {
$configurationPlugin->unsetConfiguration($config);
});
$engine = $injector->make(Engine::class);
$engine->run($app);
The important part to note here is that we're registering both a load and remove handler for any Plugin that implements
the ConfigurationPlugin
. During the Plugin loading process if the plugin implements ConfigurationPlugin
it'll be
passed into your callback. The return value of your loading handler should be a Promise
or null. There should be
no return value for remove handlers.
Step 3 - Register implementations of your new plugin type
Now the only thing we need to implement the new type and register it with our Application.
<?php
namespace Acme;
use Amp\Promise;
use function Amp\call;
class MyConfigurationPlugin implements ConfigurationPlugin {
public function setConfiguration(Configuration $configuration) : Promise {
return call(function() use($configuration) {
// we could load something from a file or network call
$configuration->set('foo', 'bar');
});
}
public function unsetConfiguration(Configuration $configuration) : void {
$configuration->unset('foo');
}
}
// All the code in your bootstrap file to get your Application created
$app->registerPlugin(MyConfigurationPlugin::class);