【问题标题】:Separating business logic from PHP Doctrine 2从 PHP Doctrine 2 中分离业务逻辑
【发布时间】:2015-01-04 14:25:10
【问题描述】:

我使用 symfony 2.3 和 php 学说 2。

该方案有以下型号:

  • 实体订单 - 典型的客户订单
  • entity BadOrderEntry(fields: id, order - 与 Order, createdAt 的单向一对一关系)
  • 用于创建实体 BadOrderEntry 的工厂 BadOrderEntryFactory
  • 存储库 BadOrderEntryRepository 用于实体 BadOrderEntry 的搜索方法
  • 管理器 BadOrderEntryManager 用于实体 BadOrderEntry 的保存/编辑/删除方法
  • AND MAIN CLASS BadOrderList - 坏订单列表,该类的代码:

    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);
        }
    }
    

我真的很喜欢这门课的设计。我想了很多。 一切都很棒。但!有一个问题:方法add和remove的操作必须在事务中进行。

PHP Docrine 2 中的事务代码如下所示:

<?php
$em->getConnection()->beginTransaction();
try {
    //... do some work
    $em->getConnection()->commit();
} catch (Exception $e) {
    $em->getConnection()->rollback();
    throw $e;
}

但是如何在 BadOrderList 中调用这段代码呢?

我花了很多时间删除了依赖数据库(以及相应的PHP Doctrine 2),然后重新创建呢? 现在依赖隐藏在 BadOrderEntryRepository 和 BadOrderEntryManager 类中。

BadOrderList类中如何隐藏对事务机制的依赖?

【问题讨论】:

  • 将事务管理添加到您的Manager::adddelete我还建议您重新考虑您的设计。这不是很好。让您的模型持久独立。
  • @Ziumin 如何将事务管理添加到 Manager::add(或删除)?有哪些设计问题? Manager 只是在学说对象管理器之上的额外抽象层。这不是坏事,也不是好事。但提供更多控制权。
  • 您可以按照您在示例中提到的方式进行操作。 doctrine-orm.readthedocs.org/en/latest/reference/… 。至于设计问题 - 为什么你认为你的列表是主要对象。主要用于您架构的哪一部分?您是否考虑过方法名和类名?你能在没有教义的情况下测试整个模型吗?
  • 1) 你是否提供连接注入(doctrine.dbal.default_connection)?这个动作创建了对类\Doctrine\DBAL\Connection 的依赖。我的问题是,如何避免它。 2)主要只在这个问题的背景下。我只针对一个问题创建了一个主题,并且只显示了与之相关的代码。
  • 1) 您可以制作 ORMManager,扩展您的 Manager,您可以使用一些抽象的 UnitOfWork/Persister/Storage/etc 或其与最终 ORM 类的接口。无论如何,您需要一个适配器来连接模型之外的某个地方的 ORM。您的问题是如何隐藏对BadOrderList 类中事务机制的依赖? 2)为什么? :)

标签: php symfony orm doctrine-orm datamapper


【解决方案1】:

经过我们的讨论,我对你的问题有了答案。 问题真的不是“如何隐藏对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 结构将如下所示:

BadEntryBundle
|
+ Entity
| |
| --- BadOrderEntryEntity.php
|
+ ORM
| |
| --- ORMBadOrderEntryManager.php 

然后您只需将 ORMBadOrderEntryManager 注入您的 BadOrderEntryList

【讨论】:

  • 这是一个非常酷的解决方案!我在 JMSPaymentCoreBundle 中看到了类似的解决方案。但没想到……你让我开了眼!非常感谢!
【解决方案2】:

您可以将您的类转换为服务,并在将您的服务容器注入到您的类中后,随意调用它。 你可以在这里找到更多关于dependency injection的信息:

$injectedContainerOfService->get("id_of_your_service")

【讨论】:

  • 谢谢。这是非常简单和明显的解决方案。但不是实用/可测试/可维护的。
  • 它的实用性和可测试性,但如果你想测试它,你应该解耦你的控制器并将其转换为服务
  • 你在哪里看到控制器?
  • 为什么它不可测试?我想说如果您的类是这样的控制器或者不可测试,也许它是一个设计问题
猜你喜欢
  • 2011-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-15
  • 2014-09-04
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
相关资源
最近更新 更多