Next thing you do is writing a template for your form and to specify some validation rules. My controller action which receives the search POST looks like this:
We need to implement the findBySearchCriteria function in the empty repository class of the user entity. This function returns a query builder object which we can do everything we want with.
The following examples show what is possible with the doctrine2 query builder in the search function.
Many-to-one search
The user has a languages attribute which is of type Language. The entity Language has three attributes:- a language name (e.g. english, french, etc)
- points that define how good the language is spoken by the user (10 very good, 1 very bad)
- a back reference to the user
As "exists" in the query builder expects a dql subquery, we give it one.
"u" is the alias for the User class of the main query builder. The same method is used for the french language points.
The resulting DQL is:
SELECT u, l FROM Acme\UserBundle\Entity\User u WHERE (EXISTS( SELECT langE FROM AcmeUserBundle:Language langE WHERE langE.user = u AND langE.language = :langName AND langE.points BETWEEN 10 AND :points))
Nested AND / OR queries
Next requirement is that the zip code of the user entity has to lie in a given range of zip codes. The user who defines the search criteria is able to provide a list of zip code ranges. The format for a range is "xxxxx-xxxxx", so a zip code consists of five digits.The zip code range search query needs to be built using OR. The user's zip code can lie in one range OR another. Native SQL could look like this:
WHERE (zipCode BETWEEN :zipCodeFrom1 AND :zipCodeTo1) OR (zipCode BETWEEN :zipCodeFrom2 AND :zipCodeTo2)
To combine this with the language query, the OR part has to be nested within an AND part:
WHERE ((zipCode BETWEEN :zipCodeFrom1 AND :zipCodeTo1) OR (zipCode BETWEEN :zipCodeFrom2 AND :zipCodeTo2)) AND (EXISTS( SELECT ....To accomplish the OR nesting you can use add() on the orx expression. The following example shows how to do that:
This results in a really nice nested query like this:
SELECT u FROM Acme\UserBundle\Entity\User u WHERE ((u.zipCode BETWEEN :zipFrom1 AND :zipTo1) OR (u.zipCode BETWEEN :zipFrom2 AND :zipTo2)) AND (EXISTS( SELECT langE FROM AcmeUserBundle:Language langE WHERE langE.user = u AND langE.language = :langName AND langE.points BETWEEN 10 AND :points))
Building nested queries is really easy. It took me some time to find out that I can use add() on the orx expression to dynamically add parts to it.
No comments:
Post a Comment