0

通过“入门”教程开始 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;
    }

}
4

1 回答 1

1

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

“映射器”将是 TableGateway 对象,例如 AlbumTable、SongTable 等。您将调用模型或域对象的专辑和歌曲类,这些代表了应用程序中的实际实体。映射器只是负责将它们持久保存在您的数据库等中。

当使用 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;
}
于 2013-06-29T00:56:41.720 回答