在DDD中使用ZF2控制器插件进行应用程序服务?

时间:2015-03-02 05:32:37

标签: zend-framework2 domain-driven-design zend-controller-plugin

我目前正在使用DDD(域驱动设计)来实现新的Zend Framework 2项目。一切正常,但我对应用程序服务有疑问。

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

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

我对此完全错了吗?或者您是否愿意保持逻辑如何对域服务或控制器中的存储库的结果做出反应?

最诚挚的问候,

拉​​尔夫

2 个答案:

答案 0 :(得分:2)

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

  1. 控制器插件包含任何MVC / REST通用的代码 行动和业务逻辑并不普遍。插件应该是方便的 "控制"请求/响应,而不是业务逻辑 在模型水平上。将它链接在一起会减少它 可重复使用,例如用于控制台操作。它也使它不太可能 将业务逻辑与其他框架结合使用。
  2. 测试很尴尬。将控制器插件注入控制器 类构造函数参数有点多余,因为它们已经存在 可从插件管理器中注入AbstractActionControllerAbstractRestfulController。没有以一种明显/可见的方式注入依赖项(如trough contructor方法),因此很难弄清楚控制器类实际上取决于什么 上。此外,因为所有插件(AbstractPlugin相关)都依赖于控制器实例,从而切换上下文 http到控制台(如用于phpunit测试)可能会出现问题。还测试逻辑 写作/作为控制器插件提供迟早会 升级到包括测试和中的请求/响应对象 这是不必要的复杂性。
  3. 这不直观。当我听到插件时,我会想到一些小事。 在这种不起眼的情况下,不是一个完整的业务逻辑代码 名称。因此,当我没有时间调试某些代码时,最后一个 我需要它的东西就像那样不合适。
  4. 我再次重申,这只是我的意见。我已经了解到很多模式可能会在一个奇怪的用例下崩溃,但到目前为止,上述几点对我和我的团队都有意义。

答案 1 :(得分: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;
    }
}




也许这有助于将来的某个人。