反馈我的模型层方法Symfony 2模型层+学说

时间:2013-11-07 21:34:42

标签: php oop zend-framework symfony doctrine-orm

请提供以下创建模型层的方法的反馈,该模型层由业务规则组成,这些业务规则使Doctrine用于数据访问。

我目前的方法是基于这样一种观念,即Model是一个ContainerAware类/对象,其中包含所有非库,业务特定的域逻辑。

我发现我必须锤击框架以这种方式做事,这就是为什么我的大脑部分质疑我的方法。

我目前正在使用Symfony 2,它与所有现代PHP MVC框架一样,使用像Doctrine 2这样的ORM层,并且不可避免地将其视为模型层。我猜测情况与ZF2类似,所以尽管我的例子是用SF2编写的,但我认为这是一个与框架无关的问题。

具体示例

作为一个具体示例,请考虑以下情形:

消息要求

  • 作为用户,我可以创建属于我的消息。
  • 作为用户,我可以更新属于我的消息。
  • 作为用户,我可以归档属于我的消息。

控制器

在Symfony2中,这些要求在控制器层中编码为Actions。 我将跳过检查消息是否实际属于用户的无关代码,但显然,这也应该是域逻辑的一部分。在方法“belongsToUser”或类似方法。

 // Vendor\MessageBundle\DefaultController 
 public function archiveAction(Request $request) {
    // ... 
    $em = $this->getDoctrine()
               ->getManager();
    $message = $em->getRepository('MessageBundle:Message');
                    ->getManager()
                    ->getRepository('MessageBundle:Message')
                    ->find($request->get('id'));
    $message->setIsArchived(true);
    $em->persist($entity);
    $em->flush();
    $this->flashMessage('Message has been archived.');
    // ...
}

模型

如果我将它放入模型中,它将如下所示:

class MessageModel 
{
     public function archive($messageId) {
     // ... 
        $em = $this->getDoctrine()
                   ->getManager();
        $message = $em->getRepository('MessageBundle:Message')
                    ->find($messageId);
        $message->setIsArchived(true);
        $em->persist($entity);
        $em->flush();
     // ... return true on success, false on fail.
     }
}

修订控制器

我的修订控制器现在看起来像这样:

 // Vendor\MessageBundle\DefaultController 
 public function archiveAction(Request $request) {
    // ... 
    $model = new MessageModel(); // or a factory.
    $result = $model->archive($request->get('id'));
    if($result) {
        $this->flashMessage('Message has been archived.');
    } else { 
        $this->flashMessage('Message could not be archived due to a system error.');
    }
    return array('result'=>$result);
    // ...
}

另外两个要求也将在模型上实施。

我的方法简而言之

简而言之,这是我目前的做法:

  • 控制器 - 少逻辑
  • 查看 - 保持不变
  • 模型 - 容器识别并容纳所有业务逻辑,访问Doctrine作为数据访问。
  • ORM - 被视为模型层的一部分,但不被视为模型层。
  • 服务层 - 如果需要,我可以使用服务层处理多个图层,但我发现由于简单,我只需要在几个场合使用它我必须建立的应用程序的性质。

我的问题

  • 我的方法是否与其他人的做法一致?
  • 我错过了一些明显的东西吗?
  • 你有没有尝试过类似的东西,发现它好/坏?

提前谢谢。

1 个答案:

答案 0 :(得分:3)

首先,您可以使用ParamConverter来简化控制器。如果找不到实体,则会自动抛出异常。

我会调用消息方法archiverestore,但这是一个偏好问题。

JMSSecurityExtraBundle提供了一种集成安全检查的好方法。使用ACLs检查当前用户是否可以存档邮件。

您的MessageModel类似于您在FOSUserBundle中可以找到的Managerinterface/abstract和教义ODM / ORM implementation)模式。

这些经理正在构建存储层和控制器之间的桥梁,并且所有管理器共享相同的接口(即UserManagerInterface)。通过这种方式,您可以轻松地与推动交换,即学说。

通过将您的控制器变为服务并注入Manager服务而不是注入整个容器(即通过扩展Symfony\Bundle\FrameworkBundle\Controller\Controller)并从那里获取来改进。

您应该只将所需的依赖项注入服务以简化测试。 在doctrine orm / odm的示例中,管理器服务将检索classname参数,entity- / documentmanager服务和存储库服务。 (service definition

您可以在Benjamin Eberlei的博客文章“Extending Symfony2: Controller Utilities”中找到创建控制器实用程序服务的其他灵感。

另一种常用的技术是为最常用的控制器依赖项创建一个抽象parent service。 (example

我的最后一个快速提示是将flashmessages的创建移至event listeners/subscribers。只需检查该方法是否返回Message或更好MessageInterface类型的对象,并添加success-flash消息。如果找不到实体,则可以捕获异常并添加flashmessage并显示错误消息。

当使用像FOSRestBundle's这样的视图响应侦听器时,你甚至可以在方法结束时省略return,如果方法没有返回任何内容,它会自动假设你返回原始参数 - 阅读它here

最后,您可以在一个可测试的控制器服务中找到一个方法,如下所示:

/** 
 * @PreAuthorize("hasPermission(#message, 'ARCHIVE')")
 */
public function archiveAction(Message $message) 
{
    $message->archive();
    $this->messageManager->update($message, true);
}

manager->update()方法的行为类似于我的示例中FOS\UserBundle\Doctrine\UserManager中的方法。