PHP LINQ: A nice alternative

A few days ago, I was browsing through the CodePlex projects, to see if I could find something nice to try, and it happens I did. I’ve always been a defender of .NET and it was the motive of several discussions with my (not so fan of .NET) friends. One feature that I’ve always enjoyed on C# was the introduction of LINQ on .Net 3.5 which I believe is one of those life changers of the language.

For those of you who hate .NET or just don’t care about it, LINQ is a powerful way to access/query your data through a set of extension methods created on the IEnumerable interface. For those of you who’ve never heard of it, you can do amazing things like this:

var aCollection = new List<AnySortOfClass>();

var query = from item in aCollection 
   where item.APropertyName == “Nice!!” 
   select item;

foreach (var item in query )
 Console.WriteLine(“Found an item: ” + item.Name);
 

This is a pretty neat stuff to have when programming, at least you can kiss goodbye to all the nasty for loops (or foreach loops) looping into an array just to filter data. The idea of taking the SQL approach into other programming languages, at least for performing data related tasks is very reasonable one, so I believed that LINQ would be conceived for at least a few other languages.

Due to the fact of LINQ heavy use of anonymous types and lambdas (supported on PHP until 5.3, at least directly, before we could use create_function() ), I didn’t had much hope for a PHP version of LINQ to show up, then I found PHP LINQ, a project hosted in CodePlex and maintained by Martin Balliauw.

After browsing for a couple minutes the source code and the examples, I have to say, that PHP LINQ does have some potential. For instance, there is a Zend_Db_Table adapter for those who use Zend framework, which is kinda neat. You can do something like this:

Assuming you have a EmployeeTable (employee.php)

class EmployeeTable extends Zend_Db_Table {
    // table name
 protected $_name = 'employees'; 
 
    protected $_primary = 'Id';
}
 

You can now perform this query:

$employeeTable = new EmployeeTable(array('db' => $db));
$employeeTable->setRowClass('Employee');

$result = from('$employee')
 ->in( $employeeTable )
 ->where('$employee => strlen($employee->Name) < 5')
 ->orderBy('$employee->Name')
 ->select('$employee');
   
foreach ($result as $employee){
 // do something with $employee...
}
 

I think this is a rather nice way to work around queries for the database. Anyways, will try to do on my free time (which is kinda scarce these days) a driver for using with Propel, which is the ORM I like using!

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!