Symfony by default uses Propel for its ORM. Although Propel supports supports custom SQL I have learned how to take advantage of the built-in Criteria class to help construct queries. As described in the Propel trac,
…its database neutrality and logical simplicity make it a good choice for expressing many common queries; however, for a very complex query, it may prove more effective (and less painful) to simply use a custom SQL query to hydrate your Propel objects. (propel trac)
In building a complex search system for a client, I benefited greatly from being able to add and remove columns and conditions to a criteria object on the fly without having to worry about the actual SQL syntax. However, eventually I hit a wall when I needed to add a left join using multiple columns. Adding left joins to a criteria object is typically done like this:
$c = new Criteria();
$c->addJoin(TABLE_A::ID, TABLE_B::ID, Criteria::LEFT_JOIN);
/* equivalent to: "...left join TABLE_B ON (TABLE_A.ID=TABLE_B.ID)" */
However, this syntax does not support a join with multiple conditions, so you can’t produce something like this:
...left join TABLE_B ON (TABLE_A.ID=TABLE_B.ID AND TABLE_B.VALUE > 100)
In playing around quite a bit and examining the source code, I realized you could hack the addJoin method call and trick it into adding the extra column for you. The addJoin method actually is creating a new Join object that has a left and right column definition as defined in the method call. These are used to build the join condition:
$condition = $join->getLeftColumn() . '=' . $join->getRightColumn();
(see the source)
So, if you add the extra columns to the RightColumn like so:
$c->addJoin(TABLE_A::ID, TABLE_B::ID.' AND '.TABLE_B::VALUE.' > 0', Criteria::LEFT_JOIN);
the generated SQL will yield something like this:
...LEFT JOIN TABLE_B ON (TABLE_A.ID = TABLE_B.ID AND TABLE_B.VALUE > 0)
Although it’s a hack and it may not work under all conditions, so far it has been a suitable workaround.