Using Propel with CodeIgniter

CodeIgniter is a nice development framework used for PHP applications. Is light, small, compact and it does provide an “Object Oriented” solution for web development. However, it lacks a major component, which is a database infrastructure. CodeIgniter’s models provide a rather quick and dirty solution for database access, which is nice for small projects, because we cannot be thinking on the large solution every time we write a piece of code, but for most decent application, a small approach like that one, just won’t do it.


The solution? Well, using an ORM framework. I’m a defender of ORM mapping solutions and I believe that they are here to stay, just like the Korn song. Anyways, there is no easy way to integrate CodeIgniter with Propel; they just don’t seem to get along. I’ve read a wiki post explaining how to do it, but I found it quite disturbing for a few reasons


  • A solution shouldn't tell you to change the apache configuration
  • Propel has a really powerful autoloading system, why did they not prepared for using it?

Anyways, the idea I came up with is to integrate Propel as an independent library for the framework using the libraries autoloader, which is much like the post I'm talking about, but I made a few tweaks. CodeIgniter stores it’s plugins into the folder system/libraries, so the best way to start is copying Propel’s runtime into that folder. Create a folder called propel and copy the runtime files (propel/runtime/lib/*) there.


After copying Propel we can create the library’s entry point, which is a file called propel.php and there we will write a class to load Propel:


class CI_Propel
{
  public function CI_Propel()
  {
 define(DIRECTORY_SEPARATOR, “DS”);
     require dirname(__FILE__) . DS . "propel" . DS . "Propel.php";
     Propel::init(BASEPATH . "application/config/propel-conf.php");
  }
}

In this class we require the Propel main file (Propel.php) and we tell it where he can find the configuration file. The configuration file is the xml file generated by Propel storing the database configuration and we must specify it in order to get propel running.


Now we’ve created our driver, we need to tell CodeIgniter to load our library, and this is done by going into the application/config/autoload.php file, where CI stores the libraries to be loaded with the application. We need to look for the line:


$autoload['libraries'] = array();

And change it with the information we need to load propel:


$autoload['libraries'] = array('Propel');

Now, we need to copy Propel’s models into the models folder located in the application folder and the configuration files generated should be on the application/config folder. Now the mapping configuration files should be edited to load the models properly; Propel works with relative routes to the models and it breaks when we try to load those models from a different path. You should look for lines like this one:


'CategoriesTableMap' => 'Northwind/map/CategoriesTableMap.php'

And change them for the real CI path:


'CategoriesTableMap' => BASEPATH . DIRECTORY_SEPARATOR . "application" . 
DIRECTORY_SEPARATOR . 'models/map/CategoriesTableMap.php'

Well, all we need to do now is use Propel! Keep in mind that using Propel’s classes directly from the controller is a bad practice, because you’d be coupling your data access layer to your presentation layer, you can take a look on this post if you want to read a bit more about it.


For our practical purposes we can just call the Propel query object from the controller now, much like this:


function index()
{
  $query = ProductsQuery::create()->limit(10)->find();
  $data =  array();
  $data['rows'] = $query;

  $this->load->view('welcome_message', $data);
}

And it will retrieve the results quickly and using a nice ORM mapper. I hope you’ve found this post useful and as usual commenting is highly encouraged!

10 comments:

  1. Thanks for sharing this, found your comment on Stack Overflow. I've been looking at ORM options for CI and think I'll give Propel a shot.

    ReplyDelete
  2. Hi Tommy!

    You should give a try to Propel, I believe is very good. The only "weak" spot is the documentation that is not as extensive as other frameworks, but still, I find it better than the rest.

    ReplyDelete
  3. Thanks, I liked of your post. And, I am using this code way of Propel loading.

    ReplyDelete
  4. can you post a zip version of integration?

    ReplyDelete
  5. hi, confirmed.. except i had to made minor changes. define(DIRECTORY_SEPERATOR, "DS") seems to need a fix, anyway... For me it's APPPATH instead of BASEPATH (<-- links into system folder). If i am right, everytime you update your project folder you have to copy classes/... and adjust application/config/classmap...-file?!?! i see no other way. Of course if your DB structure never changes everythings OK... Well, it works, BIG *thumbs up*...

    ReplyDelete
  6. Thanx.. nice post.. A downloadable version of ur code would be very helpful..

    ReplyDelete
  7. Hi everybody!

    For those of you that wanted me to upload the code somewhere, I've made a repository on github with the code. Check it out here!

    ReplyDelete
  8. Thank you for your article, it's very helpful! After several days of finding the right ORM system for Codeigniter, I decided to give the opportunity to Propel and it's great! The only negative thing about Propel is documentation. I will definitely use it in the next major project following the end of October 2011. Thank you David!

    ReplyDelete
  9. Helpful but could be better with a little more details.

    I supposed that you are calling $this->propel to access propel in your controller.. Do you put your logic in Propel's generated model class file? How do you access CI instance inside the model?

    anothing way would be the following(haven't implemented it yet):

    rename libraries/Propel.php to core/MY_Model.php and have it extend the CI_Model. this way I can access CI directly from any propel models.

    put model methods in propel generated model php file.

    in controller, $this->load->model('Book'); then use $this->book->my_model_method();

    ReplyDelete
  10. Thanks a lot man.

    ReplyDelete

Commenting is allowed!