If you’ve been an insightful observer from the very first article, then you've realized that the brave warrior driving the forces of this ORM is…yes, dependency injection. To keep all of the code clean and uncluttered, however, the creation of object graphs must be encapsulated behind some low-level factories and dependency injection containers, thus keeping object instantiation isolated from application logic. To accomplish this objective, I’m going to appeal to the functionality of a manual dependency injection container (AKA a poor man’s DIC) and the one provided by a simple factory class, to create the previous MySQL adapter and a service that will run CRUD operations in domain objects. Here are the classes that perform all of these tasks, along with the interface that they implement: (Blog/Injector/InjectorInterface.php) <?php namespace Blog\Injector; interface InjectorInterface
(Blog/Injector/MysqlAdapterInjector.php) <?php namespace Blog\Injector; class MysqlAdapterInjector implements InjectorInterface /**
(Blog/Injector/EntryServiceInjector.php) <?php namespace Blog\Injector; class EntryServiceInjector implements InjectorInterface The code fragment above speaks for itself. It defines a low-level factory, which is responsible for creating a Singleton instance of the aforementioned database adapter (in fact, this factory is optional, as it’s possible to eliminate this Singleton by using only dependency injection). After doing that, it shows the implementation of a simple DIC, which gathers in one single place all the collaborators required for building a service layer that handles blog entries. Of course, at this time you may be wondering how this still-undefined service looks. Check the following snippet, which shows the originating classes of the service: (Blog/Service/AbstractService.php) <?php namespace Blog\Service; abstract class AbstractService /** /** /** /** /** /**
(Blog/Service/EntryService.php) <?php namespace Blog\Service; class EntryService extends AbstractService There you have it. As you can see above, the service layer is composed of a simple hierarchy of classes that act like wrappers for the mappers defined previously. This provides a single “catch-all” point, which allows you to encapsulate all of the functionality required for manipulating blog entries and their associated entities -- that is, comments and authors. Finally, to provide the ORM with a more flexible structure that enables us to work with multiple services (aside from the one that you just saw), below I included a simple service locator class. It allows you to create on request a specified service by using its associated dependency injection container. Check it out: (Blog/Service/ServiceLocator.php) <?php namespace Blog\Service; class ServiceLocator Mission accomplished. With this service locator up and running, we’ve come to the long-awaited moment when we’ll be able to see the ORM in action! Of course, first it’s necessary to create some MySQL tables and populate them with some sample blog entries, their associated comments and the corresponding authors. So, here are the tables:
As shown above, each blog post has effectively caught the attention of a few picky users, even though at disparate levels. Naturally, the most interesting facet of this process is demonstrating whether or not the ORM is capable of handling the data stored in the tables and maintaining the relationships that exist between the involved entities. Well, the following script hopefully will make your doubts disappear: <?php use \Blog\Library\Loader\Autoloader as Autoloader, // include the autoloader // create the service locator // add the entry service injector to the service locator // get the entry service via the associated service injector // display all the entries along with their associated comments (comments are lazy-loaded from the storage) // add a new entry to the storage // delete an entry from the storage That worked like a charm! As the above code fragment shows, running CRUD operations on the tables created before is a breeze, thanks to the functionality provided by the blog entry service. Moreover, if you test the script on your own machine (provided that you’ve defined the sample tables, too), you should get the following output:
Not too bad at all, right? Not only have the blog entries been properly fetched from the database, but the related comments and authors have been loaded on request. Even though this example is somewhat contrived, it demonstrates that building an extendable, object-oriented ORM in PHP is much simpler than one might think. So, feel free to play with it for a while and tweak it to suit your own requirements. Final Thoughts In this tutorial, I showed that the implementation of a customizable ORM using modern development techniques is a fairly straightforward process that can be tackled with minor efforts. As you just saw, exploiting the benefits brought by dependency injection, and the use of the data mapper pattern along with a domain model (even an anemic one) is a powerful combination that allows you to manipulate relationships between entities with relative ease. Naturally, if your needs are closer to the level of an enterprise, a full-blown ORM like Doctrine can be the best solution. In either case, learning how to create a library like the one above, even in its simplest version, has hopefully been a didactic, and why not, fun experience. See you in the next PHP tutorial!
blog comments powered by Disqus |
|
|
|
|
|
|
|