这是合约。 使用Doctrine ORM for PHP,我需要"解耦"来自实体持久层的模型。 假设我们有UserEntity,其中包含db映射的所有漂亮内容, as:注释,属性,setter / getters等。 另一方面,我希望有一个单独的User类,它只保存与业务相关的逻辑,例如:User :: getFullName()。 此外,我希望用户扩展UserEntity,以便用户继承所有访问方法。
我可以通过不为我工作来检查可能的解决方案:
任何想法?
答案 0 :(得分:3)
得了! (> = PHP 5.4解决方案)
简短:使实体成为特征,在模型类中使用实体特征。 查看此文档页面:http://doctrine-orm.readthedocs.org/en/latest/tutorials/override-field-association-mappings-in-subclasses.html。
实施例: 假设我们有用户模型。首先创建用户实体:
/**
* @ORM\Table(name="user")
*/
trait UserEntity {
/**
* @var integer
*
* @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @var string
*
* @ORM\Column(name="first_name", type="string", length=100, nullable=true)
*/
protected $firstName;
/**
* @var string
*
* @ORM\Column(name="last_name", type="string", length=100, nullable=true)
*/
protected $lastName;
// other mapping here...
}
然后创建一个模型并在其中使用实体特征:
/**
* @ORM\Entity
*/
class User {
use UserEntity;
public function getFullName() {
return $this->firstName . ' ' . $this->lastName;
}
}
在用户模型中注意@Entity注释。这是直接使用模型所必需的 在实体经理。
现在假设我们需要一个扩展User one的Admin模型。这有点棘手。 我们必须将@Entity更改为User中的@MappedSuperclass,以便进行扩展。 然后创建Admin模型,将其声明为@Entity,并在其上重新声明表名 使用@Table注释(否则,由于某些原因,Doctrine会因为要获取哪个表而混淆)。 看起来像这样:
/**
* @ORM\MappedSuperclass
*/
class User {
use UserEntity;
public function getFullName() {
return $this->firstName . ' ' . $this->lastName;
}
}
/**
* @ORM\Entity
* @ORM\Table(name="user")
*/
class Admin extends User {
public function getFullName() {
return parent::getFullName() . ' (admin)';
}
}
这样,用户和管理模型(=实体)都可以在Doctrine中使用。
我们不能做任何我们通常对实体做的事情: 通过实体管理器查找()它们,直接在查询中使用模型等。
答案 1 :(得分:0)
您可以在PHP中使用魔术方法来转发所有的访问者方法调用,例如:
class UserModel
{
protected $userEntity;
public function __construct($entity)
{
$this->userEntity = $entity;
}
public function __call($name, $arguments)
{
if (!method_exists($this, $name) AND method_exists($this->userEntity, $name)) {
return call_user_func_array(array($this, $name), $arguments);
}
}
}
您可以定义自己的本地EntityRepository类,该类扩展Doctrine\ORM\EntityRepository
。这样,您可以确保find
,findBy
,findOneBy
方法将创建模型的新实例,在模型中设置$ entity对象并返回新的Model实例而不是实体。
您可以编写一个模型类(不将其注册到Doctrine2中),它扩展实体类并编写您自己的自定义Hydrator类(并将其注册到Doctrine2中),以确保您的结果将作为Model类的数组返回不是Entity类的数组。
您可以定义所有这些"与数据库相关的业务逻辑"在您的实体存储库类和所有这些"非数据库相关的业务逻辑"在服务类中(如果您愿意,可以创建专用于一个实体的服务)。然后使用db-logic参数(实体)调用业务逻辑层(服务,存储库)。
另一方面,Symfony方式非常灵活,因为只要它们是PSR,你就可以在预先建立的Symfony结构之外构建任何功能。
答案 2 :(得分:0)
关于定制保湿器。 简而言之,这个解决方案也不适合我(我可能会遗漏任何东西)。这里有两个陷阱:
因此,Mihai Stancu建议的任何解决方案都不适合我。
答案 3 :(得分:0)
好吧,我最近一直问自己这个问题,而我得到的简单答案是将所有的anotations从实体中移到yaml或xml中,以便整理我的“模型”/实体。
然后我的所有属性都在我的用户类中,但是所有的持久性配置都已移出,那么你也可以用getter和setter做任何你想做的事情(在我看来尽可能多地删除)。