Blog: Getting To Know Propel 1.5: When You Really Need Arrays

The Propel Team – 17 May 2010

Web applications spend a large share of their code transforming arrays of data. PHP is a wonderful language for that, because it offers a lot of array manipulation functions. But web developers are actually required to translate business logic into a program - not to mess up with arrays. In fact, web developers should spend the least possible amount of time dealing with arrays, because this time is lost. A piece of code transforming an array is usually not very reusable, it doesn’t carry any logic, and it’s a pain to test and maintain.

Propel, as other ORMs, advocates the use of objects rather than arrays. But it turns out that you sometimes need an array representation of your model objects. Propel makes these situations painless by offering the shorcuts you need at the right time.

From ActiveRecord Objects To Arrays

One of the first goals of Propel is to replace the data structure of a database record, represented as an array by PDO, with an ActiveRecord object. Instead of accessing the columns of a record using an array interface, ActiveRecord objects offer getter and setter methods. The objects promote encapsulation, hide some columns from the end user, and can offer new, ‘virtual’ columns, calculated from other columns or even data from other tables. The Propel Guide explains this concept in detail, so there should be nothing new there:

However, it is sometimes useful to get an array representation of an ActiveRecord object. Whether for debugging purposes, or to dump data for later reuse, arrays are sometimes simpler to deal with than objects. The conversion is very straightforward with Propel:

Note that if you hydrated a model object together with its relations, then toArray() can be even more powerful than that. Just set the third argument to true to also convert relations to arrays:

You can also populate an empty Model object from an associative array by calling fromArray(). That’s a quick way to set several properties an once; it’s especially useful if you provide a form to edit a model object using phpNames as input names.

PropelCollections Give You The Array You Need

Propel 1.5 introduces PropelCollections, which are a wonderful way of not messing up with arrays. At first sight, a collection looks like an array, and behaves like an array. It also provides additional abilities, already illustrated in a previous article in this very blog:

But now, what if you actually need an array, for a special purpose? For instance, an autocomplete field using jQuery requires an action returning an associative array of book titles, indexed by primary key. Propel makes it trivial to transform a Collection object into such an array:

The first argument of toKeyValue() is the name of the column to use for the array index, the second is the name of the column to use for the array value. In fact, toKeyValue() is a little smarter than that. With no argument, it returns an associative array indexed by primary key, and uses the ActiveRecord __toString() method. So, provided the title column is declared as primaryString in the book schema, you can get the same associative array by calling:

If you need more than just a key and a value, then PropelCollection::toArray() is probably the method you need. It turns a collection into an array of associative arrays, much like the ones you get when calling individually toArray() on an ActiveRecord object:

Reindexing A Collection

Propel collection are indexed incrementally, for performance reasons. That means that the first element in a collection always uses 0 as index, the second uses 1, and so on. It makes methods like isFirst(), isLast(), or isOdd() fast and efficient, but it forbids the use of a custom index.

Fortunately, PropelCollection::getArrayCopy() accepts a column name as first argument, and returns an array of Model objects indexed by the chosen column:

toArray() also accepts a column name as first argument to choose a custom index column:

Whether you need to sort the results according to one of the columns of a model, or to get a list of ActiveRecord objects indexed by primary key, the ability to reindex an existing collection will save you a lot of coding.

Query From An Array Of Conditions

In a previous example, a list of books was created based on a ‘title’ request parameter. But you may want to provide a set of widgets to filter a list of books on several fields. In this case, the request may contain several parameters, each corresponding to a given column.

It’s easy to create a query using an associative array of filters:

filterByArray() expects an associative array of filter names and values, and turns it into a list of filterByXXX() calls. The previous line is the equivalent to:

filterByArray() can even accept additional filters not based on model columns, provided that you added a custom filterByXXX() method. For instance, if you add the following field to the book search form:

Then all it takes to make it work is to implement a BookQuery::filterByAuthor() method:

Raw Results From A Query

Even though Propel is fully Object-Oriented, there are times when hydrating an ActiveRecord object is just overkill. In cases you need a single scalar value resulting from a database query, there is often no interest to attach it to a model object. In this case, you can still use the methods of the generated query objects, by using the ‘statement’ formatter to get a raw PDO statement as a result instead of a model object.

If you need several columns and several rows, but still not attached to an ActiveRecord object, you can do the same, and call fetchAll() on the result statement to get an array to iterate on:

But if you end up doing too much of this kind of query, watch out: you’re probably missing the point of actually using an ORM. The following code sample provides the same functionality as the previous one; it is not more expensive to run, yet it is much more object-oriented, and much easier to write:

Conclusion

If you come from a PDO background, it probably feels more natural to use arrays instead of objects. Propel makes it easy to use an array as an input for an ActiveRecord object or a Query, or to output results as arrays. But try to reduce the use of arrays to a strict minimum, or you will spend too much time transforming these arrays, instead of dealing with the business logic of your web application. And you may miss some of the best features of Propel, which are only enabled by an Object-Oriented approach.