【问题标题】:zend framework 2 understanding the exchangeArray methodzend framework 2 理解 exchangeArray 方法
【发布时间】:2018-02-22 15:09:43
【问题描述】:

来自documentation

 namespace Album\Model;

 class Album
 {
     public $id;
     public $artist;
     public $title;

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

我们的相册实体对象是一个简单的 PHP 类。为了使用 Zend\Db 的 TableGateway 类,我们需要实现 exchangeArray() 方法。该方法只是将传入数组中的数据复制到我们实体的属性中

好的,我们需要。但是该函数的作用是什么?

我的意思是,我已经理解了什么该函数的作用,但我不明白为什么它会这样做

真的有必要声明所有变量吗?

假设我有一个包含 20 列的表格,我想将它们全部选中。 然后我应该声明 20 个命名变量。

如果我想区分公共(打印)和私有(内部)变量,这是有道理的。

还有其他原因吗?

【问题讨论】:

    标签: zend-framework2 tablegateway


    【解决方案1】:

    这不仅仅是定义类成员。它更多的是关于面向对象的好处,如封装、继承等。 假设您的实体如下所示:

    declare(strict_types=1);
    namespace Application\Entity;
    
    class Album
    {
        protected $id;
    
        protected $artist;
    
        protected $title;
    
        public function getId() : int
        {
            return $this->id;
        }
    
        public function setId(int $id) : Album
        {
             $this->id = $id;
             return $this;
        }
    
        public function getArtist() : string
        {
            return $this->artist;
        }
    
        public function setArtist(string $artist) : Album
        {
            $this->artist = $artist;
            return $this;
        }
    
        public function getTitle() : string
        {
            return $this->title;
        }
    
        public function setTitle(string $title) : Album
        {
            $this->title = $title;
            return $this;
        }
    } 
    

    使用实体的第一个优势:不可能出现拼写错误。 $data['atrist'] = 'Marcel' 在大多数情况下都可以使用。 $album->setAtrist('Marcel') 会抛出错误。

    第二个优势是类型提示。特别是当您使用 PHP7 时,您可以利用类型提示的优势。 $album->setId('1') 将抛出错误,因为此方法需要一个整数值。

    第三个优势是可以为您的实体添加一些额外的代码。如果我们需要发布日期但没有给出发布日期怎么办?您可以在实体中验证事物。

    protected $releaseDate;
    
    public function getReleaseDate() : \DateTime
    {
        if ($this->releaseData == null) {
            throw new \Exception('no release date given. evacuate!');
        }
    
        return $this->releaseDate;
    }
    

    另一个优点是 zend 框架中的水合作用。虽然exchangeArray 方法是一种简单的水合,但zend 框架提供了更复杂的水合方式。如果您在数据库表中的发布日期列是 DATE 类型,并且您希望实体中的 releaseDate 成员是代表此日期的 \DateTime 对象,那该怎么办?

    // data from your database
    $data = [
        'id' => 1,
        'artist' => 'the outside agency',
        'title' => 'scenocide 202',
        'releaseDate' => '2010-06-30',
    ];
    
    // hydration of your entity with zend 's own hydrator classes
    $album = (new ClassMethods())
        ->addStrategy('releaseDate', new DateTimeStrategy('Y-m-d'))
        ->hydrate($data, new Album());
    
    $releaseDate = $album->getReleaseDate()->format('d.m.Y');
    

    如您所见,发布日期是一个简单的字符串。在为您的实体补水时,发布日期将通过补水策略转换为 \DateTime 对象。

    这些好处不仅仅是区分公共变量、受保护变量和私有变量。实体只接受和提供变量,这些变量应该在您的实体中。您可以使用所有 oo 的东西,例如继承(实现 \JsonSerializable 接口有时非常神奇)、类型提示、封装、多态等等......

    最后但同样重要的是:IDE 支持。如果您的实体对象是严格的 php doc 注释,那么您的 IDE 知道您可以对您的实体做什么。为您减少工作量。 ;)

    编辑:表网关实例化与水合结果集

    要在表格网关中使用实体对象的上述优势和水合器,您必须像以下示例一样实例化表格网关。

    class AlbumTableGateway extends TableGateway
    {
        public function __construct(Adapter $adapter)
        {
            $resultset = new HydratingResultset(
                (new ClassMethods())->addStrategy('releaseDate', new DateTimeFormatter()),
                new AlbumEntity()
            );
    
            parent::__construct('album_table', $adapter, null, $resultset);
        }
    
        public function fetchById($id)
        {
            $select = $this->getSql()->select();
            $select->columns([
                'id',
                'artist',
                'title',
                'releaseDate',
            ]);
    
            $select->where->equalTo('id', $id);
    
            $result = $this->selectWith($select);
    
            // get the found resultset with $result->current()->getId();
            return $result;
        }
    }
    

    本示例假设 Table Gateway 是通过相应的工厂创建的。

    【讨论】:

    • 你的回答很好,但我有点困惑:你说的是一般情况吗?我的意思是,据我了解,为了应用您的示例,我需要使用 ClassMethods 水合器来建立 TableGateway,而给出的示例使用默认的 ArraySerializable。我说的对吗?
    • 您在开篇文章中给出的示例是使用 ArraySerializable 接口。你是绝对正确的。您必须使用类方法 hydrator 实例化您的表网关。我将编辑我的答案并举例说明如何实例化表网关。
    猜你喜欢
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    • 2015-09-11
    • 1970-01-01
    • 2018-10-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多