1
votes

I have an entity called User which has inheritance for Student, Professional and Business.

When a user is registered, is only a User but they must update their profile and choose which kind of user is, I have a form which handles this, a controller which gets the form data, but I can't update the discriminator field type with $userEntity->setType()

This is my mapping stuff

class User
{
    const TYPE_BASIC        = "Basico";
    const TYPE_STUDENT      = "Estudiante";
    const TYPE_PROFESSIONAL = "Profesional";
    const TYPE_BUSINESS     = "Empresa";

    protected $type = self::TYPE_BASIC;

    public function getType()
    {
        return self::TYPE_BASIC;
    }
    public function setType($type)
    {
        $this->type = $type;
    }

class Student extends User
{
    protected $type = self::TYPE_STUDENT;

And then Professional and Business just like Student (changing const)

<entity name="User" table="user_base" inheritance-type="JOINED">
    <discriminator-column name="type" type="string"/>
    <discriminator-map>
        <discriminator-mapping value="Basico" class="User"/>
        <discriminator-mapping value="Estudiante" class="Student"/>
        <discriminator-mapping value="Profesional" class="Professional"/>
        <discriminator-mapping value="Empresa" class="Business"/>
    </discriminator-map>

the child tables are named user_xxx where xxx = Student/Professional/Business

And this is my controller

    if($form->isValid())
    {
        $em         =   $this->getDoctrine()->getManager();

        $data       =   $form->all();
        $type       =   $data['type']->getData();
        $email      =   $data['email']->getData();
        $profile    =   $data['profile']->all();
        $name       =   $profile['name']->getData();
        $lastName   =   $profile['lastName']->getData();
        $birth      =   $profile['birth']->getData();

        $profileEntity  = new Profile();
        $profileEntity->setBirth($birth);
        $profileEntity->setName($name);
        $profileEntity->setLastName($lastName);
        $profileEntity->setUser($user);

        $em->persist($profileEntity);
        ladybug_dump($type);
        $userEntity =   $em->getRepository('User')->find($user);
        $userEntity->setProfile($profileEntity);
        $userEntity->setType($type);
        if($user->getEmail() != $email)
            $userEntity->setEmail($email);
        $em->persist($userEntity);

        $em->flush();

    }

Everything is persisted but type field, which remains it's original data. I know when I change discriminator column I need to create a new row inside it's child element, but first I want to know how to change the discriminator column.

2

2 Answers

1
votes

it is possible if you use this custom bit of code in the Form of a Trait which you can use inside a Repository.

The Trait:

namespace App\Doctrine\Repository;

use App\Exception\InvalidDiscriminatorClassException;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;

/**
 * Discriminator Trait
 */
trait DiscriminatorTrait
{
    /**
     * @return ClassMetadata
     */
    abstract public function getClassMetadata();

    /**
     * @return EntityManager
     */
    abstract public function getEntityManager();

    /**
     * Update Discriminator Column
     *
     * @param integer $id
     * @param string $class
     * @return boolean
     * @throws InvalidDiscriminatorClassException
     */
    private function updateDiscriminatorColumn($id, $class)
    {
        /* @var ClassMetadata $classMetadata */
        $classMetadata = $this->getClassMetadata();

        if (!in_array($class, $classMetadata->discriminatorMap)) {
            throw new InvalidDiscriminatorClassException($class);
        }

        $identifier = $classMetadata->fieldMappings[$classMetadata->identifier[0]]["columnName"];

        $column = $classMetadata->discriminatorColumn["fieldName"];
        $value = array_search($class, $classMetadata->discriminatorMap);

        /* @var Connection $connection */
        $connection = $this->getEntityManager()->getConnection();

        try {
            $connection->update(
                $classMetadata->table["name"],
                [$column => $value],
                [$identifier => $id]
            );
        }
        catch (DBALException $e) {
            return false;
        }

        return true;
    }
}
0
votes

According to the Doctrine documentation on Inheritance mapping, it is not possible to either get or set the type. You may wish take advantage of PUGXMultiUserBundle, which readily handles the mapping. This bundle also makes it possible for your users to register with the appropriate profile.