Php 服务层的数据访问和安全性(条令和采埃孚)

Php 服务层的数据访问和安全性(条令和采埃孚),php,model-view-controller,doctrine-orm,zend-framework2,service-layer,Php,Model View Controller,Doctrine Orm,Zend Framework2,Service Layer,我们最近开始使用Doctrine 2.2和Zend Framework 2的部分内容,以改进组织、减少重复等。今天,我开始讨论如何实现一个服务层,作为控制器和条令实体之间的中介 现在,我们的大部分逻辑都驻留在控制器中。此外,我们使用一个动作助手来测试某些权限;然而,在实现Zend\Di之后,我提出了一种新的方法。我开始创建特定于实体的服务模型,使用Zend\Di注入EntityManager实例和当前用户的权限 控制器代码如下所示: 类项目\u DeleteController扩展Webjawn

我们最近开始使用Doctrine 2.2和Zend Framework 2的部分内容,以改进组织、减少重复等。今天,我开始讨论如何实现一个服务层,作为控制器和条令实体之间的中介

现在,我们的大部分逻辑都驻留在控制器中。此外,我们使用一个动作助手来测试某些权限;然而,在实现Zend\Di之后,我提出了一种新的方法。我开始创建特定于实体的服务模型,使用Zend\Di注入EntityManager实例和当前用户的权限

控制器代码如下所示:

类项目\u DeleteController扩展Webjawns\u控制器\u操作
{
公共函数init()
{
$this->_initJsonContext();
}
公共函数索引()
{
$response=$this->_getAjaxResponse();
$auditId=(int)$this->_getParam('audit_id');
如果(!$试听){
抛出新的DomainException(“需要审核ID”);
}
/*@var$auditService服务\Audit*/
$auditService=$this->getDependencyInjector()->get('Service\Audit');
试一试{
$auditService->delete($Audited);
$response->setStatusSuccess();
}catch(Webjawns\Exception\SecurityException$e){
$this->_noAuth();
}捕获(Webjawns\Exception\Exception$e){
$response->setStatusFailure($e->getMessage());
}
$response->sendResponse();
}
}
以及我们的一个服务层的示例。构造函数接受两个参数——一个接受EntityManager,另一个接受Entity\UserAccess对象——由Zend\Di注入

名称空间服务;
使用Webjawns\Service\doctor,
Webjawns\Exception;
类审计扩展了抽象服务
{
公共功能删除($auditd)
{
//只有帐户管理员才能删除审核
如果(\Webjawns\u Acl::ROLE\u ACCT\u ADMIN!=$this->getUserAccess()->getAccessRole()){
抛出新异常\SecurityException(“只有帐户管理员才能删除审核”);
}
$audit=$this->get($auditd);
if($audit->getAuditStatus()!=\Entity\audit::STATUS\u IN\u PROGRESS){
抛出新异常\DomainException(“提交审核后无法删除审核”);
}
$em=$this->getEntityManager();
$em->remove($audit);
$em->flush();
}
/**
*@param integer$auditd
*@return\Entity\Audit
*/
获得公共功能($audit)
{
/*@var$audit\Entity\audit*/
$audit=$this->getEntityManager()->find('Entity\audit',$auditd);
如果(null==$audit){
抛出新异常\DomainException('Audit not found');
}
如果($audit->getAccount()->getAccountId()!=$this->getUserAccess()->getAccount()->getAccountId()){
抛出新异常\SecurityException(“用户和审核帐户不匹配”);
}
返回$audit;
}
}
  • 对于我们正在努力完成的事情,这是一个合适的模式吗
  • 在发布的服务层中进行权限验证是否是一种良好的做法
  • 据我所知,视图逻辑仍然驻留在控制器中,为模型提供了在各种上下文(JSON、XML、HTML等)中使用的灵活性。想法

  • 到目前为止,我对这种方式很满意,但如果有人看到我们这样做的任何缺点,请发表你的想法。

    我喜欢你在这里所做的,我认为你的关注点分离是好的。我们正在尝试使用自定义存储库更进一步。因此,例如,标准模型/服务方法可能如下所示:

    public function findAll($sort = null)
    {
        if (!$sort) $sort = array('name' => 'asc');
        return $this->getEm()->getRepository('Application\Entity\PartType')
                    ->findAll($sort);
    
    }
    
    <?php
    namespace Application\Repository;
    
    use Application\Entity\PartType;
    use Doctrine\ORM\EntityRepository;
    
    class PartTypeRepository extends EntityRepository
    {
    
        public function findAllProducts($order=NULL)
        {
            return $this->_em->createQuery(
                        "SELECT p FROM Application\Entity\PartType p 
                            WHERE p.productGroup IS NOT NULL 
                            ORDER BY p.name"
                   )->getResult();
        }
    
    }
    
    。。。我们正在向存储库中添加需要DQL的内容,以将所有DQL排除在模型之外,例如:

    public function findAllProducts($sort = null)
    {
        if (!$sort) $sort = array('name' => 'asc');
        return $this->getEm()->getRepository('Application\Entity\PartType')
                    ->findAllProducts($sort);
    
    }
    
    对于上述模型,repository类如下所示:

    public function findAll($sort = null)
    {
        if (!$sort) $sort = array('name' => 'asc');
        return $this->getEm()->getRepository('Application\Entity\PartType')
                    ->findAll($sort);
    
    }
    
    <?php
    namespace Application\Repository;
    
    use Application\Entity\PartType;
    use Doctrine\ORM\EntityRepository;
    
    class PartTypeRepository extends EntityRepository
    {
    
        public function findAllProducts($order=NULL)
        {
            return $this->_em->createQuery(
                        "SELECT p FROM Application\Entity\PartType p 
                            WHERE p.productGroup IS NOT NULL 
                            ORDER BY p.name"
                   )->getResult();
        }
    
    }
    

    就我的两便士。我不相信有正确的方法和错误的方法,但是,我开始将身份验证放在服务层,然后将其移动到控制器中。我的理由是服务层是我的内部API,我应该使用我的控制器层向世界公开它,因此它应该决定谁可以访问什么。另外,如果我想构建任何内部工具/脚本等,我不需要在它们中构建身份验证来使用我的服务层。小心不要混淆身份验证和访问控制。身份验证可以(应该?)进入模块,然后再将任何域类引入到图中。仅当您建立了用户标识后。示例:如果(!$authService->hasIdentity())在域服务模型中。@JamieSutherland:我不同意。服务定义了业务逻辑;控制器是请求和适当业务逻辑之间的桥梁。例如,您将只有一个用于订购产品的服务,但您可能有多个用于HTTP请求、API请求等的控制器。如果您担心ACL是特定于请求的(例如,通过HTTP,您可能需要一个用户会话,在该会话中,正如您希望API请求有一个密钥一样),请概括您的ACL实现以实现这一点。我强烈反对将访问控制代码放在存储库中。存储库不应该知道应用程序的任何业务逻辑。它应该只关注检索数据。业务逻辑用于更高级别的服务和类。我认为从条令实现中抽象存储库也是一个好主意。使用组合(默认的条令存储库类)而不是继承。这与接口编码相结合,允许您轻松交换部分或所有存储库中的数据源(我喜欢称之为“映射器”,以避免混淆)