Since I want to keep things clear and easy to follow, the DI containers that I plan to build in the next few lines will be simple factories. They will implement the following interface: (MyApplication/Injector/InjectorInterface.php) <?php namespace MyApplicationInjector; interface InjectorInterface Definitely, the contract defined by the “InjectorInterface” interface doesn’t bear any further discussion. So move on and take a close look at the implementer below. It is a factory that creates a Singleton instance of the previous MySQL adapter (you remember that one, right?): (MyApplication/Injector/MysqlAdapterInjector.php) <?php namespace MyApplicationInjector; class MysqlAdapterInjector implements InjectorInterface /** There’s no need to be a rocket scientist to grasp the logic behind the “MysqlAdapterInjector” class. As you can see, it simply implements the “create()” method defined by the earlier interface to return to client code a Singleton of the aforementioned MySQL adapter. With this low-level factory already up and running, it’s really easy to create another one that spawns valid user service objects. Skeptical? Then take a peek at the following class, which should change your mind quickly: (MyApplication/Injector/UserServiceInjector.php) <?php namespace MyApplicationInjector; class UserServiceInjector implements InjectorInterface There you have it. In a few easy steps, I implemented a basic DI container, which is capable of creating instances of the previous user service class by injecting the corresponding dependencies at the appropriate places. Of course, similar results can be obtained with an “automated” container that uses reflection internally to figure out what collaborators must be injected into a specific object. In this case, though, I decided to stick with the so-called poor man’s dependency injection, since the number of object graphs that need to be created is really small. So far, so good. At this point, I’m sure that you've grasped how the pair of DI containers do their things. So, the next step is to build a helper that permits us to abstract away the creation of a specified service (including the one that you saw in the preceding section). The definition of this brand new helper will be shown in the next segment, so keep reading. Giving the final touches to the service layer: creating a service helper Frankly speaking, the creation of a helper class that allows you to retrieve (and also inject) a specified service is entirely optional. However, the convenience of having such a class at our disposal is that it can be used either for pulling in or out model data in an action controller or in a view, when working with an MVC stack. Having clarified that point, here’s the code for this helper: (MyApplication/Service/ServiceLocator.php) <?php namespace MyApplicationService; class ServiceLocator /** /** /** /** /** /** /** /** /**
(MyApplication/Service/ServiceLocatorException.php) <?php namespace MyApplicationService; class ServiceLocatorException extends Exception{} From the above code fragment, it’s clear to see that the previous “ServiceLocator” class behaves like a static registry. This permits us to save and retrieve services and DI containers (called injectors in this case) via a set of convenient methods. Nevertheless, the most interesting aspect of this class is the implementation of its “getService()” method. It follows a simple naming convention to retrieve a specified service. For instance, if the requested service is called “user,” the method will first look in the registry to see if the service has been created, and will return it to client code. Otherwise, it’ll attempt to find an associated injector called “UserServiceInjector,” which will be used (when possible) to create the pertinent service. Do you understand the inner workings of the helper? Great. And now that you've grasped how this class functions, we're finally ready to put this sample user service to work for us. However, to see the service’s actual functionality, you’ll have to wait until the next tutorial. Final Thoughts In this penultimate chapter of the series, I put the final touches on the previous service layer. I added to it a couple of basic dependency injection containers, along with a static helper. These can be used by client code -- and by client code, I mean anything that can consume the layer in question, including action controllers and views in an MVC schema -- to construct a specified service in a valid state. With this additional step, we've finally set the scene to see the service's abilities in action. So, make sure to tighten your seatbelts and be ready to be confronted with a bunch of code samples, as this process will be conducted in the last tutorial. Don’t miss it!
blog comments powered by Disqus |
|
|
|
|
|
|
|