0

我目前正在为一个新的Zend Framework 2项目使用DDD(域驱动设计)。一切正常,但我确实有关于应用程序服务的问题。在DDD内使用ZF2控制器插件进行应用程序服务?

我知道应用程序服务位于应用程序层,并且是域逻辑的入口点。例如,他们可以访问域服务或存储库。

现在我想知道是否应该将应用程序服务作为控制器插件来实现。在经典的MVC应用程序中,这个控制器插件可以处理来自被叫域服务或存储库的结果。根据这些结果,他们可以生成重定向响应或将数据/表单传递给ViewModel。如果这个逻辑封装在一个插件中,我的控制器只需调用插件并返回插件的结果。

我完全错了吗?或者你宁愿保留逻辑如何对控制器中的域服务或存储库的结果作出反应?

最好的问候,

拉尔夫

+0

我不确定您在域和应用程序服务之间做出的实际区别。我想你可以为你的服务类制作插件,但目前我看不到优势。我有控制器工厂,并注入控制器所需的服务。有时候我的服务本质上就像存储库一样,但我仍然一直定义一个服务,因为应用程序定义了一个基本服务,它处理所有的域安全。 – dualmon 2015-03-02 15:50:04

+0

那么域服务只处理属于域的东西,而应用服务则是作为应用程序和域之间的网关处理。这些应用程序服务将注入存储库或域服务,并且控制器获取注入的应用程序服务。 – Frille2012 2015-03-04 12:46:26

回答

2

当然它是一种主观的,人们对这样的事情强烈的意见......所以这里是我的:

  1. 控制器插件包含的代码的通用到任何MVC/REST 行为和业务逻辑不是通用的。插件应该促进 “控制”请求/响应,而不是在模型层面上减少 的业务逻辑。将它链接在一起会使它更少可重复使用,例如 。控制台操作。此外,它会使其不太可能 与其他框架一起使用业务逻辑。
  2. 测试很尴尬。将控制器插件作为控制器注入类构造函数参数会有点多余,因为它们已经可以从注入到AbstractActionControllerAbstractRestfulController中的插件管理器中获得 。没有以明显/可见的方式注入依赖关系(如槽构造方法)使得难以弄清楚控制器类实际上取决于 。此外,由于所有插件(相关的AbstractPlugin)都依赖于控制器实例,因此将http上的上下文从 切换到控制台(如用于phpunit测试)可能会出现问题。另外测试逻辑 作为控制器插件被写入/提供将迟早会升级到在测试中包括请求/响应对象,并且这是不必要的复杂性。
  3. 这并不直观。当我听到插件时,我想到了一些小事。 不是一个完整的业务逻辑代码掩埋在这样不起眼的 名称。所以,当我没有时间调试某人编码最后的 的东西时,我需要它的东西是不合适的。

我再次想重申一下,那只是我的看法。我了解到,有很多模式可能会在一个足够奇怪的用例下崩溃,但上述观点对我和我的团队而言至今仍有意义。

+0

经过进一步阅读,我得出了同样的结论。我创建了应用程序服务作为单独的命令对象。这些命令在错误情况下抛出异常,或者在成功时返回一个小的结果对象。控制器操作现在只处理这些异常或结果对象。 感谢您的想法。 – Frille2012 2015-03-04 12:42:58

0

至于这里我的解决方案的例子中,你可以看到一个控制器动作:

public function showAction() 
 
    { 
 
     $service = $this->readProductEntityCommand; 
 
     $service->setId($this->params()->fromRoute('id')); 
 

 
     try { 
 
      $result = $service->execute(); 
 
     } catch (ProductException $e) { 
 
      $this->flashMessenger()->addMessage($e->getMessage()); 
 

 
      return $this->redirect()->toRoute('part3/product'); 
 
     } 
 

 
     return new ViewModel(
 
      array(
 
       'productEntity' => $result->getData(), 
 
      ) 
 
     ); 
 
    }

这里是作为一个命令对象

class ReadProductEntityCommand implements CommandInterface 
 
{ 
 
    protected $productRepository; 
 

 
    protected $id; 
 

 
    public function __construct(ProductRepositoryInterface $productRepository) 
 
    { 
 
     $this->productRepository = $productRepository; 
 
    } 
 

 
    public function setId($id) 
 
    { 
 
     $this->id = $id; 
 
    } 
 

 
    public function execute() 
 
    { 
 
     if (is_null($this->id)) { 
 
      throw new ProductIdInvalidException(
 
       'Produkt ID wurde nicht angegeben.' 
 
      ); 
 
     } 
 

 
     try { 
 
      $product = $this->productRepository->getProduct(
 
       new ProductIdCriterion(
 
        new ProductId($this->id) 
 
       ) 
 
      ); 
 
     } catch (\Exception $e) { 
 
      throw new ProductNotFoundException(
 
       'Es konnten kein Produkt gelesen werden.' 
 
      ); 
 
     } 
 

 
     if ($product === false) { 
 
      throw new ProductNotFoundException('Produkt wurde nicht gefunden.'); 
 
     } 
 

 
     $result = new Result(); 
 
     $result->setValid(true); 
 
     $result->setData($product); 
 
     $result->setMessage('Produkt wurde gelesen.'); 
 

 
     return $result; 
 
    } 
 
}
应用服务构建的一个例子

也许这有助于未来的人。

相关问题