Feature: Delegate container for discoverable providers/factories
adrianmiu opened this issue · comments
I am using this library in my some projects and I would like to see this feature added.
Most of the times the container is used to retrieve and instance of a class. For this situations I use another class with the "Factory" suffix which implements an interface like this
interface FactoryInterface
{
/**
* Creates an object based on the alias
* Depending on the needs of the application it can return
* a new object on each invocation or the same object
*
* @param ContainerInterface $container
* @return mixed
*/
public function __invoke(ContainerInterface $container);
}
So, when the container requires the App\Mail\Sender
class, the delegate container looks for App\Mail\SenderFactory
class and uses it to return the object
I have also created another interface that allows a static method for a class to act as the factory.
interface StaticFactoryMethodInterface
{
public static function factory(ContainerInterface $app);
}
In this case the delegate container checks if the class implements this interface and uses it to produce the desired service.
I can implement this feature if you'd like
I'm curious as to what problem this solves over just creating a definition in the container?
Service providers solve a problem that a definition in the container doesn't, right? It lets your app make use of 3rd party packages for once.
However the service providers must be registered. Since these factories would be similar to a single-class provider (ie: 1 provider for 1 class) we can use a naming convention to let the delegate container discover single-class provider so you don't have to manually register them.
Now, your question made think more about it and it seems it would be trivial to implement this auto-discover-ability feature by using the current implementation of providers instead of the factory interface I've proposed. So for the App\Mail\Sender
class you could create a App\Mail\SenderProvider
with the following code
namespace App\Mail;
class SenderProvider extends League\Container\ServiceProvider\AbstractServiceProvider {
protected $provides = ['App\Mail\Sender'];
public function register()
{
$this->getContainer()
->add('App\Mail\Sender')
->addArgument('param1')
->addArgument('param2');
}
}
}