在阅读了 Matthew Weier O'Phinney 的许多关于在模型中实施 ACL 的文章后,我一直专注于实现这一目标的最佳方法。然而,在进一步研究领域对象的最佳实践后,我了解到这些模型不应包含对数据映射器或任何 CRUD 操作的任何引用。
以 ERM 软件为例,它根据销售和采购订单维护库存并处理进出公司的货物。我想象有几个域......
- 公司
- 运输
- 命令
- 产品
- 集会
- 还有其他几个
由于公司可以有不同的类型(例如制造商、供应商、零售商),因此此信息存储在我的数据库中的许多表中(例如公司、类型、公司类型)。因此,我的公司域有一个数据映射器,它使用每个数据库表的 Zend_Db_Table 实例的对象。
在我的控制器操作中,我知道应该很少有逻辑。例如,创建一个新公司可能会像这样......
public function createAction()
{
  // Receive JSON request from front end
  $data = Zend_Json::decode($request);
  $companyObj = new App_Model_Company();
  $companyObj->populate($data);
  $companyMapper = new App_Model_DataMapper_Company();
  $companyMapper->save($companyObj);
}
考虑到这一点,我觉得最好将我的 ACL 检查合并到 DataMapper 中,并将验证合并到域对象中。My Domain 对象都扩展了一个基础抽象类,它重载了 PHP 的魔力__set和__get方法。在每个域对象的构造函数中,我通过$_properties使用键填充数组来定义对象的属性。这样,我的__set方法看起来像......
public function __set($property, $value)
{
    $className = __CLASS__;
    if(!array_key_exists($property, $this->_properties))
    {
        throw new Zend_Exception("Class [ $className ] has no property [ $property ]");
    }
    // @return Zend_Form
    $validator = $this->getValidator();
    /*
     * Validate provided $value against Zend_Form element $property
     */
    $this->properties[$property] = $value;
    }
}
我所有的数据映射器的save()方法 typehint App_Model_DomainObjectAbstract $obj。
问题 #1 - 由于我的数据映射器将处理所有 CRUD 操作,并且域对象实际上应该只包含特定于该域的属性,我觉得 ACL 检查属于数据映射器 - 这可以接受吗?
我试图避免在我的控制器中实例化数据映射器,但这似乎不合理,因为我认为我对这种设计模式有了更好的理解。
问题 #2 - 我是否过于复杂了这个过程,我是否应该编写一个 ACL 插件来Zend_Controller_Plugin_Abstract根据方法中的传入请求扩展和处理 ACL preDispatch()?
非常感谢您的宝贵时间!