Injecting Service Collections with Annotated Container
The ability to inject a collection of services using idiomatic Annotated Container code has long been a desire of mine. In fact, Annotated Container's oldest open issue (at the time of this posting) tracks this exact feature. The issue is 2+ years old and originally targets the v0.3 release of Annotated Container. Sadly, every time I tried to implement this feature in the past I ran into a seemingly insurmountable hurdle. This was compounded by the fact I want to maintain feature parity across the different Container libraries that are supported.
Finally, after a change in how I was approaching a solution and a deep dive into each of the supported Containers, I managed to find an implementation that solves all of my wants for this feature! In the below example we'll take a look at how we can inject collections of services.
Injecting Array of Services
With how ubiquitous the array
is in PHP, injecting an array of services is bound to be a common use-case.
Let's assume we have the following code:
In Annotated Container prior to 2.4 it was extremely difficult to satisfy this requirement. None of the options
are very good. If you used a #[ServiceDelegate]
, a way to mark a method as a factory for your services, you'd
still need to know which implementations to use in the collection. The Observer system allowed for fetching collections of services, but it was only after the object had
been created.
In versions 2.4 and above, you can now use the #[Inject]
attribute and implementations of a new interface,
Cspray\AnnotatedContainer\ContainerFactory\ListOf
to support injecting collections in constructor parameters!
After 2.4, we can make the following adjustment to our WidgetDashboard
implementation.
The new functionality comes where we're passing in an instance of ListOfAsArray
, with the class type that we expect to be injected into this parameter. From an end user's perspective, that's basically it! Whatever
services are defined that implement the Widget
interface will be part of the injected array.
Injecting Custom Collection of Services
What if you don't pass around arrays and have a custom, type-safe collection object? No worries, Annotated Container's new feature supports this use case as well! Let's assume that our widget example looks like the following instead:
To support this use case we can use similar functionality as the array use case, but we'll have to provide our own implementation of ListOf
. This is what that might look like:
In this scenario, we get our WidgetCollection
injected thanks to our new ListOf
implementation. With the
provided ListOfAsArray
or your own custom ListOf
implementation a variety of use cases for injecting a
collection of services can be satisfied. I anticipate releasing Annotated Container 2.4 over the next few days
and will be sure to make use of this feature in my own apps.
Happy dependency injection!