0

I have 2 entities:

class Opponent
{
  ...
  ...
  ...
}

class Process 
{

    /**
     * @var array
     * 
     * @ORM\Column(name="answers_in_related_questionnaires", type="json", nullable=true)
     */
    private $answersInRelatedQuestionnaires = [];

    .
    .        
    . 

}

I have in the field answersInRelatedQuestionnaires amongst other things the object opponent

"opponent": {
 "id":1088,
 "name":"Inora Life Versicherung"
}

I want to write a getter in the entity process, that gets not only the both values id and name from opponent, but the whole entity Opponent. Something like this:

private function getOpponent() : Opponent
{
    $id = $this->answersInRelatedQuestionnaires['opponent']['id'];
    return $entityManager->getRepository(Opponent::class)->find($id)
}

I have read, that using of the entity manager within the entity is not a good idea. Which solutions for my issue are there? Can I use the Process repository in the Process entity?

olek07
  • 513
  • 2
  • 7
  • 21

1 Answers1

1

You should not inject entity manager in an entity, it's a very bad practice and violates the separation of concerns between classes. BUT if you really want you indeed can inject entity manager in your entity.

GOOD PRACTICE:

Create a Model/Process class and include there any functionality that concerns your model. Doctrine entities are not model classes. In Model/Process you can inject the entity manager and any other service, you need.

EDIT: By creating a Model/Process class I mean creating a class named Process inside Model directory in your /src folder. Your path of your class will be: /src/Model/Process. Of course, the name of the directory or the class can by anything, but this is a typical convention. Your Model class should be responsible for all your business logic, such as validation of your model etc. This will indeed make your code structure more complicated but will be a savor in the long run for large scale projects. You will also need a Model/ProcessManager to properly populate Process model in different cases (e.g. when loaded from Database, user form etc.) Of course, in the end it's all a matter of trade-off between complexity and sustainability.

An interesting approach about models in Symfony, mostly applicable in large scale projects, can be found here.

ALTERNATIVES:

If you access the opponent attribute only after an entity has been loaded you can use Doctrine PostLoad LifecycleCallback to properly set opponent attribute. This is not a bad practice:

use Doctrine\Common\Persistence\Event\LifecycleEventArgs;

/**
 * @ORM\Entity()
 * @ORM\HasLifecycleCallbacks()
 */
class Product
{
    // ...
    private $opponentObject;

    /**
     * @ORM\PostLoad
     */
     public function onPostLoad(LifecycleEventArgs $args){
         $em = $args->getEntityManager();

         $id = $this->answersInRelatedQuestionnaires['opponent']['id'];
         $this->opponentObject = $em->getRepository(Opponent::class)->find($id);

     }

     public function getOpponent() {
         return $this->opponent;

     }
} 

Finally if you really really want to inject the entity manager into your entity you can achieve that with dependency injection via autowiring:

use Doctrine\ORM\EntityManagerInterface;

class Process
{
    private $em;

    public function __contruct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }
    ....
}
iiirxs
  • 4,493
  • 2
  • 20
  • 35
  • No, I don't want to inject entity manager. I know, it's a a very bad practice. I find the solution with onPostLoad interesting. But what do you mean with Model/Process? I don't understand it. Can you explain detailed, please? – olek07 Dec 07 '18 at 12:04
  • 1
    The solution with onPostLoad works, if I fetch the data with $this->getDoctrine()->getRepository(Process::class)->find(2000000); But doesn't work, if I fetch the data with query builder $qb = $this->createQueryBuilder('p') ->select('p') ->where('p.id = :processId') ->setParameter('processId', 2000000); – olek07 Dec 07 '18 at 12:48
  • 1
    Edited my answer to better explain the model/process suggestion. It's a more complicated solution. – iiirxs Dec 07 '18 at 12:52