Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2/Doctrine How to store count of related objects within an Entity

I have set up a bundle that has a test object which holds a number of testQuestion objects each of which is a question and the given answer (or 0 if no answer). From twig I want to be able to get the information from the test object to say how many questions there are and how many have been answered.

I have created a query to pull this out of the db, and in the Test Entity I have created 2 new properties to store the number of questions and the number answered. I have created a TestRepository inside which the query resides. The Test object checks to see if the object has the value set and if not loads it when needed as I won't always need this information.

However I'm stuck on how to link the repository code to the test object, both to call the repo function and for the repo function to save the values to the relevant Test object.

Acme/Quizbundle/Test/Test.php

namespace Acme\QuizBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Acme\QuizBundle\Entity\TestRepository;

/**
 * @ORM\Entity(repositoryClass="Acme\QuizBundle\Entity\TestRepository")
 * @ORM\Table(name="test")
 */
class Test    {
protected $numQuestions = null;
protected $numQuestionsAnswered = null;

public function getNumQuestionsAnswered () {
    if (is_null($this->numQuestionsAnswered)) {
        $repository = $this->getEntityManager()->getRepository('\AcmeQuizBundle\Test');
        $values = $repository->calculateNumQuestions();
    }
    return $this->numQuestionsAnswered;
}

Acme/Quizbundle/Test/TestRepository.php (There's a matching method for getNumQuestions())

namespace Acme\QuizBundle\Entity;

use Doctrine\ORM\EntityRepository;

class TestRepository extends EntityRepository {

private function calculateNumQuestions() {

    $qb = $this->getEntityManager()
                ->createQueryBuilder();

    $query = $this->getEntityManager()->createQueryBuilder()
                        ->select('COUNT(id)')
          ->from('testquestion', 'tq')
          ->where('tq.test_id = :id')
          ->setParameter('id', $this->getId())
          ->getQuery();

    $result = $query->getSingleScalarResult();
    var_dump($result);
    }
like image 305
Al_ Avatar asked Jul 13 '12 15:07

Al_


1 Answers

There are a number of different patterns you can use to achieve this result, the simplest of which is to simply use an aggregate field. This stores the information after it's modified, rather than calculating it each time that it's needed.

An alternate solution is to create a one-to-many association between your Test and TestQuestion repositories (assuming that there isn't one already), then in your twig template you can simply use {{ testEntity.questionsAnswered.count() }} - you can even tell Doctrine to make this an "extra-lazy" association so that it uses the COUNT SQL statement to look up how many answered questions there are (by default it actually fetches the question entities when you try to enumerate the association).

Finally, there's the method that I wouldn't recommend highly, but might be required depending on your situation. Similar to the approach that you use in your question, you fetch the question count in your repository, but to keep with Symfony's simple Model approach, you don't kick off the query from inside the entity (as the entity should never have information about the entity manager/repository).

Instead, you can use a Doctrine EventListener to be informed whenever an instance of your Test entity is loaded (see here, using the postLoad event), then call your repository method and set it on the entity from there.

like image 174
Lachlan Pease Avatar answered Sep 22 '22 19:09

Lachlan Pease