Symfony form query_buider and entity repository
Asked Answered
B

2

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.

Bronchitis answered 16/7, 2013 at 12:39 Comment(0)
C
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

Chur answered 16/7, 2013 at 13:1 Comment(7)
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.Bronchitis
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.Chur
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 ;)Bronchitis
@Bronchitis Yes, sorry, didn't notice that last paragraph with the necessary attention.Chur
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.Bronchitis
Note the the example code above is still incorrect - it's returning a Query not a QueryBuilder and will fail.Mirage
This line saved my day: 'query_builder' => function(EntityRepository $er) use ($user). Thank you for the answer.Euxenite
S
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();
}
Streamliner answered 22/1, 2014 at 21:57 Comment(1)
Thank you. I've integrated your answer in my post and changed the query to be according to the example.Chur

© 2022 - 2024 — McMap. All rights reserved.