【问题标题】:How to use the InputFilter in a nested mapper model class in Zend Framework 2?如何在 Zend Framework 2 的嵌套映射器模型类中使用 InputFilter?
【发布时间】:2013-06-26 18:19:43
【问题描述】:

每个通过“入门”教程开始 ZF2 学习的人都会知道模型类 Album(如下)。

现在我想用歌曲扩展我的模型。一张专辑可以有 0 首或更多首歌曲。这些歌曲将获得一个新的 talbe songs (id, title, album_id) 和映射器Album\Model\Song。映射器Album\Model\Song 的构建类似于Album\Model\Album。映射器Album\Model\Album 将获得一个新属性songCollectionAlbum\Model\Song 对象的数组,或者可能类似于Album\Model\SongCollection 对象)。

  • InputFilter 用于“嵌套”(映射器)类是否有意义?
  • getInputFilter()应该如何修改?
  • 应该如何修改setInputFilter()?好的,现在它根本没有实现。但是对于浅层类结构,如何实现这一点大致很清楚——并且不清楚如何为引用另一个映射器(-s)的映射器实现它。

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;
    }

}

【问题讨论】:

    标签: orm model zend-framework2 zend-inputfilter


    【解决方案1】:

    我认为您对本示例中列出的模型和映射器的关系有些困惑。

    “映射器”将是 TableGateway 对象,例如 AlbumTable、SongTable 等。您将调用模型或域对象的 Album 和 Song 类,它们代表了应用程序中的实际实体。映射器只是负责将它们持久化到您的数据库等中。

    当使用 TableGateway 实现时,我会让每个域对象(例如 Ablum)处理 InputFilter 以获取 TableGateway 将要保留的属性(例如 AlbumTable)。

    对于您所说的示例,我根本不会更改专辑模型 InputFilter。原因是和Songs的关系是这样的:

    Album HAS many songs, Song Belongs to Album (the Song would have the link back to the 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 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;
        }
    }
    

    注意不需要更改专辑模型,因为关系是“歌曲属于专辑”。

    当您的对象关系变得更加复杂时,您会希望考虑使用 Hydrators 为您构建对象 (http://framework.zend.com/manual/2.0/en/modules/zend.stdlib.hydrator.html)

    现在您将创建一个 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);
            }
        }
    }
    

    然后您可以修改您的专辑模型以允许添加歌曲:

    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;
        }
    }
    

    然后你可以很容易地构建你的对象图,我通常会做一个服务器来做这种事情:

    相册服务.php

    public function getAlumbWithSongs(int $id)
    {
        $album = $this->getAlbumTable()->getAlbum($id);
    
        if($album) {
            $this->getSongTable()->addSongsToAlbum($album);
        }
    
        return $album;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-30
      • 1970-01-01
      • 2013-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多