Dependency Injection: Using a Setter Method within a Model

In this fifth part of a six-part series on the dependency injection pattern, I explore the implementation of the pattern by using a simple setter method within a model class. You’ll see that this approach is very easy to follow.

While not as widely known as other popular design patterns like Singleton and Factory, the dependency injection pattern is a powerful programming methodology that allows you to define the way that one given class is going to accept additional objects that it requires to work as expected.

In the case of PHP 5, there are two major trends that most developers stick to when it comes to implementing dependency injection within a certain application: the first one relies on injecting the dependency of a class via its constructor, while the second approach does this, but by means of a setter method instead. Of course, both approaches use aggregation to deal with a class’s dependency, since in this case, composition contradicts the schema imposed by the Inversion of Control principle.

All of these buzzwords should be pretty familiar to you at this point, because over the course of the tutorials that preceded this one I explained how to apply the dependency injection pattern. If you go back to the previous part of this series, then you’ll recall that I left off discussing how to use the “injection by constructor” approach with a couple of basic classes.

In this specific example, the first of these classes was a simple MySQL handler, while the second one was a model class that required the functionality of the first to interact with a predefined MySQL table. This fictional scenario showed that it’s very easy to combine the power of dependency injection with the benefits of the Model-View-Controller pattern within a single application.

However, as I said a moment ago, dependency injection can also be achieved with a setter method. So, in this installment I’m going to explain how to use this approach with the pair of sample classes previously mentioned.

Want to see how this will be done? Then begin reading!

{mospagebreak title=Review: the Model-View-Controller and Dependency Injection Patterns}

In the previous article of this series I discussed how to apply the dependency injection pattern via a constructor method, which was coded inside a model class. Below I reintroduced the complete definitions of the classes that comprised this example, starting with the source code corresponding to the MySQL database handler mentioned at the beginning.

Here’s how this particular class was defined originally:

class MySQL

{

private $result = NULL;

private $link = NULL;

private static $instance = NULL;

 

// returns a singleton instance of MySQL class (chainable)

public static function factory($host, $user, $password, $database)

{

if (self::$instance === NULL)

{

self::$instance = new MySQL($host, $user, $password, $database);

}

return self::$instance;

}

// connect to MySQL

public function __construct($host, $user, $password, $database)

{

if (FALSE === ($this->link = mysqli_connect($host, $user, $password, $database)))

{

throw new Exception(‘Error : ‘ . mysqli_connect_error());

}

}

 

// perform query

public function query($query)

{

if (is_string($query) AND empty($query) === FALSE)

{

if (FALSE === ($this->result = mysqli_query($this->link, $query)))

{

throw new Exception(‘Error performing query ‘ . $query . ‘ Error message :’ .mysqli_error($this->link));

}

}

}

 

// fetch row from result set

public function fetch()

{

if (FALSE === ($row = mysqli_fetch_assoc($this->result)))

{

mysqli_free_result($this->result);

return FALSE;

}

return $row;

}

 

// get insertion ID

public function getInsertID()

{

return mysqli_insert_id($this->link);

}

// count rows in result set

public function countRows()

{

if ($this->result !== NULL)

{

return mysqli_num_rows($this->result);

}

}

// implement destructor to close the database connection

function __destruct()

{

mysqli_close($this->link);

}

}

Certainly, there’s not much to be said about the logic driving the previous “MySQL” class, since all that it does is build a simple abstraction layer that allows you to perform common operations against a selected MySQL database through a simple API. Period.

While analyzing the internals of the database handling class may be pretty boring for you, things will definitely become much more interesting when you look at the definition of the model below. It uses the functionality of “MySQL” for accessing a predefined “users” table. See for yourself how this process is accomplished:

class UserModel

{

private $db = NULL;

 

// constructor

public function __construct(MySQL $db)

{

$this->db = $db;

}

 

// get all users

public function getAll()

{

return $this->db->query("SELECT * FROM users");

}

 

// get a single user

public function get($id = 1)

{

return $this->db->query("SELECT * FROM users WHERE id = ‘$id’");

}

 

// create/update user

public function save($data, $id = NULL)

{

if (is_array($data) && !empty($data))

{

if ($id === NULL)

{

$data = array_values($data);

$fields = ”’ . implode("’,'", $data) . ”’;

$this->db->query("INSERT INTO users (id, fname, lname, email) VALUES (NULL, $fields)");

}

else

{

$fields = ”;

foreach ($data as $field => $value)

{

$fields .= $field . ‘=” . $value . ”,’;

}

$fields = substr($fields, 0, -1);

$this->db->query("UPDATE users SET $fields WHERE id=$id");

}

}

}

 

// delete user

public function delete($id = NULL)

{

if ($id !== NULL)

{

$this->db->query("DELETE FROM users WHERE id=$id");

}

}

}

Not too bad, huh? As shown before, the “UserModel” accepts an instance of the MySQL class, which is finally stored as a property, so it can be accessed by all of the model’s methods.

Undeniably, the beauty of this approach is that it shows in a nutshell how a proper implementation of dependency injection can reveal the power of the Inversion of Control principle. This principle states that the context of an object is responsible for providing it with its dependencies, and not the inverse process.

So far, so good. Now that you’ve relearned how the two previous classes interact with each other, here’s a basic script that demonstrates how to use them for running some CRUD operations against the “users” MySQL table. Take a look at it:

// create new instance of MySQL class

$db = new MySQL(‘host’, ‘user’, ‘password’, ‘database’);

