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

时间:2013-09-09 18:52:16

标签: php zend-framework2

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

class User
{

    protected $userTable;
    public $id;
    public $name;

    public function __construct($userTable)
    {
        $this->userTable = $userTable
    }

    public function getUserArticles()
    {
        return $this->userTable->getUserArticles($this->id);
    }
}

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

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

2 个答案:

答案 0 :(得分:6)

您要做的是混合两种设计模式:Active RecordData Mapper

如果您查看Data Mapper模式,您可以使用Mapper访问Model和数据库。模型是被动的 - 通常不调用外部资源(它是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. 您将持久层与域层分开。
  4. 希望这有帮助!

答案 1 :(得分:2)

你不应该将你的映射器注入你的模型,这恰恰相反。对于您来说,重要的是关系的工作方式和模型不应该知道他们的数据如何映射到持久性框架。

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

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。要做到这一点,这太过分了。