Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Doctrine, how to achieve additional model functionalities for Entity

Let's say I have an Doctrine's (version 2) entity as follows:

<?php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * User
 *
 * @ORM\Table(name="users")
 * @ORM\Entity
 */
class User {
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=50, nullable=false)
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="group_id", type="string", length=6, nullable=true)
     */
     private $groupId;

    // Getters and setters...
}

Now, I would like to manage User's relation to Group, but with some conditions, like:

  1. returning NULL (or some sort of skeleton/template of \AppBundle\Entity\Group with fixed values not loaded from database) if Group of users.group_id does not exist, even if it is set to a value (no key restrictions set in the database to prevent this behaviour), so some sort of validation/check required
  2. lazy load Group, when calling $user->getGroup()

I am reading Google on and on and I'm confused of how to achieve that properly (in the line with Doctrine/Symfony way).

I could add a ManyToOne to the entity's class relation like this:

/**
 * @var \AppBundle\Entity\Group
 *
 * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Group")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="group_id", referencedColumnName="id")
 * })
 */
private $group;

But then how to prevent exceptions caused by non-existing foreign keys? I.e. I would like to retrieve user's group details when it is available in my database, but when it is not I do not want Doctrine to throw an exception an crash my application.

People say that using an Entity Manager from within an Entity is a very bad practice and I agree. But I am confused about using Proxy Objects or Inheritance Mapping for this purposes.

It seems like using Models could be the way, but I couldn't find any strong documentation of how to properly implement them in Doctrine2.

Please help if you can. In Kohana it was so, so simple (but immature this way).


EDIT:

@Massimiliano Fedel suggested trying catching an exception in User::getGroup() method, to eventually make non-existed groups return as NULL.

So I have commited this code:

/**
 * Get group
 *
 * @return \AppBundle\Entity\Group
 */
public function getGroup() {
    try {
        $group = $this->group;
    } catch (\Doctrine\ORM\EntityNotFoundException $e) {
        $group = null;
    }
    return $group;
}

Unfortunatelly, it seems that exception cannot be catched this way, because framework exits with an Doctrine\ORM\EntityNotFoundException:

Entity of type 'AppBundle\Entity\Group' for IDs id(999) was not found

EDIT 2:

Below you can find some basing schema of User flow, i.e. why I can not ensure that all Users will have available Groups in my database.

enter image description here

like image 878
roomcays Avatar asked Feb 12 '16 13:02

roomcays


2 Answers

1)Have you tried catching the exception inside the getter method of the "group"? so that you can catch the exception and return "null" in case an exception occured.

2) as from the doctrine 2.1 documentation: "Associations are marked as Lazy by default, which means the whole collection object for an association is populated the first time its accessed." http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html

like image 148
Massimiliano Fedel Avatar answered Oct 05 '22 02:10

Massimiliano Fedel


Well, what about creating a service, that is going to wrap your CRUD operations on the User entity, let's say UserService? This way, you can leave group_id as it is and add group field that is not managed (no annotations, not persisted to DB).

The UserService will have getGroup method, that will take User as an argument, then retrieve his group_id and use EntityManager (or indeed GroupService) to fetch the Group entity, if none was found, you will return null, otherwise you will set the returned Group to the unmanaged field of the entity, so you don't have to fetch it again next time.

like image 28
Jan Mares Avatar answered Oct 05 '22 04:10

Jan Mares