2016-10-13

For the last couple weeks, I’ve talked about creating database abstractions. In the first article, I spoke about the need for creating a high-level API, on top of standard WordPress APIs to act as a CRUD interface for your projects. The second was about using classes with all static methods for validation and storage of options. In part three, I want to talk about dependency injection and illustrate the value of this concept by offering a different way to create a database abstraction than I did before.

What I showed in the last article works for its purpose. But, that system was strongly coupled to the options API and required a new class declaration for each option. Because of the use of class inheritance, there is little redundancy in code, but that approach has limited usage.

What Is Dependency Injection

Before we begin, we must go over what a dependency injection is.

Basically, it is a fancy sounding term that just means that a class takes the data it needs to function from outside of the class, instead of constructing this data itself. Dependency injections are helpful for several reasons.

A dependency injection encourages following the single responsibility principle. You might think “this class outputs popular posts in the footer of a post” when it actually assembles a WP_Query object based on the current HTTP request, queries the database, and outputs some HTML on the_content filter.

That’s a lot of responsibilities for one class. Here is the kind of class I’m talking about:

This class does not use dependency injection. As a result, it’s basically impossible to write a unit test for this class. Also, if you wanted to add AJAX based pagination, you’d be in trouble. If you wanted to reuse this class with a different view or post type, you’d have to rewrite it quite a bit. What if you wanted to use the same query, but return the posts as JSON?

This is the beauty of dependency injection. We can inject our query arguments and the view path into this class. Then we can take the HTML it generates and use that as a dependency of another class. This gives us a modular, testable, and reusable system.

Here is a refactored example of this class that takes the WP_Query arguments and the path for the view file as dependencies:

Now this class can be used with different query arguments or layouts. We just make a new instance with different values passed to the constructor. Notice that this class does not add any hooks. The HTML property can be accessed by another class whose responsibility is to hook to the_content filter.

This is an example of constructor dependency injection because the dependencies are injected in the constructor. We could also have added a public set_query() method that took a WP_Query object or an array of WP_Query arguments. That would be an example of method injection.

The third type of dependency injection is property injection. In this case, class properties are intentionally left public to allow for dependencies to be set on them externally. This is probably the least useful form of dependency injection because it can lead to the wrong type of dependency being injected.

I normally prefer constructor dependency injection. In some cases, a class needs an array of objects of a specific class. In that case, method injection is better, as you can take one object at a time and ensure it is correct using type hinting or other validation.

Let’s start with an example database abstraction for data stored as posts and posts meta:

This class makes use of both constructor dependency injection and method dependency injection. All of the class properties can be set via the magic __get() method, and retrieved via the magic __set() method. We inject the ID of the post into the constructor and let the class assemble the data we need from post and post_meta.

Here is an example class that extends this to implement the system:

This code is still completely tied to the way that the WP_Post class functions and stores data. I’m OK with that in this case because post and post meta storage is pretty specific to WordPress and hard to escape without moving to custom tables.

Despite the strong coupling I still like this because it makes the WordPress APIs invisible outside the encapsulation of this class. Look at this example of how we would use our example implementation:

In this code I used various properties of the class, via the magic __get() and __set() methods to create a new item in the database as well as to query for and echo data. The data is stored in a post, which is invisible to the outside world.

If I wrote a plugin using this system and in a later version to store data as posts and then later I switched to storing data in custom tables, that code would not break. Yes, I’d need to rewrite the internals of the class and create a migration system. But, all the code using that database abstraction would still function the same way.

The Power Of Invisibility

In my first article in this series, I talked about the reason behind making your own database abstractions. A good database abstraction makes the API that interfaces with WordPress and by extension the database invisible. By making these APIs “invisible” the way they function becomes irrelevant to the outside user.

A good database abstraction is essentially a black box. Data goes in, data goes out and we don’t really know why or how. We don’t need to know why and how. It just works and we can build on top of it any way we want to.

I hope in this article and the last two you have shown the value of creating database abstractions on top of WordPress APIs. The sooner you adopt a database abstraction in your work, the more stable your project will be and the easier it will be to make a change to how you store data in the future. If you want to replace options or post/ post meta storage with custom table storage, then that will be easy. If you do, be sure to read Pippin Williamson’s excellent series on creating custom table APIs that begins here.

Josh Pollock



Josh is a WordPress plugin developer and educator. He is the owner and a developer for CalderaWP, makers of Caldera Forms, a different kind of and Ingotthe native WordPress A/B testing solution.

The post Designing Better WordPress Database Abstractions Using Dependency Injection appeared first on Torque.

Show more