CodeIgniter is a widely used PHP framework that aims to help developers write better structured code and remove boilerplate tasks from the workflow.
In this article, I'm going to explain some incredibly useful techniques to use when developing applications using CodeIgniter.
1. Easier Configuration Parameters
When creating libraries (or anything that requires configuration values) for our applications, we often need to use configuration parameters in order for it to be able to perform its tasks. When doing so, we can use the snippet shown below to obtain the configuration values.
$value = $this->config->item( 'some_item' );
This is fine, if we have just a couple of configuration parameters, but when we need to extract a dozen configuration parameters or so, loading values this way can be very annoying. Wouldn't it be great to load every parameter like the array we use in the configuration file? In order to do just that you need to load it in the following way.
$this->load->config( 'config_file', true ); $options = $this->config->item( 'config_file' ); // $options['some_item'];
And with that single line, our entire configuration file will be placed in the $options
array. And to further sweeten the deal, using this technique also makes sure you avoid the name collision problem in configuration files. This way, your parameters can be named anything you'd like without worrying about other configuration files.
2. Allowing Optional Configuration Options
Building up on our earlier point, imagine a scenario where we'd like to pass parameters to our library from either a configuration file or an options array when loading it. Maybe we're using the same library in different parts of our application and the config options cannot be the same for each use case.
To be able to do this, place a private _options
member in you library and use a constructor like the following.
private $_options = array(); public function __construct( $options = array() ) { if ( is_empty( $options ) ) { $this->load->config( 'config_file', true ); $options = $this->config->item( 'config_file' ); } $this->_options = $options; }
After this, you can access your parameters through the private _options
array within your library, and, just like the previous example, you've avoided name collision problems with the keys in your configuration files.
3. Leveraging HTML Emails
The need to send HTML emails through your app is omnipresent, be it a newsletter or some automatic welcome message. Usually, you'd do this by hand coding the corresponding HTML in the message
parameter of our email object (been there, done that).
Well, it's no secret that the above method is pretty ugly. The following tip is not quite a trick but merely a way to take advantage of some CodeIgniter functionality where it makes sense.
Personally, I prefer this approach as I manage a few sites where I need to send newsletters, and several other HTML emails, and using templates will significantly ease up the process.
In your application's views
folder, create a folder called emails
and place any HTML email you'd like to send inside it, with the corresponding structure to be rendered by email clients. And now, in the method where you shoot off the emails, you can use the following code:
public function send_mail() { $this->load->library( 'email' ); $this->email->from( '[email protected]', 'John Doe' ); $this->email->to( '[email protected]' ); $this->email->subject( 'Some subject' ); $this->email->message( $this->load->view( 'emails/message', $data, true ) ); $this->email->send(); }
A couple of important things to keep in mind when using this technique:
- The email library must be set up to be able to send HTML emails
- The
data
object used when loading the view should contain the options used in the view - With this approach, we're using the built-in functionality of retrieving the content of a view file instead of sending it to the output class by setting the third parameter to true when loading the view.
4. Managing Application Versions
Let's face it: almost every recent PHP application is a backend service or an API. If you have used the Google Maps API, you've probably noticed that Google allows us to pass a version parameter for us to tell it which version we're going to make use of.
Wouldn't it be nice if we can do this in our CodeIgniter applications? This way, we can create new versions of our software while supporting legacy versions to ensure backwards compatibility.
With this technique, we'll be able to use a single CodeIgniter installation to handle multiple versions of our application using the same index file. We'll be able to choose the version by passing a v
parameter in the request.
There are a couple of things in order for this to work. First off, I'm going to rename my application
folder. Since this is the first version of my API, I'll simply name it 1.0.0.
After this, I'm going to rename my index.php
file, call it 1.0.0.php
and change the application_folder
line in it. Replace line 75 with:
$application_folder = '1.0.0';
Cool, now our application version is 1.0.0. Are we going to call that 1.0.0.php
file instead of index? Absolutely not! Let's create a new index.php
file and add the following code to it.
define( 'API_VER', 'v' ); array_key_exists( API_VER, $_REQUEST ) ? $v = $_REQUEST[ API_VER ] : $v = '1.0.0'; if ( file_exists( "{$v}.php" ) ) { if ( is_dir( dirname( __FILE__ ) . "/{$v}" ) ) { require dirname( __FILE__ ) . "/{$v}.php"; } else { $error = new stdClass(); $error->error = true; $error->description = 'INVALID_API_VERSION'; echo json_encode( $error ); exit; } } else { $error = new stdClass(); $error->error = true; $error->description = 'INVALID_API_VERSION'; echo json_encode( $error ); exit; }
Here, we're defining the parameter that we'll use to choose the version. If no version is passed, we use the 1.0.0 version. If a version is passed, we make sure there's a corresponding file and folder for that version. Otherwise, we throw an error.
To add more versions, we'd simply have to copy our 1.0.0
folder and the 1.0.0.php
file, rename them according to the version we're going to create, change the application_folder
variable in the file and start working on the next version of our API. When we feel comfortable enough with it, we can make it the version by modifying the index.php
file.
5. Serving Separate Response Formats
Dot notation? No, I'm not talking about Objective-C messages. If you have used the Twitter API or something similar, you'll remember that at the end of the method call, you can specify the format you want the response in. As I really like to create RESTful services using CodeIgniter, I like to add this functionality to them even though I've always use JSON.
In order to do this, we need to take advantage of CodeIgniter hooks to preprocess our URI. We'll use two hooks for this process, and we'll set a config item to set the response format accordingly.
First off, what are hooks? According to the CodeIgniter user guide,
CodeIgniter Hooks feature provides a means to tap into and modify the inner workings of the framework without hacking the core files
In plain English, they're a way to change the normal execution flow of an application. Although we don't want to do precisely that here, we do want to preprocess our URI before the CodeIgniter Router class has a chance to inspect it. With that in mind, we're going to make use of the "pre_system" hook.
In order for us to use hooks we have to enable them. To do that, open the config.php
file under the config
and set the enable_hooks
item to true.
$config['enable_hooks'] = TRUE;
We now need to add the hook that will take care of the pre-routing process. Inside the config
folder in your application folder, open the hooks.php
file and add the following code:
$hook['pre_system'] = array( 'class' => 'Router', 'function' => 'route', 'filename' => 'router.php', 'filepath' => 'hooks' );
What this code does is that it tells our application to run the route
method of our Router
class inside our hooks
folder. A quick note here: the filepath
parameter is the path to the file that has the method you want to call, and it MUST be relative to your application folder WITHOUT a trailing slash.
Now we need to create the class and method that this hook is going to call. In your hooks
folder (if it's not there, create it) inside your application
folder, create a new file, name it router.php
and place the following code in it.
if ( !defined( 'BASEPATH' ) ) exit( 'No direct script access allowed' ); class Router { private static $_format = ''; public function route() { $request = strstr( $_SERVER['REQUEST_URI'], '?', true ); if ( !$request ) { $request = $_SERVER['REQUEST_URI']; } $parts = explode( '.', $request ); self::$_format = $parts[ sizeof($parts) - 1 ]; if ( self::$_format == 'json' || self::$_format == 'xml' || self::$_format == 'rss' || self::$_format == 'atom' ) { $_SERVER['REQUEST_URI'] = substr( $request, 0, ( strlen( $request ) - strlen( self::$_format ) - 1 ) ); } else { self::$_format = ''; } } }
CodeIgniter Hooks feature provides a means to tap into and modify the inner workings of the framework without hacking the core files
A couple of things to note here. First off, you'll notice that I'm using an static class member to store the type of the request. That's because we're getting the response format correctly, but we cannot tell the rest of the application about it. At this early point of the application execution, the config class is not yet loaded so we need to use another hook. With that in mind, we'll need to make it static so it's not overridden when we call the next hook.
Right at the beginning, I'm checking for an ?
symbol, so the rerouting here won't conflict with any parameters passed through the URL. The strstr
method will return the string BEFORE that character as the third parameter is set to true. Do keep in mind that this behavior was added in PHP 5.3.0, so if you're using a previous version, you'll need another way to obtain the part of the string before the ?
symbol.
Because of the way we're retrieving the requested response format from the URI and then setting the REQUEST_URI
key manually for the CodeIgniter Router, we need to check that the output requested is valid. If not, we let the application handle the request without interfering.
Now we have identified the requested response format but our controllers doesn't know about it. I think that a clean way to inform this is with a config
parameter. In order to set it we need to use another hook. The first two hooks are pre_system
and pre_controller
.
However, at this point we cannot use the get_instance
method, meaning we can't set a config item, so we'll use the post_controller_constructor
hook. As long as you don't intend to use the response format config item in the controllers constructors this technique will work.
After the pre_system
hook in the hooks.php
file add the following code.
$hook['post_controller_constructor'] = array( 'class' => 'Router', 'function' => 'config', 'filename' => 'router.php', 'filepath' => 'hooks' );
As you can tell, this hook is calling another method in the same class that we use to retrieve the requested response format. In the Router
class after (or before) the route
method, add the following code.
public function config() { $CI =& get_instance(); $CI->config->set_item( 'response_format', self::$_format ); }
In this method, we're setting a configuration option called response_format
with the format retrieved on the route
method.
Finally, to use this response format in your controllers (or anywhere in your application) use the following code.
$format = $this->config->item( 'response_format' );
And with that, you can retrieve the requested format and parse the result accordingly. As to parsing the response, I leave it as an exercise to the reader.
Conclusion
I hope you've found some of these tips useful. As you may have noticed, I've focused on RESTful services since, in my opinion, they are what we as PHP developers should be focusing on.
I look forward to your comments and thank you so much for reading.
Comments