16

I'm trying to create a form with data in collection type depending on the user being logged. I'm following this chapter of the Symfony cookbook.

Everything works fine when the query_builder option is a closure where I get my data from DQL. As the data need to be fetched from different location in code, I would prefer to define the query in the Repository class.

Here is the function in my repository :

public function findOwnedBy($user) {
    $query = $this->getEntityManager()->createQuery("SELECT l FROM MyBundle:Article a JOIN a.owndBy u WHERE u.id = :userId");
    $query->setParameters(array("userId"=>$user->getId()));
    return $query->getResult();
}

This function works when called in a Controller and return an array of Article. Here is a snippet of the symfony doc :

$formOptions = array(
                    'class' => 'Acme\DemoBundle\Entity\User',
                    'multiple' => false,
                    'expanded' => false,
                    'property' => 'fullName',
                    'query_builder' => function(EntityRepository $er) use ($user) {
                        // build a custom query, or call a method on your repository (even better!)
                    },
                );

When I put a call to my Repository function in the query_builder, I get an error : Expected argument of type "Doctrine\ORM\QueryBuilder", "array" given, which I can understand because my Repository returns an array of Entity, not a QueryBuilder.

I don't want to duplicate code and create a new QueryBuilder in the Form. What is the best practice to use the query from the Repository ? I was thinking of having two function in the repository, one returning an array and the other returning the QueryBuilder, but the comment in Symfony doc "or call a method on your repository (even better!)" let me think there's better way for this case.

chadyred
  • 424
  • 1
  • 9
  • 19
Florent
  • 806
  • 2
  • 8
  • 14

2 Answers2

28

It should be easy. Do the following:

public function queryOwnedBy($user) {

    $query = $this->createQueryBuilder('a')
            ->from('MyBundle:Article', 'a')
            ->innerJoin('a.owndBy', 'u')
            ->where('u.id = :id')                
            ->setParameter('id', $user->getId());

    return $query;
}

public function findOwnedBy($user) {
    return $this->queryOwnedBy($user)
            ->getQuery()
            ->getResult();
}

Then in the form builder:

$formOptions = array(
    'class' => 'Acme\DemoBundle\Entity\User',
    'multiple' => false,
    'expanded' => false,
    'property' => 'fullName',
    'query_builder' => function(EntityRepository $er) use ($user) {
        return $er->queryOwnedBy($user);
    },
);

EDIT

Thank's for ncatnow and unagi I've changed the previous functions to return the querybuilder

saamorim
  • 3,855
  • 17
  • 22
  • I also though it should be easy and that was my first try. This return me the error `Expected argument of type "Doctrine\ORM\QueryBuilder", "array" given`. Seem that `query_builder` expect a QueryBuilder object, whatever it is given directly or returned by a closure. – Florent Jul 16 '13 at 13:12
  • Edited the post. Create two function, on which returns the query and another which returns the result. On the form builder call the function that returns the query. That should work and still is DRY. Sorry, I'll change the names as they aren't appropriate. – saamorim Jul 16 '13 at 13:22
  • hehe, it's indeed what I did and what I describe in the last paragraph of the question. I'll go that way, the small comment in Symfony's doc let think it can work out of the box, it's confusing ;) – Florent Jul 16 '13 at 13:42
  • @Florent Yes, sorry, didn't notice that last paragraph with the necessary attention. – saamorim Jul 16 '13 at 15:46
  • The aim of my question was to know if there is a better way, but it seems not. I accept your answer, as this short discussion is the point. – Florent Jul 17 '13 at 06:56
  • 7
    Note the the example code above is still incorrect - it's returning a Query not a QueryBuilder and will fail. – ncatnow Sep 30 '13 at 06:31
  • This line saved my day: `'query_builder' => function(EntityRepository $er) use ($user)`. Thank you for the answer. – Ragnar Jul 21 '17 at 19:58
8

I just did a little fix of saamorim answer. The working code would be something like this:

public function queryOwnedBy($user) {

    $query = $this->createQueryBuilder("u")
            ->where('u.id = :id')                
            ->setParameter('id', $user->getId());

    return $query;
}

public function findOwnedBy($user) {
    return $this->queryOwnedBy($user)
            ->getQuery()
            ->getResult();
}
unagi
  • 81
  • 1
  • 2
  • Thank you. I've integrated your answer in my post and changed the query to be according to the example. – saamorim Jul 14 '14 at 10:32