我有一个包含大量链接属性的实体,当我处理CSV导入时,我不想为所有链接字段创建$em->getReference()
次调用(主要是因为我希望尽可能保持抽象,并且不想对所有可能的引用进行硬编码。
我更愿意在给定属性的Entity setter方法中执行此操作。然而,这需要我从模型中获取学说,而这又是一种不好的做法。
我应该访问实体的元数据并从那里开始,还是有更好的方法,我还没有提到过?
答案 0 :(得分:1)
在setter中做这件事,真的搞砸了整个SOA的事情。如果您关心的是解耦和抽象的代码,您可以使用Dependency Inversion
假设您有实体A
,它与实体B
和C
有关联,然后从原始数据中获取对正确B
和C
个实例的引用你从CSV
获得,你将定义两个接口,例如:BRepositoryInterface
和CRepositoryInterface
,它们都可能包含一个方法find($id)
,但它们仍然必须是不同的。现在让各个实体的Doctrine Repositories实现这些接口并将它们注入到创建实体A
的服务中。
如果你真的想要制作一些好的代码,那么你应该创建实现每个接口的单独的类,然后将你的Doctrine存储库注入它们,然后这些类充当这些存储库的包装器,这样你在{之间就有了一个独特的层。 {1}}图层和您的DataMapper
图层,它可以为您提供所需的抽象
这是我在最近关于良好代码business logic
和设计模式的研究中所学到的。它不是近乎完美的地方(不是有这样的事情)。任何想法/评论将不胜感激。
更新:关于您的评论:
优秀设计所追求的主要内容之一是“捕捉领域专家的语言”,(有关这些传奇人物的描述,请参阅this source第4项).ie:你的简单英语代码是什么?
您的代码所说的基本上是从与DDD
关联的实体的存储库中找到具有这些给定ID的对象。这看起来非常好,因为您没有明确依赖A
与A
的关联但仔细观察,你会发现你确实依赖于实际的B
和C
对象及其存储库,因为当你提供 id
对于某些Object,你不只是提供id
,而且你也隐含地说明了那个对象是什么,否则id
除了它的标量值之外没有任何意义。但是这种方法肯定有设计的语义和 RAD 的用例。但仍然存在 Demeter法的问题,但它可以解决,见下文:
无论哪种方式,我认为你肯定应该有一个A
对象的工厂看起来像这样。
class AFactory{
protected $br;
protected $cr;
public function __construct(BRepositoryInterface $br, CrepositoryInterface $cr){
$this->br = $br;
$this->cr = $cr;
}
public function create($atr1, $atr2, $bId, $cId){
$b = $this->br->find($bId);
$c = $this->cr->find($cId);
return new A($atr1, $atr2, $bId, $cId);
}
}
现在您可以使用您为此工厂建立另一家工厂所述的设计来创建此工厂,这也将解决 Demeter法的问题。该工厂将拥有{{1}作为它的依赖,它将读取Entity Manager
的元数据,并根据该元数据获取相关对象的存储库,并从这些存储库创建一个新的A
实例,现在,如果您实现这些接口(AFactory
和BRepositoryInterface
)在您的实际Doctrine存储库中,CRepositoryInterface
实例将成功创建。