假设我有两个类,User和UserId,看起来像这样:
<?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
在调用"find()"时,是否可以告诉条令为我生成一个具有UserId的用户?
是的,这是可能的,我将进一步解释。
简单的方法
首先,我必须说,对于这个简单的用例,Andresch Serj提供的答案应该足够了。
使用构造函数设置UserId
对象,如果UserId
对象还不存在,则通过延迟实例化获得:
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;
}
// ...
}
真正的答案
为了在实体加载(从数据库中提取)时对其进行操作,可以使用Doctrine的PostLoad
事件。
首先创建一个监听器,该监听器将创建一个新的UserId
对象并将其设置在User
实体上:
use DoctrineORMEventLifecycleEventArgs;
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);
}
}
然后重构User
的getUserId()
方法以简单地返回UserId
对象。添加一个setUserId()
方法(明智的做法是确保已经存在的UserId
对象不能交换)。还要注意@EntityListeners
注释,它告诉Doctrine这个实体有一个监听器:
/**
* @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;
}
// ...
}
最后,在应用程序的配置/引导阶段,您应该注册侦听器:
$listener = new UserListener();
$em->getConfiguration()->getEntityListenerResolver()->register($listener);
现在,每当Doctrine加载User
实体时,就会在其中插入一个UserId
对象。这种设置对于比您描述的更高级的用例非常有用。
你可以在这里和这里阅读更多关于这方面的信息。
如果您只需要用户对象能够传递UserID对象,您可以将其添加为私有属性并添加公共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();
}
知道你为什么需要这个真的很有帮助。我想说的是:条令是你们数据库的一个展示。如果您想将id存储为整数,则不需要将其作为对象。如果你需要一个对象来用id做某些事情(生成它,操作它…),你可以在你的用户对象中有一个getter来为你生成所述对象。
public function getUserId()
{
return new UserId($this->id);
}
或者,您可以在Helper类或服务中拥有操作UserId所需的所有方法。