More than 1 year has passed since last update.

※前提として、yield を使うので PHP5.5 以上であることが必要です

Phalcon の Resultset (Model::findの返却値) は多少の機能はありますが、ほぼORM機能を持ったクエリ結果カーソルの域を出ないので Ginq を使っています。

Resultset → Ginq

変換するには Ginq::fromLazy と yield を使います。

$rs = BlogEntries::find();
$entries = Ginq::fromLazy(function() use (&$rs) {
    foreach ($rs as $item) {
        yield $item;
    }
});

// 一日の中で PV 数が最上位のブログ記事を取得
$entries = $entries
    ->groupBy(['e'=>'e.getDate()'])
    ->select(function(GroupingGinq $g) {
        return $g->max(['e'=>'e.getPV()']);
    });

// 出力(これを View でやる)
foreach ($entries as $date => $entry) {
    echo $date . ":" . $entry->getTitle();
}

本来 Resultset はイテレータなので、そのまま Ginq::from(BlogEntries::find()) と書いても動くはずなのですが、なぜか要素がところどころ抜け落ちたりしました。
原因は不明ですが yield を使うことで極限まで抽象化できるので Ginq::fromLazy で解決できます。

find の返却値自体を Ginq にしちゃう

継承する中間クラスとして ModelBase クラスを定義し、find メソッドをオーバーライドします。

use Ginq\Ginq;
use Phalcon\Mvc\Model;

class ModelBase extends Model {

    /**
     * @param array $parameters
     * @return static[]|Ginq
     */
    public static function find($parameters = null) {
        $rs = parent::find($parameters);
        return Ginq::fromLazy(function() use (&$rs) {
            foreach ($rs as $item) {
                yield $item;
            }
        });
    }

} 

すべての Model で ModelBase を継承するだけで、find の結果が Ginq に統一されます。
思い切ったやりかたではありますが、中途半端に Ginq を使い分けるよりもコーディングポリシーを統一できるので、私は実際のプロダクトを一気にリファクタリングしました。

注意が必要なところ

いまのところ、この方法を使う上で以下の点に気を付ける必要があります。

count($entries) ではなく $entries->count()

count($entries) では正しく数量が計算できませんでした。
Ginq の count メソッドを使って $entries->count() と記述する必要があります。

Volt テンプレートエンジンの for 文の特殊変数が機能しない

Volt のループ構文ではループコンテキストという特殊変数が使えますが、このうち

  • loop.first
  • loop.last
  • loop.length

などは使用できませんでした。もちろん $entries->toList() でプリミティブの配列にすれば使えます。

{% for entry in entries.toList() %}
    {{ loop.last }}
{% endfor %}

このへんは責任が持てませんので、各自で検証してください。


暇があったらページネータの GinqAdapter を書こうと思ってます。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.