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;
}
}
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()"?
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.