Zend Framework 2 - 在模型中调用映射器函数的最佳方式


Zend Framework 2 - Best way to call mapper functions in Models

在我的 zend Framework 2 项目中,我更喜欢双层模型(映射器和模型)而不是教义,并试图使它们像教义一样工作,这样我就可以从模型(实体)访问关系数据。以下示例演示了我想要实现的目标。

class User
{
    protected $userTable;
    public $id;
    public $name;
    public function __construct($userTable)
    {
        $this->userTable = $userTable
    }
    public function getUserArticles()
    {
        return $this->userTable->getUserArticles($this->id);
    }
}

问题是我无法在我的用户模型中注入我的用户表,因为表网关使用模型类作为数组对象原型,稍后注入该原型以创建用户表网关(映射器)。

我不想在我的模型中注入服务管理器,因为这被认为是一种不好的做法。如何在用户模型中注入用户表?可能吗?实现我想要做的事情的最佳方式是什么

您要做的是混合两种设计模式:Active Record 和 Data Mapper。

如果您看一下数据映射器模式,您将拥有同时访问模型和数据库的映射器。该模型是被动的 - 通常不调用外部资源(它是一个POPO - 普通的旧PHP对象)。

您的问题的解决方案是将相关信息注入模型,从而仅将模型保留为数据结构。

下面是 MVC 应用程序的工作方案:

控制器 - 用于输入验证和从服务检索数据

<?php
...
public function viewAction()
{
    $id = (int) $this->params()->fromQuery('id');
    $service = $this->getServiceLocator()->get('your-user-service-name');
    $user = $service->getUser($id);
    ...
}

服务 - 用于执行业务逻辑;调用多个数据映射器

<?php
...
public function getUser($id)
{
    // get user
    $mapper = $this->getServiceLocator()->get('your-user-mapper');
    $user = $mapper->getUserById($id);
    // get articles
    $article_mapper = $this->getServiceLocator()->get('your-article-mapper');
    $user->articles = $article_mapper->getArticlesByUser($id);
    return $user;
}

数据映射器 - 用于操作一种类型的域实体 - 如果您正在访问数据库,它应该与 tableGateway 组成

<?php
...
public function getUserById($id)
{
    $select = $this->tableGateway->getSql()->select();
    $select = $select->where(array('id' => $value));
    $row = $this->tableGateway->selectWith($select)->current();
    return $row;
}

域模型 - 用于数据表示

<?php
...
class User 
{
    public $name; // user name
    ...
    public $articles; // holds the user articles
}

优势

  1. 被动模型易于阅读 - 了解数据结构及其关系。
  2. 被动模型易于测试 - 您不需要外部依赖项。
  3. 将持久性层与域层分开。

希望这有帮助!

您不应该将映射器注入到模型中,这正是相反的方式。对于您来说,重要的是要了解关系的工作方式,并且模型不应知道其数据如何映射到持久性框架。

你提到教义

,所以我建议你也看看教义是如何解决这个问题的。他们这样做的方式是通过代理。代理是一个生成的类(你需要编写自己的生成器或自己编写所有代理),它扩展了模型并注入了映射器:

class Foo
{
    protected $id;
    protected $name;
    public function getId()
    {
        return $this->id;
    }
    public function getName()
    {
        return $this->name;
    }
    public function setName($name)
    {
        $this->name = $name;
    }
}
class ProxyFoo extends Foo
{
    protected $mapper;
    public function __construct(FooMapper $mapper)
    {
        $this->mapper = $mapper;
    }
    public function getName()
    {
        if (null === $this->name) {
            $this->load();
        }
        return parent::getName();
    }
    protected function load()
    {
        $data = $this->mapper->findById($this->id);
        // Populate this model with $data
    }
}

我的建议:要么查看Zend Framework 2应用的默认映射器模式,忘记延迟加载,要么只使用Doctrine。这是太多的工作,无法正确完成这项工作。