While proxy objects can be utilized in a variety of situations and environments, they yield excellent results when lazy-loading data from an application’s persistence layer (usually this layer is seated upon a RDBMS, but it could be a web service or anything else). With the progressive adoption in the PHP field of Domain-Driven Design methodologies, the use of proxies for loading and reconstituting collections of domain objects on request from the underlying storage can help in the implementation of more efficient persistence strategies. This is true despite the need in some cases to create a few additional abstraction layers, like data mappers, repositories and even services. It's relatively easy to use the capabilities of proxies and lazy-load sets of entities from a database, even in the most simple use cases. Indeed, in the two previous parts of this tutorial, I started building an extendable blog program. It used a couple of proxy classes to pull, from a MySQL table, the comments related to a particular blog entry. Unfortunately, the blog in its current state isn’t entirely functional. It's necessary to add to it a simple service layer. With this layer, all of the logic required by the interaction between the mappers and the database can be neatly encapsulated behind a cleaner and uncluttered API. In this final installment, I’ll set up this additional layer, thus finishing the sample blog program. Now, it’s time to continue learning how to make proxy objects work for us in PHP. Let’s jump in! Adding a service layer to the blog In reality, adding a service layer to the blog’s existing structure is optional, as it’s possible to demonstrate the functionality of proxies without implementing this extra abstraction tier. However, since I want to keep all the logic required to perform CRUD operations on blog entries hidden behind a single entry point, accessible to different front-ends, I’ll be bold and bring this layer to life anyway. Having said that, this is the class that will make the service work. Take a close look at it: (MyApp/Service/EntryService.php) <?php namespace MyApp\Service; class EntryService As you can see above, this new class is a basic wrapper for the previous entry mapper, which can fetch, save, and remove entries from the database. At first glance, it looks like a repository; it can deal with aggregate roots (the blog entries). Keep in mind, however, that it can be easily extended to perform many other tasks with the involved domain objects, such as representing them in XML, emailing them, or whatever comes to mind. If you understand how the service works, the next step is to create a simple dependency injection container (DIC). This container will take care of spawning (in this case manually) the service’s object graph in a snap. To do this, I’ll make the container an implementer of the following interface: <?php namespace MyApp\Service; interface InjectorInterface That was simple to code and read, right? So, move on and take a look at the originating class of the aforementioned DIC: (MyApp/Service/EntryServiceInjector.php) <?php namespace MyApp\Service; use MyApp\Model\Mapper, class EntryServiceInjector implements InjectorInterface As the above code fragment shows, the “EntryServiceInjector” class's responsibility is to build the graph corresponding to the previous entry service. As I said before, in this case all the dependencies are injected manually; even so, implementing this DIC helps to separate object instantiation from application logic, which is a good programming practice. So far, so good. At this point, the blog’s service layer is finally ready for some real action. However, there’s one more thing that I’d like to do. Since the blog might be coupled with an existing MVC stack (for instance, the infrastructure provided by a framework from the many available out there), it’d be helpful to create a basic helper. This helper would allow you to create the service on request, and can be consumed easily within an action controller. The helper's definition will be shown in the next section.
blog comments powered by Disqus |
|
|
|
|
|
|
|