// inject instance of MySQL in the model via its constructor

$userModel = new UserModel($db);

// add new user

$userModel->save(array(‘fname’ => ‘Alejandro’, ‘lname’ => ‘Gervasio’, ‘email’ => ‘alejandro@domain.com’));

// update existing user

$userModel->save(array(‘fname’ => ‘Mary’, ‘lname’ => ‘Wilson’, ‘email’ => ‘mary@domain.com’), 1);

// delete existing user

$userModel->delete(1);

Easy to code and read, isn’t it? As this code fragment shows, it’s very simple to combine the functionality of the MVC pattern and dependency injection to build a program that handles user-related database records.

However, as you can see above, the dependency, which in this case happens to be an instance of the “MySQL” class, is inputted into the model via its constructor. What if I show you how to achieve the same result by using a setter method instead?

Assuming that you’re interested in learning how to accomplish this, in the following section I’m going to add the setter to the model class, thus implementing another handy variation of the dependency injection pattern.

Now, click on the link below and read the following segment, please.

{mospagebreak title=Applying dependency injection through a setter method}

As you may have guessed, applying the dependency injection pattern through a setter method with the user model class that you saw before is only a matter of coding the method in question, so it can take in an instance of the corresponding MySQL handler. It’s that easy, really.

Nevertheless, to help you understand this process more quickly, below I listed the modified version of the “UserModel” class, which now includes this whole new method.

Study the following code sample, please:

class UserModel

{

private $db = NULL;

 

// constructor (not implemented)

public function __construct(){}

 

// setter for database handler

public function setDatabaseHandler(MySQL $db)

{

$this->db = $db;

}

 

 

// get all users

public function getAll()

{

return $this->db->query("SELECT * FROM users");

}

 

// get a single user

public function get($id = 1)

{

return $this->db->query("SELECT * FROM users WHERE id = ‘$id’");

}

 

// create/update user

public function save($data, $id = NULL)

{

if (is_array($data) && !empty($data))

{

if ($id === NULL)

{

$data = array_values($data);

$fields = ”’ . implode("’,'", $data) . ”’;

$this->db->query("INSERT INTO users (id, fname, lname, email) VALUES (NULL, $fields)");

}

else

{

$fields = ”;

foreach ($data as $field => $value)

{

$fields .= $field . ‘=” . $value . ”,’;

}

$fields = substr($fields, 0, -1);

$this->db->query("UPDATE users SET $fields WHERE id=$id");

}

}

}

 

// delete user

public function delete($id = NULL)

{

if ($id !== NULL)

{

$this->db->query("DELETE FROM users WHERE id=$id");

}

}

}

See how simple it is to implement dependency injection via a setter method within the above model class? I bet you do! In this particular case, this brand new method, called “setDatabaseHandler(),” plays the same role as the older constructor — that is, it accepts an instance of the “MySQL” class, which is finally stored as a property for further use.

At first sight, it seems that this approach requires you to write more code than when using a constructor, which is undeniably true. However, there are times when a class will need to take in multiple dependencies to work properly. In a case like this, a setter method might be the most appropriate option to use, but in the end, which approach to implement will depend on your own personal preferences.

Having already modified the definition of the previous “UserModel” class to make it accept its dependency via a setter method, the next step we must take is creating a script that shows this approach in action.

Therefore, in the final section of this tutorial I’m going to code that script for you, which hopefully will give you a more solid understanding of how to implement dependency injection by using a slightly different approach.

Now, go ahead and read the following segment, please. We’re almost done!

{mospagebreak title=Performing CRUD operations on user-related records}

As I said in the preceding segment, I’d like to finish this tutorial by showing you how the refactored version of the previous “UserModel” class can be used for inserting, updating and deleting records from its associated “users” MySQL table.

To do that, I coded a short script that shows how neatly dependency injection works when using the model’s setter method. Here’s the corresponding example code:

// create new instance of MySQL class

$db = new MySQL(‘host’, ‘user’, ‘password’, ‘database’);

$userModel = new UserModel();

// inject MySQL instance in the model via its setter method

$userModel->setDatabaseHandler($db);

// add new user

$userModel->save(array(‘fname’ => ‘Alejandro’, ‘lname’ => ‘Gervasio’, ‘email’ => ‘alejandro@domain.com’));

// update existing user

$userModel->save(array(‘fname’ => ‘Mary’, ‘lname’ => ‘Wilson’, ‘email’ => ‘mary@domain.com’), 1);

// delete existing user

$userModel->delete(1);

As seen above, once an instance of the “MySQL” class has been properly created, it’s injected into the internals of the user model via the “setDataBaseHandler()” method, so it can perform CRUD operations against its targeted table.

Again, it’s fair to point out that the approach that you’ll use to apply dependency injection within your own PHP 5-based applications will depend on certain factors, including the number of dependencies required by class, the application’s structure, and finally, your personal coding preferences.

Final thoughts

In this fifth episode of the series, I explored the implementation of the dependency injection pattern by using a simple setter method within a model class. As you were able to see for yourself, this approach is very easy to follow, so I think you shouldn’t have major problems putting it into practice.

In addition, it’s worthwhile to say that another common case where dependency injection shines is when building polymorph objects via interfaces. That sounds hard to grasp, right? Well, fear not, because in the following article I’m going to teach you how to apply this useful concept to building a couple of database drivers in PHP 5.

Don’t miss the next tutorial!

Google+ Comments

Google+ Comments