zf2-在没有servicemanager的映射器中创建模型(具有依赖项) [英] zf2 - creating models (with dependencies) in mapper without servicemanager

查看:67
本文介绍了zf2-在没有servicemanager的映射器中创建模型(具有依赖项)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

上一篇关于从zf2应用程序中删除ServiceLocatorAwareInterface的文章之后,我现在在使用数据映射器时遇到一个涉及对象创建的难题。

Following from my previous post about removing ServiceLocatorAwareInterface's from my zf2 app, i am now faced with a puzzle involving object creation when using data mappers.

当前的实现我的数据映射器使用tablegateway查找特定的行,调用服务管理器以获取域对象,然后填充并返回完整的对象。

The current implementation of my data mapper uses a tablegateway to find specific rows, calls the service manager to obtain a domain object, then populates and returns the full object.

public function findById($userId){
        $rowset = $this->gateway->select(array('id' => $userId));
        $row = $rowset->current();
        if (!$row) {
            throw new \DomainException("Could not find user with id of $userId in the database");
        }
        $user = $this->createUser($row);
        return $user;
    }

public function createUser($data){
        $userModel = $this->getServiceManager()->get('Model\User');
        $hydrator = $this->getHydrator();
        if($data instanceof \ArrayObject){
            $hydrator->hydrate($data->getArrayCopy(), $userModel);
        }else{
            $hydrator->hydrate($data, $userModel);
        }
        return $userModel;
    }

该模型需要从服务管理器中调用,因为该模型还有其他依赖性,因此,不能从映射器中调用 $ user = new App\Model\User()

The model needs to be called from the service manager because it has other dependencies, so calling $user = new App\Model\User() from within the mapper is not an option.

但是,现在我要从代码中删除servicemanager的实例,我不确定将模型放入映射器的最佳方法。显而易见的答案是在构造函数中传递它,并将实例另存为映射器的属性:

However, now i am removing instances of the servicemanager from my code, i am unsure of the best way to get the model into the mapper. The obvious answer is to pass it in the constructor and save the instance as a property of the mapper:

 public function __construct(TableGateway $gateway, \App\Model\User $userModel){
        $this->_gateway = $gateway;
        $this->_userModel= $userModel;
    }

    public function createUser($data){
        $userModel = $this->_userModel;
        //....snip....
    }

此在一定程度上可以正常工作,但是随后多次调用 createUser (例如,当找到所有用户时)会用最后一个对象数据(如预期的那样)写入每个实例,但不是我想要的)

This works to a degree, but then multiple calls to createUser (such as when finding all users, for instance) over writes each instance with the last objects data (as to be expected, but not what i want)

因此,每次调用 createUser 时,我都需要返回一个新对象,但是依赖关系传递给构造函数。通过将模型传递到构造函数中,我可以克隆对象。

So i need a "new" object returned each time i call createUser, but the dependency being passed into the constructor. With the model passed into the constructor I can clone the object eg.

    public function createUser($data){
        $userModel = clone $this->_userModel
        //....snip....
    }

...但是关于它似乎不对,代码有气味吗?

...but something about it doesn't seem right, code smell?

推荐答案

是的,它闻起来不好。

设计ORM并不容易。关于ORM的设计方式一直存在讨论,并且可能永远都会进行讨论。现在,当我试图了解您的设计时,我注意到您指出您的模型既包含数据,又具有其他依赖关系。这是错误的,包含数据的模型应该在应用程序中没有任何层。

Designing an ORM isn't easy. There is and probably always will be discussion about the way an ORM should be designed. Now, when I'm trying to understand your design I noticed you are pointing out that your models contain the data but also have "other" dependencies. This is wrong, the models containing your data should work without any layer in your application.

实体应该在没有ORM的情况下工作

我认为您应该将业务逻辑(依赖性)与数据分开。这将具有许多优点:

In my opinion you should separate your business logic (dependencies) from your data. This will have many advantages:


  • 更具表现力的

  • 易于测试

  • 较少耦合

  • 更灵活

  • 易于重构

  • More expressive
  • Easier to test
  • Less coupling
  • More flexible
  • Easier to refactor

有关如何设计ORM层的更多信息,我强烈建议浏览这些幻灯片

For more information about how to design your ORM layer I highly recommend browsing through these slides.

让我们制作 UserMapper 负责从数据库中分离内存中对象(仅包含数据)。

Lets make the UserMapper responsible for separating the in-memory objects (containing only data) from the database.

class UserMapper
{
    protected $gateway;
    protected $hydrator;        

    public function __construct(TableGateway $gateway, HydratorInterface $hydrator)
    {
        $this->gateway = $gateway;
        $this->hydrator = $hydrator;
    }

    public function findOneById($id)
    {
        $rowset = $this->_gateway->select(array('id' => $id));
        $row = $rowset->current();

        if(!$row) {
            throw new \DomainException("Could not find user with id of $id in the database.");
        }
        $user = new User;
        $this->hydrator->hydrate($row, $user);
        return $user;
    }

    public function findManyBy(array $criteria)
    {
       // $criteria would be array('colum_name' => 'value')
    }

    public function save(User $user)
    {
        $data = $this->hydrator->extract($user);
        // ... and save it using the $gateway.
    }
}

有关数据映射器职责的更多信息,请查看马丁·福勒的定义

For more information about the responsibility of data mappers check out Martin Fowler's definition.

建议不要将任何与模型相关的业务逻辑直接放入 Controller 中。因此,我们只需创建一个简单的 UserService 即可处理验证。如果您喜欢表单对象,也可以在此过程中使用 Zend\Form\Form

It's recommended not to place any model related business logic directly into the Controller. Therefor lets just create a simple UserService which will handle validation. If your fond of form objects you could also use Zend\Form\Form in this process.

class UserService
{
    protected $inputFilter;
    protected $hydrator;

    public function __construct(InputFilter $inputFilter, HydratorInterface $hydrator)
    {
        $this->inputFilter = $inputFilter;
        $this->hydrator = $hydrator;
    }

    protected function validate(array $data)
    {
        // Use the input filter to validate the data;
    }

    public function createUser(array $data)
    {
        $validData = $this->validate($data);
        $user = new User;
        $this->hydrator->hydrate($validData, $user);
        return $user;
    }
}



数据对象



现在可以使包含数据的对象成为纯旧PHP对象,不受任何限制。这意味着它们没有任何逻辑,我们可以在任何地方使用它们。例如,如果我们决定用另一个类似Doctrine的ORM来替换我们的ORM。

Data Object

Now lets make the objects containing the data Plain Old PHP Objects, not bound by any restriction. This means they are not coupled with any logic and we could use them anywhere. For instance if we decide to replace our ORM with another like Doctrine.

class User
{
    protected $name;

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }
}

有关Plain Old PHP Objects概念的更多信息可以可以在维基百科对POJO的解释中找到。

More information about the concept of Plain Old PHP Objects can be found on Wikipedia's explanation of POJO.

这篇关于zf2-在没有servicemanager的映射器中创建模型(具有依赖项)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