bernhardh
bernhardh

Reputation: 3309

How to dynamically change doctrine queries in symfony

Lets say, I have a class Movie with a Orm\OneToMany relation ship to the class Actors.

I have already a working example of an getter for $movie->getActors(); which will return all actors of that movie.

But how to dynamically modify the query for that? For example, I show a list of all actors of the movie, and allow the user to sort by name, age, gender, whatever.

===== EDIT ======

After learning, that such things belongs to the repository class (thanks to Yoshi, scoolnico), here is the adapted question:

Lets say, I have got a Movie ID 4711. I will fetch the movie:

$movie = $this->getDoctrine()
    ->getRepository("Movie")
    ->find(4711);

And now, I need to get all Actors from this movie sorted by name (as an example).

$actorsOfMovie = $this->getDoctrine()
    ->getRepository("Actor")
    ->findBy(array("movie_id" => 4711), array('name'=>'asc'));

Is this really the correct way? With this version, I need to know in the controller, how the relationship between movie and actors work! Thats a thing, doctrine should handle for me!

And how to use it with multiple movies?

// Controller
$movies = $this->getDoctrine()
    ->getRepository("Movie")
    ->findfindBy(array());
return $this->render("xyz.html.twig", array("movies": $movies));

// Twig: xyz.html.twig
{% for movie in movies %}
    <h1>{% movie.getName() %}</h1>
    <p>Actors: {% for actor in movie.getActorsOrderByName() %}{{ actor.getName() }},{% endfor %}
{% endfor %}

Upvotes: 0

Views: 1233

Answers (2)

bernhardh
bernhardh

Reputation: 3309

I think the best solution for this is to use doctrine's Criteria class (http://docs.doctrine-project.org/en/latest/reference/working-with-associations.html#filtering-collections).

Have a look at https://www.boxuk.com/insight/blog-posts/filtering-associations-with-doctrine-2

Based on this, I can do the following:

// In the Movie Class
/**
 * Get actors
 *
 * @param array $options
 *
 * @return \Doctrine\Common\Collections\Collection
 */
public function getActors($options = array())
{
    if(!$options) {
        return $this->actors;
    }

    $criteria = Criteria::create();

    if(isset($options["order_by"])) {
        $criteria->orderBy($options["order_by"]);
    }
    if(isset($options["limit"])) {
        $criteria->setMaxResults($options["limit"]);
    }
    if(isset($options["offset"])) {
        $criteria->setFirstResult($options["offset"]);
    }
    // Or I can define other filters or sorting stuff
    if(..) {
        ...
    }

    return $this->actors->matching($criteria);
}

Upvotes: 0

scoolnico
scoolnico

Reputation: 3135

You just have to create a specific function in your class Repository:

class MovieRepository extends EntityRepository
{
   public function getActoryByGender($gender)
   { 
       /.../
   }
}

And in your controller:

/.../
$em = $this->getDoctrine()>getManager();
$repository = $em->getRepository('YourBundle:Movie');
$actors = $repository->getActorByGender('male');
/.../

Upvotes: 1

Related Questions