Doctrine映射2个具有1个表的对象

时间:2014-01-05 18:05:49

标签: php doctrine-orm ddd-repositories

鉴于我有2个类,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生成一个用户?

2 个答案:

答案 0 :(得分:3)

是的,这是可能的,我会进一步解释。

简单方法

首先我必须说,对于这个简单的用例,answer provided by 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 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);
    }
}

然后重构getUserId() User方法以简单地返回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个对象。此设置对于比您描述的更高级的用例非常有用。

您可以详细了解这个herehere

答案 1 :(得分:0)

如果您只需要您的用户对象能够提供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();
}

知道你为什么需要它真的很有帮助。 我的意思是:Doctrine是一个数据库的演示文稿。如果要将id存储为整数,则无需将其作为对象。 如果你需要一个Object用id来做某些事情(生成它,操纵它...... )你可以在你的用户对象中有一个getter来为你生成所述对象。

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

或者您可以拥有在Helper类或服务中操作UserId所需的所有方法。