anybody's game

日々感じたこと、艦隊これくしょん、千年戦争アイギス、読書記録

HatenaBlogAPIから取得した自分のブログデータをオブジェクト化する【はてなブログ】PHPStormからはてなブログを使う Part.5

前回まで

 前回、はてなブログからデータを取得するところまで頑張りました。

aods1004.hatenablog.jp

 今回は、取得したデータをオブジェクト化(deserialize)するところまでつくりました。

 はてなブログから取得したデータは、Atom Pubという形式のXML文書なので、それをプログラムで利用しやすい形に変形します。

エンティティの設計

 ドメイン駆動デザインをベースにAtomPubをクラス化しました。

www.slideshare.net

f:id:aods1004:20180518013716p:plain

github.com

エンティティのプログラムはこんな感じ。

<?php
declare(strict_types=1);
namespace App\Entity;
/**
 * Class Feed
 * @package App\Entity
 */
class Feed extends AtomPubEntity
{
    /** @var string */
    protected $subtitle;
    /** @var Entries */
    protected $entries = [];
    /**
     * Feed constructor.
     * @param string $id
     * @param string $title
     * @param string $subtitle
     * @param array|null $author
     * @param Entries|null $entries
     * @param Links|null $links
     * @param \DateTimeInterface|null $updated
     */
    public function __construct(
        string $id,
        string $title,
        string $subtitle,
        array $author,
        ?Entries $entries,
        ?Links $links,
        ?\DateTimeInterface $updated
    )
    {
        $this->subtitle = $subtitle;
        $this->entries = $entries;
        parent::__construct($id, $title, $author, $links, $updated);
    }
    /**
     * @return null
     */
    public function getNextLinkUri()
    {
        foreach ($this->links ?: [] as $link) {
            if ($next = $link->getNextUri()) {
                return $next;
            }
        }
        return null;
    }
}

 データの注入は、コンストラクタインジェクションを選択。ドメイン駆動デザインの方針でセッターインジェクションをやろうとすると、setXXXのような、ドメイン知識と関係ないメソッドをたくさんつくらなくてはいけなくなってしまいますし、すでに設計されているAtomPub形式のようなエンティティをクラス化すると、プロパティの数も減らしたりして整理もできないですからね。プロパティインジェクションは、型チェックの不自由さで選択肢から外しました。プロパティインジェクションでやった場合、PHP7からは、メソッドの引数の型宣言できるのに、文字列をパースする分処理コストの高いAnnotationを使って型のチェックをやることになってしまいますからね。

Serializer

 XML文書と設計したエンティティのつなぎは、Symfonyにそれ用のコンポーネントがあったので、利用させてもらいました。

symfony.com

 serialize と encode、normalizeという3つの概念にわけて設計してあり、説明も十分あったため、使いやすいコンポーネントでした。

Normalizer

 Serializer + XMLEncoderでPHPの配列データにしたものを、Normalizerで、さらにオブジェクト化しました。Symfonyにも標準でいろいろなノーマライザーが組み込まれていますが、配列 からオブジェクトにするというハイコンテクストな処理をする必要があるため、PHPDocsをパースしなくてはいけなくて重かったり、動きがわかりづらかったり、コード量はすくなくなるがエンティティ側の実装が制限されたり、と、なかなかいい具合に処理を組み立てられなかったので、シンプルに独自実装を行いました。

github.com

Command

 最後に、前回まで組み立てていたコマンドとAPIのクライアントに、設計したEntiyを返してくれるように、今回組み立てた、Serializer、Normalizerを組み込んで実行。無事、今後、更新したり投稿したりしやすい感じにオブジェクトを生成することができました。次は、今回作成したこれらの仕組みをRepositoryとして切り出すところをやろうと思います。

f:id:aods1004:20180519014843p:plain

ここまでの成果

github.com