gpt4 book ai didi

php - 使用 Doctrine ORM 实现状态模式

转载 作者:行者123 更新时间:2023-12-03 23:24:10 25 4
gpt4 key购买 nike

我有一个使用状态模式的类。这是一个简单的例子

/**
* @Enitity
**/
class Door
{
protected $id;
protected $state;
public function __construct($id, DoorState $state)
public function setState(DoorState $state)
{
$this->state = $state;
}
public function close()
{
$this->setState($this->state->close())
}
...
}

interface DoorState
{
public function close;
public function open;
public function lock;
public function unlock;
}

class DoorAction implements DoorState
{
public function close()
{
throw new DoorError();
}
...
}

然后是几个定义状态中适当 Action 的类
class OpenedDoor extends DoorAction
{
public function close()
{
return new ClosedDoor();
}
}

所以我会有一些像
$door = new Door('1', new OpenedDoor());
DoctrineDoorRepository::save($door);
$door->close();
DoctrineDoorRepository::save($door);

我将如何在 Doctrine 中实现映射以便我可以坚持它?
我被卡在 $state 属性(property)上。我想保存整个基于 DoorAction 的对象,但我是否必须映射 DoorAction 父类(super class)或每个单独的子类?

我看过使用 Embeddable 来实现它或 SuperMapping但每个人都会遇到问题。

最佳答案

Doctrine2 DBAL 在文档中有一个特性,允许 ENUM
https://www.doctrine-project.org/projects/doctrine-orm/en/current/cookbook/mysql-enums.html#mysql-enums
当我们取解决方案 2:定义类型 作为基础,可以创建自己的类型,例如名为 doorstatetype或类似的表示打开/关闭状态。例如像这样:

<?php
namespace Acme\Model\Door;

use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;

class DoorStateType extends Type
{
const ENUM_DOORSTATE = 'enumdoorstate';
const STATE_OPEN = 'open';
const STATE_CLOSED = 'closed';

public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return "ENUM('" . self::STATE_OPEN . "', '" . self::STATE_CLOSED . "') COMMENT '(DC2Type:" . ENUM_DOORSTATE . ")'";
}

public function convertToPHPValue($value, AbstractPlatform $platform)
{
return $value;
}

public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if (!in_array($value, array(self::STATE_OPEN, self::STATE_CLOSED))) {
throw new \InvalidArgumentException("Invalid state");
}

return $value;
}

public function getName()
{
return self::ENUM_DOORSTATE;
}
}
然后像这样使用它:
<?php

namespace Acme\Model\Door;

/** @Entity */
class Door
{
/** @Column(type="enumdoorstate") */
private $state;

public function open()
{
if (!DoorStateType::STATE_OPEN === $this->state) {
throw new \LogicException('Cannot open an already open door');
}

$this->state = DoorStateType::STATE_OPEN;
}

public function close()
{
if (!DoorStateType::STATE_CLOSED === $this->state) {
throw new \LogicException('Cannot close an already closed door');
}

$this->state = DoorStateType::STATE_CLOSED;
}
}
这允许搜索状态:
$openDoors = $repository->findBy(array('state' => DoorStateType::STATE_OPEN));
你基本上可以拥有 convertToPHPValue方法创建允许某些逻辑的所需状态的对象,例如检查打开的门是否可以锁定或类似。
在状态必须是包含逻辑的类的情况下,您可以像这样实现它:
首先我们定义一个可以继承的正常状态:
<?php
namespace Acme\Model\Door;

abstract class DoorState
{
// Those methods define default behaviour for when something isn't possible
public function open()
{
throw new \LogicException('Cannot open door');
}

public function close()
{
throw new \LogicException('Cannot close door');
}


abstract public function getStateName();
}
然后是 OpenState:
<?php
namespace Acme\Model\Door;

class OpenState extends DoorState
{
const STATE = 'open';

public function close()
{
return new ClosedState();
}

public function getStateName()
{
return self::STATE;
}

// More logic
}
最后是 ClosedState:
<?php
namespace Acme\Model\Door;

class ClosedState extends DoorState
{
const STATE = 'closed';

public function open()
{
return new OpenState();
}

public function getStateName()
{
return self::STATE;
}

// More logic
}
然后,为了持久性,我们可以简单地使用不同的转换方法:
<?php
namespace Acme\Model\Door;

use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;

class DoorStateType extends Type
{
// SQL declarations etc.

public function convertToPHPValue($value, AbstractPlatform $platform)
{
if ($value === OpenState::STATE) {
return new OpenState();
}

if ($value === ClosedState::STATE) {
return new ClosedState();
}

throw new \Exception(sprintf('Unknown state "%s", expected one of "%s"', $value, implode('", "', [OpenState::STATE, ClosedState::STATE])));
}

public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return $value->getStateName();
}
}

关于php - 使用 Doctrine ORM 实现状态模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31411381/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com