简体   繁体   English

如何在Zend Framework 2的嵌套映射器模型类中使用InputFilter?

[英]How to use the InputFilter in a nested mapper model class in Zend Framework 2?

Everyone, who started ZF2 learning with the "Get started" tutorial, will know the model class Album (s. below). 通过“入门”教程开始ZF2学习的每个人都将知道模型类Album (下)。

Now I want to extend my model with songs. 现在,我想用歌曲扩展我的模型。 One album can have 0 or more songs. 一张专辑可以包含0首或更多歌曲。 The songs will get a new talbe songs ( id , title , album_id ) and the mapper Album\\Model\\Song . 这些歌曲将获得新的talbe songsidtitlealbum_id )和映射器Album\\Model\\Song The mapper Album\\Model\\Song will be built similar to Album\\Model\\Album . 映射器Album\\Model\\Song构建类似于Album\\Model\\Album The mapper Album\\Model\\Album will get a new property songCollection (array of Album\\Model\\Song objects or maybe something like Album\\Model\\SongCollection object). 映射器Album\\Model\\Album将获得一个新的属性songCollectionAlbum\\Model\\Song对象的数组,或者像是Album\\Model\\SongCollection对象的数组)。

  • Does it make sence to use the InputFilter for "nested" (mapper) classes? InputFilter用于“嵌套”(映射器)类是否InputFilter
  • How should the getInputFilter() be modified? 应该如何修改getInputFilter()
  • How should the setInputFilter() be modified? 应该如何修改setInputFilter() OK, now it is not implemented at all. 好的,现在根本没有实现。 But it's approximately clear how to do it for a shallow class structure -- and not clear how to implement it for a mapper, that references another mapper(-s). 但是,对于一个浅层的类结构来说,几乎是很清楚的-并不清楚如何为引用另一个mapper的mapper实现它。

Album\\Model\\Album

<?php
namespace Album\Model;

use Zend\Stdlib\ArraySerializableInterface;

use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;

class Album implements InputFilterAwareInterface, ArraySerializableInterface {

    public $id;
    public $artist;
    public $title;

    protected $inputFilter;

    public function exchangeArray(array $data) {
        $this->id     = (isset($data['id'])) ? $data['id'] : null;
        $this->artist = (isset($data['artist'])) ? $data['artist'] : null;
        $this->title  = (isset($data['title'])) ? $data['title'] : null;
    }

    public function toArray() {
        return $this->getArrayCopy();
    }

    public function getArrayCopy() {
        return get_object_vars($this);
    }

    public function setInputFilter(InputFilterInterface $inputFilter) {
        throw new \Exception('Not used');
    }

    public function getInputFilter() {
        if (!$this->inputFilter) {
            $inputFilter = new InputFilter();
            $factory = new InputFactory();

            $inputFilter->add($factory->createInput(array(
                'name' => 'id',
                'required' => true,
                'filters' => array(
                    array('name' => 'Int')
                )
            )));

            $inputFilter->add($factory->createInput(array(
                'name' => 'artist',
                'required' => true,
                'filters' => array(
                    array('name' => 'StripTags'),
                    array('name' => 'StringTrim')
                ),
                'validarots' => array(
                    array(
                        'name' => 'StringLength',
                        'options' => array(
                            'encoding' => 'UTF-8',
                            'min' => 1,
                            'max' => 100
                        )
                    )
                )
            )));

            $inputFilter->add($factory->createInput(array(
                'name' => 'title',
                'required' => true,
                'filters' => array(
                    array('name' => 'StripTags'),
                    array('name' => 'StringTrim')
                ),
                'validarots' => array(
                    array(
                        'name' => 'StringLength',
                        'options' => array(
                            'encoding' => 'UTF-8',
                            'min' => 1,
                            'max' => 100
                        )
                    )
                )
            )));

            $this->inputFilter = $inputFilter;
        }
        return $this->inputFilter;
    }

}

I think you are a little confused with the relationship with the models and mappers set out in this example. 我认为您对该示例中列出的模型和映射器的关系有些困惑。

The 'mappers' would be the TableGateway objects, such as AlbumTable, SongTable etc. The Album and Song classes yo would call models, or Domain Objects, these are what represent the actual entities in your application. “映射器”将是TableGateway对象,例如AlbumTable,SongTable等。专辑和Song类将称为模型或域对象,它们代表应用程序中的实际实体。 The Mappers just take care of persisting them in your database etc. 映射器只需要将它们持久保存在数据库中等等。

When using the TableGateway implementation, I would let each Domain Object (such as Ablum) handle the InputFilter for the attributes it's TableGateway is going to persist (such as AlbumTable). 使用TableGateway实现时,我将让每个域对象(例如Ablum)处理其TableGateway将要保留的属性(例如AlbumTable)的InputFilter。

For the example you stated, I would not change the Album Models InputFilter at all. 对于您所说的示例,我根本不会更改专辑模型的InputFilter。 The reason is the relationship with Songs is this: 原因是与歌曲的关系是这样的:

Album HAS many songs, Song Belongs to Album (the Song would have the link back to the Album)

