Building a CodeIgniter Custom Library with Method Chaining

Welcome to the seventh part of a 12-part series on the technique of method chaining in PHP 5. In this part, I will demonstrate how method chaining can be used to develop some core methods of a custom library for CodeIgniter.

In case you haven’t explored it in depth yet, method chaining is a useful programming methodology that permits you to build highly modular and compact APIs when using the object-oriented paradigm. This isn’t a proprietary feature of a specific programming language; however, it’s possible to implement it with relative ease in PHP 5.

Thus, if you’re a PHP developer who wants to master the basics of creating chainable methods while defining your own classes, then this series of articles might be the material that you’re looking for. In it you’ll find numerous examples that will show you how to apply the method chaining approach to building real-world applications.

Now that you’re well aware of the goal of these tutorials, it’s time to reexamine the topics that were treated in the previous article. In that part of the series I completed the development of a simple, useful MySQL abstraction class that had the ability to perform typical retrieval queries by means of a few basic chainable methods.

Despite the rather simplistic logic implemented by the methods of this class, this particular example hopefully demonstrated how to use chainable methods for building a PHP program that can be used under “real conditions.”

However, as I said at the beginning of this series, my goal here is to illustrate how this approach can be implemented for creating applications that can be used in production environments. So, with that premise in mind, in the next few lines I’m going to show you in a step-by-step fashion how to build a custom library for the popular CodeIgniter framework. The library will allow you to perform the most common database operations without having to create multiple models.

Also, some of the methods that will be implemented within this application will rely partially on the great DataMapper library developed by Simon Stenhouse at http://stensi.com/datamapper, so I’d like to give the corresponding credit to him. Of course, if you need to get a full-featured ORM for CodeIgniter, I recommend you to give the library a try here (http://stensi.com/datamapper/pages/download.html). It’s really worthwhile.

Finally, a word of warning is in order here before you continue reading: the library will be pretty huge, with plenty of modular chainable methods, so I suggest that you arm yourself with patience and willpower to understand how each method is going to work.

Having clarified those points, it’s time to start building this custom library for CodeIgniter by using the functionality provided by method chaining. Let’s do it right now!

{mospagebreak title=Defining the CodeIgniter custom library’s first methods}

As I stated in the introduction, the CodeIgniter library that I plan to build here will perform CRUD operations against a selected database table, without the need to create many complex models. It will rely partially on Simon Stenhouse’s DataMapper, which has been a great source of inspiration for writing mine, even though I enhanced some aspects of it (such as the recursive load of required files by means of directory iterators supplied by the Standard PHP Library (SPL)).

That being said, it’s time to start creating the library. In its initial stage, it looks like this:

The MIT License

 

Copyright (c) 2008 Simon Stenhouse

 

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

 

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

 

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 

 

class AbstractModel

{

protected $table = ”;

protected $fields = array();

protected $validation = array();

protected $error_prefix = ‘<p>’;

protected static $instance = NULL;

protected $ci = NULL;

protected $db = NULL;

 

// Factory method that creates a singleton model object

public static function factory($model)

{

if (self::$instance == NULL)

{

$model = ucfirst($model);

self::$instance = new $model;

}

return self::$instance;

}

 

// Constructor

public function __construct()

{

$this->ci = & get_instance();

$this->db = $this->ci->db;

$table = strtolower(get_class($this)) . ‘s’;

if ($this->db->table_exists($table))

{

$this->table = $table;

$this->fields = $this->db->field_names($this->table);

}

else

{

return;

}

}

}

As shown previously, the above “AbstractModel” class defines some simple properties that are pretty self-explanatory, such as the name of the database table that it’ll be associated with, the fields of that specific table, the validation rules that will be applied to the data before inserting and updating a record, and so forth.

It’s worth paying close attention to two of these properties, called “$ci” and “$instance” respectively. The first one will store an instance of the CodeIgniter super object (required for using its database class), and the last one will be used for returning a Singleton of the “AbstractModel” class.

The first method implemented above, called “factory(),” as its name implies, is used for factoring only one instance of the class. Naturally, it should be used instead of explicitly calling its constructor, since it can be chained to other methods easily.

Lastly, there’s the constructor, which is responsible for grabbing an instance of the CI super object, as well for determining if the database associated with the abstract model really exists. In this specific case, I decided to use a simple convention-over-configuration rule that assumes that the name of the associated table is simply the name of the model plus an “s.” However, it’s possible to implement a more complex process for associating a model to a table by using, for instance, the CodeIgniter inflector helper.

So far, so good. At this point the “AbstractModel” class still looks pretty useless, since it only implements a couple of methods so far. It’s valid to stress, though, that one of them is chainable, thus demonstrating how method chaining can be used for developing a production application.

Now, it’s time to keep extending the functionality of the previous class by defining some other methods. This will be done in the following section, so click on the link below and read the next few lines.

