auryn
auryn copied to clipboard
Multiple injector instances with shared dependencies
I've been looking to all issues, but it seems like this question hasn't been asked yet.
First of all, I didn't try this library yet: I saw it mentioned and thought it might be helpful for my work.
However, I need to understand something before even starting playing with it.
Scenario: WordPress plugin development, with a main plugin + n add-ons (as separate plugins).
The main plugin has a "main" class. Some of the other add-ons classes may need to use the main class as a depenendecy.
The main class should not be instantiated multiple times.
Now, I guess I could store an instance of Auryn\Injector
as a global variable and use that global variable with all other add-ons, but I don't want to use globals (I don't think I need to explain why) if there are better options.
I wonder if, setting a dependency as shared and creating multiple instances of Auryn\Injector
(which is most likely what I would need to do anyway if I don't want to use the global variable approach) I would still be able to use this shared dependency.
I've thought about this problem, and although it's a perfectly valid thing to want to do, I haven't been able to come up with a solution internal to this library that wouldn't be one of:
i) Far too complicated. ii) Far too difficult to use. iii) Not covering enough use-cases. iv) all of the above.
For most of the valid but complex use-cases people have asked about, normally they can be solved by extending the Injector, and putting that complex logic in the make()
method.
I think something along these lines should work for you:
$mainPluginInjector = new Injector();
// Configure the $mainPluginInjector here.
$mainPluginInjector->share(MainPlugin::class)
$upstreamClasses = [
MainPlugin::class,
MainLogger::class
];
$pluginInjector = new DownstreamInjector($injector, $upstreamClasses);
// configure $pluginInjector here.
// $pluginInjector is now ready to use.
class DownstreamInjector extends Injector {
private $upstreamInjector;
private $upstreamClasses = [];
function __construct(Injector $upstreamInjector, array $upstreamClasses, Reflector $reflector = null) {
parent::__construct($reflector)
}
public function make($name, array $args = array()) {
// Arbitrarily complex logic could go here.
if (in_array($name, $this->upstreamClasses, true) === true) {
return $this->upstreamInjector->make($name, $args);
}
return parent::make($name, $args);
}
}
If it doesn't feel free to specify your requirements a bit more clearly. Although a solution is unlikely to be added to this library itself, there's probably a not too complex way of doing it yourself.
If I understand well this should work:
// main-plugin.php
add_action( 'plugin_loaded', function () {
$injector = new \Auryn\Injector();
$injector->make( 'MyPlugin\MainClass' );
// do some other stuff with $injector obj
add_filter( 'my_plugin_get_injector_instance', function() use ( $injector ) {
return $injector;
} );
} );
// Then in the add-on plugin you can
add_action( 'plugin_loaded', function () {
$injector = apply_filters( 'my_plugin_get_injector_instance', null );
if ( ! $injector ) {
// do some stuff or return
}
$injector->make( 'MyAddon\ClassWithMainClassDependency' );
}, 11 );
// ClassWithMainClassDependency.php
namespace MyAddon;
use MyPlugin\MainClass;
class ClassWithMainClassDependency {
__constructor ( MainClass $obj ) {
$this->main_class = $obj;
}
}
It's probable I misread the question. But I've now added some words in commit f93349d5dd98399aa0ac69d2c62ba7cc93e2f3b1
When app-bootstrapping by Auryn is not possible
Sometimes, the initialisation of the application is outside of your control. One example would be writing plugins for Wordpress, where Wordpress is initialising your plugin, not the other way round.
You can still use Auryn by using a function to make a single instance of the injector:
function getAurynInjector()
{
static $injector = null;
if ($injector == null) {
$injector = new \Auryn\Injector();
// Do injector defines/shares/aliases/delegates here
}
return $injector;
}