将业务逻辑与 PHP 原则 2 分开
Separating business logic from PHP Doctrine 2
我使用 symfony 2.3 和 php 学说 2。
程序有以下型号:
- 实体订单 - 典型的客户订单
- entity BadOrderEntry(fields: id, order - 与 Order, createdAt 的单向一对一关系)
- 创建实体 BadOrderEntry 的工厂 BadOrderEntryFactory
- 存储库 BadOrderEntryRepository 用于实体 BadOrderEntry 的搜索方法
- 实体 BadOrderEntrysave/edit/delete 方法的管理器 BadOrderEntryManager
AND MAIN CLASS BadOrderList - 错误订单列表,此代码 class:
private $factory;
private $repository;
private $manager;
public function __construct(
BadOrderEntryFactory $f,
BadOrderEntryRepository $r,
BadOrderEntryManager $m
) {
$this->factory = $f;
$this->repository = $r;
$this->manager = $m;
}
public function has(Order $order)
{
return $this->repository->existsByOrder($order);
}
public function add(Order $order)
{
if (! $this->has($order)) {
$entry = $this->factory->create($order);
$this->manager->save($entry);
}
}
public function remove(Order $order)
{
$entry = $this->repository->findOneByOrder($order);
if ($entry !== null) {
$this->manager->delete($entry);
}
}
我非常喜欢这个class的设计。我想了很多。
一切都很棒。但!存在一个问题:添加和删除方法中的操作必须在事务中执行。
PHP 原则 2 中的交易代码如下所示:
<?php
$em->getConnection()->beginTransaction();
try {
//... do some work
$em->getConnection()->commit();
} catch (Exception $e) {
$em->getConnection()->rollback();
throw $e;
}
但是我如何在 BadOrderList 中调用这段代码?
我花了很多时间去掉依赖数据库(和相应的PHPDoctrine 2),然后重新创建呢?
现在依赖隐藏在 classes BadOrderEntryRepository 和 BadOrderEntryManager 中。
如何在classBadOrderList中隐藏对事务机制的依赖?
您可以将 class 转换为服务,并在将服务容器注入 class 后随心所欲地调用它。
您可以在此处找到有关 dependency injection 的更多信息:
$injectedContainerOfService->get("id_of_your_service")
经过我们的讨论,我对你的问题有了答案。
问题实际上不是 "How to hide the dependence on the transaction mechanism in class BadOrderList?",而是 如何将模型与持久层分离?(在该特定情况下为 Doctrine2)。
我试着用一些代码来说明我的建议
class BadOrderEntry
// Bad - is too bad word to describe an order here. Why is it bad? Is it Declined? Cancelled?
{
private $order;
// some code
}
class BadOrderEntryFactory
{
// If there is not to much processing to build BadOrderEntry better use factory method like BadOrderEntry::fromOrder($order);
}
class BadOrderEntryRepository
{
// here is some read model
}
class BadOrderEntryManager
// ITS a part of our model and shouldn't be coupled to ORM
{
public function save(BadEntry $be)
{
// some model events, model actions
$this->doSave($be); // here we should hide our storage manipulation
}
protected function doSave($be) // it can be abstract, but may contain some basic storage actions
{
}
// similar code for delete/remove and other model code
}
class ORMBadOrderEntryManager extends BadOrderEntryManager
// IT'S NOT the part of your model. There is no business logic. There is only persistent logic and transaction manipulation
{
protected $entityManager;
// some constructor to inject doctrine entitymanager
protected doSave($be)
{
$em = $this->entityManager;
$em->getConnection()->beginTransaction(); // suspend auto-commit
try {
$em->persist($be);
$em->flush();
$em->getConnection()->commit();
} catch (Exception $e) {
$em->getConnection()->rollback();
throw $e;
}
}
}
// You can also implement ODMBadOrderEntryManager, MemcacheBadOrderEntryManager etc.
因此,如果我们谈论目录结构,您的所有模型都可以从 bundle 中移出并在任何地方使用。您的 Bundle 结构将如下所示:
BadEntryBundle
|
+ Entity
| |
| --- BadOrderEntryEntity.php
|
+ ORM
| |
| --- ORMBadOrderEntryManager.php
然后您只需将 ORMBadOrderEntryManager 注入 BadOrderEntryList
我使用 symfony 2.3 和 php 学说 2。
程序有以下型号:
- 实体订单 - 典型的客户订单
- entity BadOrderEntry(fields: id, order - 与 Order, createdAt 的单向一对一关系)
- 创建实体 BadOrderEntry 的工厂 BadOrderEntryFactory
- 存储库 BadOrderEntryRepository 用于实体 BadOrderEntry 的搜索方法
- 实体 BadOrderEntrysave/edit/delete 方法的管理器 BadOrderEntryManager
AND MAIN CLASS BadOrderList - 错误订单列表,此代码 class:
private $factory; private $repository; private $manager; public function __construct( BadOrderEntryFactory $f, BadOrderEntryRepository $r, BadOrderEntryManager $m ) { $this->factory = $f; $this->repository = $r; $this->manager = $m; } public function has(Order $order) { return $this->repository->existsByOrder($order); } public function add(Order $order) { if (! $this->has($order)) { $entry = $this->factory->create($order); $this->manager->save($entry); } } public function remove(Order $order) { $entry = $this->repository->findOneByOrder($order); if ($entry !== null) { $this->manager->delete($entry); } }
我非常喜欢这个class的设计。我想了很多。 一切都很棒。但!存在一个问题:添加和删除方法中的操作必须在事务中执行。
PHP 原则 2 中的交易代码如下所示:
<?php
$em->getConnection()->beginTransaction();
try {
//... do some work
$em->getConnection()->commit();
} catch (Exception $e) {
$em->getConnection()->rollback();
throw $e;
}
但是我如何在 BadOrderList 中调用这段代码?
我花了很多时间去掉依赖数据库(和相应的PHPDoctrine 2),然后重新创建呢? 现在依赖隐藏在 classes BadOrderEntryRepository 和 BadOrderEntryManager 中。
如何在classBadOrderList中隐藏对事务机制的依赖?
您可以将 class 转换为服务,并在将服务容器注入 class 后随心所欲地调用它。 您可以在此处找到有关 dependency injection 的更多信息:
$injectedContainerOfService->get("id_of_your_service")
经过我们的讨论,我对你的问题有了答案。 问题实际上不是 "How to hide the dependence on the transaction mechanism in class BadOrderList?",而是 如何将模型与持久层分离?(在该特定情况下为 Doctrine2)。
我试着用一些代码来说明我的建议
class BadOrderEntry
// Bad - is too bad word to describe an order here. Why is it bad? Is it Declined? Cancelled?
{
private $order;
// some code
}
class BadOrderEntryFactory
{
// If there is not to much processing to build BadOrderEntry better use factory method like BadOrderEntry::fromOrder($order);
}
class BadOrderEntryRepository
{
// here is some read model
}
class BadOrderEntryManager
// ITS a part of our model and shouldn't be coupled to ORM
{
public function save(BadEntry $be)
{
// some model events, model actions
$this->doSave($be); // here we should hide our storage manipulation
}
protected function doSave($be) // it can be abstract, but may contain some basic storage actions
{
}
// similar code for delete/remove and other model code
}
class ORMBadOrderEntryManager extends BadOrderEntryManager
// IT'S NOT the part of your model. There is no business logic. There is only persistent logic and transaction manipulation
{
protected $entityManager;
// some constructor to inject doctrine entitymanager
protected doSave($be)
{
$em = $this->entityManager;
$em->getConnection()->beginTransaction(); // suspend auto-commit
try {
$em->persist($be);
$em->flush();
$em->getConnection()->commit();
} catch (Exception $e) {
$em->getConnection()->rollback();
throw $e;
}
}
}
// You can also implement ODMBadOrderEntryManager, MemcacheBadOrderEntryManager etc.
因此,如果我们谈论目录结构,您的所有模型都可以从 bundle 中移出并在任何地方使用。您的 Bundle 结构将如下所示:
BadEntryBundle
|
+ Entity
| |
| --- BadOrderEntryEntity.php
|
+ ORM
| |
| --- ORMBadOrderEntryManager.php
然后您只需将 ORMBadOrderEntryManager 注入 BadOrderEntryList