Frage

Given i have 2 classes, User and UserId which look like this:

<?php

class UserId {
    /** @var int */
    private $value;

    public function __construct($value) {
        $this->value = (int) $value;
    }
}

class User {
    /** @var UserId */
    private $id;
    private $firstName;
    private $lastName;

    public function __construct(UserId $id, $firstName, $lastName) {
        $this->id = $id;
        $this->firstName = $firstName;
        $this->lastName = $lastName;
    }
}

Database:

User: 

id : INT PK
firstName: VARCHAR
lastName: VARCHAR

Is it possible to tell doctrine to generate me a User with a UserId when calling "find()"?

War es hilfreich?

Lösung

Yes, this is possible, I'll explain further on.

The simple way

First I have to say that for this simple use-case, the answer provided by Andresch Serj should suffice.

Set the UserId object using the constructor, get the UserId object by lazily instantiating it if it isn't present yet:

class User
{
    /**
     * @var UserId
     */
    private $userId;

    /**
     * @var int
     */
    private $id;

    /**
     * @param UserId $userId
     * ...
     */
    public function __construct(UserId $userId /* ... */)
    {
        $this->userId = $userId;
        $this->id     = $userId->getId();
        // ...
    }

    /**
     * @return UserId
     */
    public function getUserId()
    {
        if (!$this->userId) {
            $this->userId = new UserId($this->id);
        }

        return $this->userId;
    }

    // ...
}

The real answer

In order to manipulate an entity when it's loaded (fetched from the database) you could use Doctrine's PostLoad event.

First create a listener that will create a new UserId object and set it on the User entity:

use Doctrine\ORM\Event\LifecycleEventArgs;

class UserListener
{
    /**
     * @param  User               $user
     * @param  LifecycleEventArgs $event
     * @return void
     */
    public function postLoad(User $user, LifecycleEventArgs $event)
    {
        $userId = new UserId($user->getId());
        $user->setUserId($userId);
    }
}

Then refactor the getUserId() method of User to simple return the UserId object. Add a setUserId() method (it's wise to make sure an already present UserId object can't be swapped out). Also note the @EntityListeners annotation, which tells Doctrine there's a listener in place for this entity:

/**
 * @EntityListeners({"UserListener"})
 */
class User
{
    /**
     * @return UserId
     */
    public function getUserId()
    {
        return $this->userId;
    }

    /**
     * @param  UserId $userId
     * @return void
     * @throws RuntimeException
     */
    public function setUserId(UserId $userId)
    {
        if ($this->userId) {
            throw new RuntimeException("UsedId already present, you can't swap it!");
        }

        $this->userId = $userId;
    }

    // ...
}

Finally, in the configuration/bootstrap phase of your application you should register the listener:

$listener = new UserListener();
$em->getConfiguration()->getEntityListenerResolver()->register($listener);

Now, whenever a User entity is loaded by Doctrine, a UserId object will be inserted into it. This setup is very useful for more advanced use-cases than the one you described.

You can read more about this here and here.

Andere Tipps

If you just need your User Object to be able to deliver the UserID Object you could add it as a private attribute and add a public getter:

private $userIdObject;

public function __construct(UserId $id, $firstName, $lastName) 
{
  $this->id = $id; = $id->id;
  $this->userIdObject = $id;
  $this->firstName = $firstName;
  $this->lastName = $lastName;
}

public function getUserId()
{
  return $this->userIdObject();
}

It would really help to know why you need this. What i am saying is: Doctrine is a presentation of your Database. If you want to store the id as an integer, there is no need to have it as an object. If you need an Object to do certain things with the id (generate it, manipulate it ...) you can have a getter in your user object that generates said object for you.

public function getUserId()
{
  return new UserId($this->id);
}

Or you could have all those needed methods for manipulating your UserId in a Helper Class or Service.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top