Using OR In Propel Queries Becomes Much Easier With Propel 1.6

Combining two generated filters with a logical OR used to be impossible in Propel - the alternative was to use orWhere() or combine(), but that meant losing all the smart defaults of generated filters.

Propel 1.6 introduces a new method for Query objects: _or(). It just specifies that the next condition will be combined with a logical OR rather than an AND.

// Basic usage: _or() as a drop-in replacement for orWhere()
$books = BookQuery::create()
  ->where('Book.Title = ?', 'War And Peace')
  ->_or()
  ->where('Book.Title LIKE ?', 'War%')
  ->find();
// SELECT * FROM book 
// WHERE book.TITLE = 'War And Peace' OR book.TITLE LIKE 'War%'

// _or() also works on generated filters:
$books = BookQuery::create()
  ->filterByTitle('War And Peace')
  ->_or()
  ->filterByTitle('War%')
  ->find();
// SELECT * FROM book 
// WHERE book.TITLE = 'War And Peace' OR book.TITLE LIKE 'War%' 
 
// _or() also works on embedded queries 
$books = BookQuery::create()
  ->filterByTitle('War and Peace')
  ->_or()
  ->useAuthorQuery()
    ->filterByName('Leo Tolstoi')
  ->endUse()
  ->find();
// SELECT book.* from book 
// INNER JOIN author ON book.AUTHOR_ID = author.ID 
// WHERE book.TITLE = 'War and Peace' //    OR author.NAME = 'Leo Tolstoi' 

This new method is implemented in the Criteria class, so it also works for the old-style queries. And since ModelCriteria::orWhere() is a synonym for ->_or()->where(), it is now deprecated.

Posted by Francois Zaninotto 

11 comments

Feb 21, 2011
Shyru said...
Great! But why is the method called _or() and not or()?
Feb 21, 2011
@Shyru: try to define a function named or() in PHP to see why...
Feb 22, 2011
IcyT said...
I really appreciate it because I was missing to use the filter methods in combination with "or" very much, thank you!
Since Propel 1.6 is not stable, I would like to raise my voice for another name of the method.

Especially beginners learn an API with the help of code completion and nobody expects a method to start with an underscore.
So a beginner would type a character and would see what it's got. The result is he hardly sees this method in code completion suggestions. But even if he sees it, he could think this method is kind of "private" as long as the underscore is often a naming convention for methods you should not call directly.

Also an advanced user must always remember that only this particular method starts with an underscore what could be annoying over time.

I'd like to make constructive criticism and here are some suggesstions: useOr, withOr, addOr, orWith
I'm also open for other suggestions of course and I hope I could convince you of the disadvantages starting a method with an underscore.

Feb 22, 2011
Loïc said...
Hi François,
I will need this method soon while working on an admin generator for symfony and dealing with filters.
May you post a more complex example of code using _or() method nested with "AND" and "OR" conditions ?

I was also wondering if it would not be easy and powerful to use _or() (whatever the name) and _and() methods as it is done with useOtherModelQuery()->...->endUse()

Following IcyT proposal, we would write something like
$query
->where('field1=value1')
->useAnd() // opening OR (
->where('field2=value2')
->where('field3=value3')
->endAnd()
->where('field4=value4')
...
making "simply" a "field1=value1 AND (field2=value2 OR field3=value3) AND field4=value4"

Personnaly, I like chaining (thanks JQuery !) and find it very readable and efficient.

I guess that Propel already knows to do that, but sure you will tell us how to do it well :)

Loïc

Feb 22, 2011
@IcyT: _or() is like _if() and _else() - and nobody ever complained about those. As for beginners, I suggest they read the manual.
Feb 22, 2011
@Loic: You're reinventing combine()!
Feb 22, 2011
Loïc said...
Héhé, it sounds like, but I don't think so ;)
First of all, I failed displaying right indentation in my last post.

I am already using combine() but it has a strong flavor with Criteria/Criterion way to make nested conditions that were hard and not natural to use in earlier versions of Propel.
And that is the point : I do believe an additional level maybe built on combine() could enhance usability.
For people knowing SQL, its by far more natural to deal with "at-the-moment" nested conditions than defining all conditions you need and then manage them one more time, and maybe one other time to get the final request : the more your request is complex (as far as conditions nesting is concerned), the less your query is readable and maintanable.
Many of you could disagree, and I will be glad to be wrong and learn why ;)

On the other hand, the use of combine is clearly indicated for automated tasks, such as code generation from config files as it is done in symfony admin generator.

Loïc

Feb 22, 2011
@Loïc: since combine() does the job, there is no need to add another way to do things as the difference in usage is not spectacular.
Feb 22, 2011
IcyT said...
What's _if() and _else()? I've never used them.
You're of course right that beginners should read the manual. But in my opinion it is also important to not put obstacles in their way and at this spot it's even very easy to avoid it.
After all I was sad reading your answer.
Feb 22, 2011
Loïc said...
Hi IcyT, maybe these topics should be discussed on the mailing list, let's go to talk about that on http://groups.google.com/group/propel-development
Feb 22, 2011
xplo said...
hi,
Loic is not reinventing combine, he s just doing what you re doing with _or() that cannot be done with condition/combine : keeping the power of the query method. Unless it s possible to use a method with condition/combine i m all for ->useConditionXXX ->endUseCondition()
...well when i reread that i see it s much more complicated than that but i ll just let it here in the unlikly case it could be a good idea =)

Leave a comment...