{mospagebreak title=Extending the functionality of the AbstractModel class}

The next step that I’m going to take regarding the development of the previous “AbstractModel” class will consist of implementing the “__set()” and “__get()” magic functions provided by PHP 5. These methods will be used to dynamically create properties for the class without having to declare them before, and for retrieving their assigned values as well.

In reality, the use of property and method overloading in PHP 5 has been a controversial topic, but in this case I’m going to use it as a shorthand for handling properties of the “AbstractModel” class.

Now it’s time to pay attention to the implementation of these methods, which looks like this:

// Sets a new property for the model

function __set($property, $value)

{

if(in_array($property, array_merge($this->fields, array(‘error’, ‘result’)), TRUE))

{

$this->$property = $value;

}

}

 

// Gets the value of an existing property of the model

function __get($property)

{

if(isset($this->$property))

{

return $this->$property;

}

return NULL;

} 

 

Quite simple to follow, right? As you can see, the previous “__set()” and “__get()” methods have been implemented in a pretty classical way. Speaking more specifically, the first method is responsible for creating only properties that have the name of the database table associated with the model class, with the exception of a couple called “error” and “result.” These last two will be used by the class later on to store errors and result sets respectively.

The “__get()” method will return to client code the value of a specified property and nothing else. It’s that simple, really.

At this point, the previous class starts to look a bit more functional, since now it’s capable of associating a specific database table with a given model. It also has the ability to assign and retrieve properties on the fly via the property overloading.

So, what’s the next step? Well, in the last section I’m going to add two other methods to the class, which will be tasked with selecting and inserting database records. However, the most interesting aspect of this process will be that one of these methods will be chainable as well.

To see how this will be done, click on the link below and read the following segment.

{mospagebreak title=Fetching, inserting and updating database records}

As I said in the previous section, the last step that I’m going to take in this tutorial will consist of adding two core methods to the “AbstractModel” class, for performing  select and insert/update SQL statements.

The respective implementations of these methods are shown below, so pay close attention to them:  

// Fetches rows from specified table

public function fetch($limit = NULL, $offset = NULL)

{

$data = array();

foreach ($this->fields as $field)

{

if (isset($this->$field) AND $this->$field != ”)

{

$data[$field] = $this->$field;

}

}

$query = !empty($data) ? $this->db->get_where($this->table, $data, $limit, $offset) : $this->db->get($this->table, $limit, $offset);

if ($query->num_rows() > 0)

{

$this->result = $query->result();

return $this;

}

$this->error = ‘No rows were returned.’;

return FALSE;

}

 

// Inserts/updates a row into the specified database table

public function save()

{

$data = array();

foreach ($this->fields as $field)

{

if (isset($this->$field))

{

$data[$field] = $this->$field;

 

}

}

// if there is any data available go ahead and save/update row

if( !empty($data))

{

// validate input data

if ($this->validate($data) === FALSE)

{

$this->error = $this->get_error_string();

return FALSE;

}

// if id property has been set in the controller update existing row

if ( !empty($this->id))

{

// Update existing record

$this->db->where(‘id’, $this->id);

$this->db->update($this->table, $data);

}

else

{

// otherwise insert new row

$this->db->insert($this->table, $data);

$this->id = $this->db->insert_id();

}

return TRUE;

}

$this->error = ‘No valid data was provided to save row.’;

return FALSE;

}

From the previous code samples, it’s pretty clear to see how the methods defined above do their things. In the first case, the “fetch()” method is responsible for retrieving database records from the table associated with the model, via the database class provided by CodeIgniter. If you’re not familiar with it yet, I recommend you read its user guide.

It’s worth noting that this particular method is capable of performing “limited” SELECTS if the proper offset and limit arguments are specified, and according to the given conditions, it’ll store in a “result” property the data set retrieved from the pertinent table. Of course, an example of the use of this property will be developed in upcoming parts of this series, so for the moment you don’t need to worry about it. 

The other method, called “save(),” will simply insert a new record into the specified database table, or update an existing one if the corresponding ID has been specified. In addition, it’s fair to note that the supplied data will be validated via a “validate()” method before performing the previous operations, but again, the implementation of this method will be covered in a subsequent article of the series.

At this stage you should have a clearer idea of how to use the method chaining approach for creating a custom library for CodeIgniter. My final suggestion is that you to study the methods shown before in detail, since this process may take a while.

Final thoughts

That’s all for the moment. In this seventh part of the series, I hopefully demonstrated how method chaining can be used for developing some core methods of a custom library for CodeIgniter.

In the following article, I’m going to keep adding more chainable methods to this library, which will equip it with the functionality required for building different modifiers of SELECT statements.

Want to learn how these useful methods will be defined? Then don’t miss the next tutorial!

Google+ Comments

Google+ Comments