はじめに
実は結構前からDoctrine2のAnnocationでValueObjectを表現する事が出来ます。
しかし、まだ正式版のリリースはありません。。。
でも知りたい方への紹介、代替案の紹介、自身の暇つぶしも兼ねて記したいと思います。
準備
Symfony2のプロジェクト内(じゃなくてもいいですがDoctrine2を動かしている環境で)
composer.jsonへ何も考えずに以下の定義を追加してcomposer updateしましょう。
"require": {
"doctrine/orm": "2.5.*@dev",
"doctrine/dbal": "v2.5.0-RC2",
}
これで準備はできました。
実装方法
http://doctrine-orm.readthedocs.org/en/latest/tutorials/embeddables.html
をみればわかります。
が、暇なので実装例について。コメントも合わせて書いていきます。
/**
* Class User
* @package RSchedule\Bundle\RScheduleBundle\Entity\User
*
* @ORM\Table(name="user")
* @ORM\Entity(repositoryClass="RSchedule\Bundle\RScheduleBundle\Entity\User\UserRepository")
*/
class User extends Entity
{
/**
* @param UserAuthority $userAuthority
*
* //これが重要、UserへUserAuthorityをEbeddedする
* //DoctrineによってUserを実態化した際に、UserAuthorityが組み込まれる
* @ORM\Embedded(class = "UserAuthority", columnPrefix = false))
*/
private $userAuthority;
}
/**
* Class UserAuthority
* @package RSchedule\Bundle\RScheduleBundle\Entity\User
*
* //これが重要、何かのクラスへ組み込まれる事を宣言している
* @ORM\Embeddable
*/
final class UserAuthority extends Enum
{
/**
* 管理者権限
*/
const ADMIN = 0;
/**
* 管理者権限なし
*/
const OTHER = 1;
/**
* //通常通りAnnotationでカラムの属性を定義可能
* @ORM\Column(name="authority", columnDefinition="TINYINT(1) DEFAULT 1 NOT NULL", options={"comment" = "権限"})
*/
private $authority;
/**
* @param $value
*/
public function __construct($value)
{
$this->authority = parent::__construct($value);
}
/**
* @return integer
*/
public function valueOf()
{
return $this->authority;
}
}
//これは色々やり方あるけどEnumっぽくしたかった(mysqlのじゃないよ)
abstract class Enum
{
public function __construct($value)
{
$ref = new \ReflectionClass(get_class($this));
$constants = $ref->getConstants();
if (!in_array($value, $constants, true)) {
throw new \InvalidArgumentException("does not definition:{$value}");
}
return $value;
}
abstract public function valueOf();
}
代替案
つかいたい、でもRC2は流石に、、、じゃあせめて正式サポート時にリファクタしやすいようにしよう、
そんな方法のご紹介です。
/**
* Class User
* @package RSchedule\Bundle\RScheduleBundle\Entity\User
*
* @ORM\Table(name="user")
* @ORM\Entity(repositoryClass="RSchedule\Bundle\RScheduleBundle\Entity\User\UserRepository")
*/
class User extends Entity
{
/**
* @param UserAuthority $userAuthority
*
* @ORM\Column(name="authority", columnDefinition="TINYINT(1) DEFAULT 1 NOT NULL", options={"comment" = "権限"})
*/
private $userAuthority;
// こんな感じでクラスにインジェクションする
public setUserAuthority(UserAuthority $userAuthority)
{
$this->userAuthority = $userAuthority->valueOf();
}
// 取り出すときもインスタンス化したクラスを返す
public getUserAuthority()
{
return new UserAuthority($this->userAuthority);
}
}
/**
* Class UserAuthority
* @package RSchedule\Bundle\RScheduleBundle\Entity\User
*
*/
final class UserAuthority extends Enum
{
/**
* 管理者権限
*/
const ADMIN = 0;
/**
* 管理者権限なし
*/
const OTHER = 1;
private $authority;
/**
* @param $value
*/
public function __construct($value)
{
$this->authority = parent::__construct($value);
}
/**
* @return integer
*/
public function valueOf()
{
return $this->authority;
}
}
abstract class Enum
{
public function __construct($value)
{
$ref = new \ReflectionClass(get_class($this));
$constants = $ref->getConstants();
if (!in_array($value, $constants, true)) {
throw new \InvalidArgumentException("does not definition:{$value}");
}
return $value;
}
abstract public function valueOf();
}
// 新規のインスタンス化はFactoryへ任せてこんな感じにすると実装がシンプルになるかも
class UserFactory
{
public function newUser()
{
$user = new User();
$user->setUserAuthority(new UserAuthority(UserAuthority::ADMIN));
return $user;
}
}
参考:
http://doctrine-orm.readthedocs.org/en/latest/tutorials/embeddables.html
[http://welcometothebundle.com/persist-the-money-doctrine-value-object/]
[https://packagist.org/packages/doctrine/orm]