Horde ORM: Rampage Data Objects

Chuck Hagenbuch

The Horde Project

Definitions: ORM

ORM is Object-relational mapping

This is a broad term for a number of techniques that usually boil down to treating a row in a database table as an object.

ActiveRecord, part of Ruby on Rails, is probably the best-known ORM in the scripting language world right now. Hibernate and Torque are well-known and popular in the Java world.

Definitions: Data Mapper

Data Mapper is one of the patterns for doing ORM, or ORM-like-things.

With Data Mapper, Mapper objects sit between the database layer and domain objects and do the translation while keeping them separated.

Definitions: Horde

Horde is one of the oldest open-source PHP projects, encompassing an application framework and over 50 applications.

Definitions: Rampage

Horde on the Rampage is a catchphrase for the rapid-application building focus of Horde 4.

This was initially called Catalyst when it started out in Chuck's head, but Catalyst (written in Perl) was released before anything got written down.

Definitions: Rdo

Rdo is Rampage Data Objects. It's not RDO.

Why Rdo?

Other PHP implementations require XML (Propel), overload objects for both the model and row instances (DB_DataObject), require defining the database schema with PHPDoc annotations (ezPDO), etc.

Late Static Binding

This is mixing objects with classes, and it's because PHP doesn't have late static binding:

$b = new Book;
$books = $b->find(...);

Should be:

$books = Book::find(...);

Rdo Goals

Be as light as possible, but no lighter

Rdo Goals

Leave managing the database to the developer (DBA) or another tool (MDB2_Schema)

Rdo Goals

Smart usage of PHP 5 features and interfaces

Rdo Goals

Broad database support, with enough SQL abstraction for things that should be simple like LIMIT


Rdo is still beta software (like GMail!). The API is getting quite stable, but it is not frozen yet.


pear channel-discover pear.horde.org
pear install horde/Rdo

Schema for initial examples

    id bigserial NOT NULL,
    name varchar(255),
    phone varchar(20),
    created int,
    updated int,

    PRIMARY KEY (id)

Getting Started

Two core concepts: Mappers and entity objects.


Mappers implement the DataMapper part of Rdo, and always extend Horde_Rdo_Mapper. They need to know how to connect to the database, and know about any relationships with other objects.

Basic Mapper implementation

Entity objects

Entity objects are the "O" in ORM. They always extend Horde_Rdo_Base, and the most they know about the database is how to find a Mapper object.

Basic entity object implementation

Rdo Examples: Read

Rdo Examples: Edit

Rdo Examples: Find and Delete

Query Objects


Lazy Loading

You don't always want to load everything from the database in one go - blobs, large text fields, complicated and rarely used relationships (second cousins twice removed - they just need to show up at weddings and funerals).

Lazy Fields

Lazy Relationships

Really Complicated Relationships

    SELECT pr.description, pr.id, pr.product_id, pr.brand_id, p.special, p.case_price, p.piece_price,
           SUM(o.units) AS units, SUM(o.extra) AS extra, pr.units_per_case, o.locked, pr.min_ord_qty,
           (SUM(o.units) + SUM(o.extra)) AS units_wanted, pr.piece_size, o.catalog_id,
           floor((SUM(o.units) + SUM(o.extra)) / pr.units_per_case) AS cases_ordered
    FROM coop_orders o INNER JOIN coop_prices p ON o.product_id = p.product_id
                       INNER JOIN coop_products pr ON o.product_id = pr.id
    GROUP BY pr.id, o.locked
    ORDER BY o.locked, pr.description;

Work with Views

What's the primary key?

Can't create a primary key on a view in MySQL; can't always have a primary key. Composite primary keys can help, but that doesn't help us with views.

Cached Models

Instead of inspecting the database for the Horde_Rdo_Model object:

# rdo-model.php coop_group_order
class Coop_group_order_Model extends Horde_Rdo_Model {

Custom Models

Compare the output to the output for the users table. Only thing missing is 'key':

Using Custom Models

Getting the Database Connection

If you need it, it's there:

Future Plans