条令映射2个对象和1个表



假设我有两个类,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);
}
}

然后重构UsergetUserId()方法以简单地返回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所需的所有方法。

相关内容

  • 没有找到相关文章

最新更新