Add a new Song Object and Gateway: 添加一个新的歌曲对象和网关:

<?php
namespace Album\Model;

use Zend\Stdlib\ArraySerializableInterface;

use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;

class Song implements InputFilterAwareInterface, ArraySerializableInterface {

    protected $id;
    protected $album;
    protected $title;

    protected $inputFilter;

    // Added Getters / Setters for the attributes rather than
    // having public scope ...

    public function setAlbum(Album $album)
    {
         $this->album = $album;
    }

    public function getAlbum()
    {
        return $this->album;
    }

    public function exchangeArray(array $data) {
        $this->id     = (isset($data['id'])) ? $data['id'] : null;
        $this->title  = (isset($data['title'])) ? $data['title'] : null;

        if(isset($data['album_id'])) {
             $album = new Album();
             $album->exchangeArray($data['album_id']);
             $this->setAlbum($album);
        }
    }

    public function toArray() {
        return $this->getArrayCopy();
    }

    public function getArrayCopy() {
        return array(
             'id'       => $this->id,
             'album_id' => $this->getAlbum()->id,
             'title'    => $this->title,
        );
    }

    public function setInputFilter(InputFilterInterface $inputFilter) {
        throw new \Exception('Not used');
    }

    public function getInputFilter() {
        if (!$this->inputFilter) {
            $inputFilter = new InputFilter();
            $factory = new InputFactory();

            $inputFilter->add($factory->createInput(array(
                'name' => 'id',
                'required' => true,
                'filters' => array(
                    array('name' => 'Int')
                )
            )));

            $inputFilter->add($factory->createInput(array(
                'name' => 'album_id',
                'required' => true,
                'filters' => array(
                    array('name' => 'Int')
                )
            )));

            $inputFilter->add($factory->createInput(array(
                'name' => 'title',
                'required' => true,
                'filters' => array(
                    array('name' => 'StripTags'),
                    array('name' => 'StringTrim')
                ),
                'validarots' => array(
                    array(
                        'name' => 'StringLength',
                        'options' => array(
                            'encoding' => 'UTF-8',
                            'min' => 1,
                            'max' => 100
                        )
                    )
                )
            )));

            $this->inputFilter = $inputFilter;
        }
        return $this->inputFilter;
    }
}

Notice no need to change the Album Model as the relationship is 'Song Belongs to Album'. 请注意,由于关系为“歌曲属于专辑”,因此无需更改专辑模型。

When you object relationships get more complex you will want to look at using Hydrators to build the objects for you ( http://framework.zend.com/manual/2.0/en/modules/zend.stdlib.hydrator.html ) 当对象关系变得更加复杂时,您将需要考虑使用Hydrators为您构建对象( http://framework.zend.com/manual/2.0/en/modules/zend.stdlib.hydrator.html

Now you would create a SongTable to persist this new Object for you: 现在,您将创建一个SongTable来为您持久存储此新对象:

<?php
namespace Album\Model;

use Zend\Db\TableGateway\TableGateway;

class SongTable
{
    protected $tableGateway;

    public function __construct(TableGateway $tableGateway)
    {
        $this->tableGateway = $tableGateway;
    }

    public function fetchAll()
    {
        $resultSet = $this->tableGateway->select();
        return $resultSet;
    }

    public function getSong($id)
    {
        $id  = (int) $id;
        $rowset = $this->tableGateway->select(array('id' => $id));
        $row = $rowset->current();
        if (!$row) {
            throw new \Exception("Could not find row $id");
        }
        return $row;
    }

    public function saveSong(Song $song)
    {
        $data = array(
            'album_id' => $song->getAlbum()->id,
            'title'    => $song->title,
        );

        $id = (int)$song->id;
        if ($id == 0) {
            $this->tableGateway->insert($data);
        } else {
            if ($this->getSong($id)) {
                $this->tableGateway->update($data, array('id' => $id));
            } else {
                throw new \Exception('Form id does not exist');
            }
        }
    }

    public function fetchAlbumSongs(Album $album)
    {
        $resultSet = $this->tableGateway->select(array(
            'album_id' => $album->id
        ));

        return $resultSet;
    }

    public function addSongsToAlbum(Album $album)
    {
        foreach($this->fetchAlbumSongs($album) as $song) {
            $album->addSong($song);
        }
    }
}

You Could then Modify you Album model to allow Songs to be added: 然后,您可以修改专辑模型以允许添加歌曲:

class Album implements InputFilterAwareInterface, ArraySerializableInterface {

    // Other stuff here

    /**
     * @var array
     */
    protected $songs = array();

    public function addSong(Song $song)
    {
        $this->songs[] = $song;
    }

    public function getSongs()
    {
         return $this->songs;
    }
}

You can then build your object graph easily, I would usually make a server to do do this kind of thing: 然后,您可以轻松地构建对象图,通常我会让服务器来做这种事情:

AlbumService.php AlbumService.php

public function getAlumbWithSongs(int $id)
{
    $album = $this->getAlbumTable()->getAlbum($id);

    if($album) {
        $this->getSongTable()->addSongsToAlbum($album);
    }

    return $album;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM