投稿日:

CakePHP 2.x で Entity オブジェクトを使えるプラグイン — FkRecordModel


昨年ぐらいから CakePHP 2 を本格的に触ることになりまして、これまでの Paper ドライバーを卒業と喜んでいたんですが、いきなりつまづいた…というか不満に思ったのが Model の構造でした。CakePHP も 2 となり、もうてっきり Rails の ActiveRecord のようなものになっているかと思いきや、find メソッドが返すものは相変わらず array だったんですね。これはもう思想なのかも?…とはいえ、Paper ドライバーレベルではなかなか思想まで理解できません。同じような不満が出ていないかと検索してみたところ、次の記事が見つかりました。

同じことを思う方はいるもので♪ 早速、上のプラグインを利用させていただいたのですが、どうも CakePHP 2 系では上手く動かないようでしたので、修正を試みたものの、挫折。せっかくだからということで、自分で作ることにしました。これでも自称フレームワークマニアですしねw

その成果物がここで紹介する FkRecordModel です。GitHub に公開中です。

次のような簡単な構成になっています。

  • FkRecord        エンティティオブジェクト。find メソッドなどの戻り値などになります。
  • FkRecordCollection  findAll などの戻り値となります。
  • FkRecordModel  拡張された Model クラスです。FkRecord 生成の為に find などをオーバーライドしています。

次のような機能があります(特に高機能ではありません)。

  • FkRecord::save() で保存
  • FkRecord::validates() でバリデーション
  • FkRecordModel::build() 新しい FkRecord のビルド
  • エンティティフィールドのシンプルなアクセス。Ex. $post->title
  • Validation error は FkRecord が保持し、View で参照可能
  • HTML のラベルの表示などに利用できるフィールド別名のサポート(VerboseName)
  • リレーションを FkRecordCollection で取得。Ex. $post->tags //hasMany のデータの取得

上述の CakeEntity プラグインとの相違点は多々とあると思いますが、とりあえず大きなところで、本プラグインは「CakePHP の通常通り配列を返す」という選択肢を設けていません。find 系メソッドは常に FkRecord または FkRecordCollection を返します。(自分はたぶん使わないからです。ごめんなさい)。また、FkRecordCollection は不要だったり邪魔だと思われる方も我慢してください(イテレータにしておくと色々と便利という信条です)。ちなみに、FkRecordCollection::sort() メソッドには不満があります(削除または改良したいです。どなたか良い案ください)。

以下、簡単な利用例です。

AppModel の定義

まずは以下のように AppModel の super クラスとして本プラグインのクラスを利用します。AppModel の他に、AppRecord も作成してください。FkRecordCollection は全てのモデルで共通に利用されます。

具象モデルクラスの定義

モデルクラスでは、それぞれのモデル毎に、Model と Record を定義します。Model の定義は通常通りですが、verboseName などの指定ができます。Record にはエンティティオブジェクトで提供したい機能を実装してください。自らのフィールドへのアクセスは、$this->fieldName または $this[$alias][$fieldName] です。

Controller での利用例

Controller での利用は次のような雰囲気になります。$post->save() のようにして保存します。FkRecord::save() メソッドは、バリデーションエラーがある時には、false を返します。バリデーションエラーの内容はエンティティオブジェクトが保持し、これは View の中で利用できます。

View での利用例(一覧表示)

FkRecordModel に定義された関連は、$post->tags のようにして FkRecordCollection/FkRecord として取得できます。なお、FkRecordCollection は empty($posts) のように空判定できません。FkRecordCollection::isEmpty() メソッドを利用してください。

View での利用例(編集画面)

フォームを扱うには、FkRecord::bindFormHelper() メソッドで FormHelper をエンティティにバインドし、以後、$post->Form->text($fieldName) といった感じでフォームエレメントを出力できます。FkRecord::getVerboseName($fieldName) でフィールドの別名を取得できます。FkRecord::getError($fieldName) で、そのフィールドにエラーがあれば、その内容を取得します。

 

以上、簡単にですがご紹介まで。

もし奇特な方がいらっしゃいましたら、一度ご利用いただき、是非フィードバックなどを頂けたら嬉しいです! 是非! 是非!

 

投稿日:

JavaScript の超便利なメソッド bind で this を制御する


JavaScript の関数オブジェクトには、「bind」という便利なメソッドがあります。このメソッドは関数内で参照できる this を指定のオブジェクトに束縛できるものです。この関数を使うと、this に関連した良く有る問題をスマートに解決できます。

this にまつわるよくある問題

次の例は、実行後に「こんにちわ ぷんちゃん」とアラートするコードです。

では、3秒後に表示させてみましょう。よく次のように書きます。

これは期待通りに動作します。しかし、setTimeout に渡している無名関数は、単に Person.sayHello() をコールしているだけなので、次のようにも書けそうです。

しかし、これは期待通りには動作しません。
通常、ブラウザで実行させている時には「こんにちわ undefined」と表示されます。

これは JavaScrip における一般的な動作です。オブジェクトのメソッドはオブジェクトに束縛されているものではなく、その時々のコンテキストにおいて実行されるからです。JavaScript をある程度理解しているプログラマは、このことを良くご存知のはずです。

bind を使って this を束縛する

さて、本題です。

この this を固定してしまえるメソッド「bind」が関数オブジェクトには存在します。
例を見てみます。

今度は期待通り動作しました。

bind メソッドはこのように、関数内の this を指定のオブジェクトに束縛した新しい関数を返す機能を提供します。上の例では、bind に punchan オブジェクトを与えて、sayHello メソッド内の this が常に punchan オブジェクトとなるような新しい関数を取得し、それを setTimeout に渡すことで、期待通りの動作を実現しました。

このように、bind を使うことで、関数実行時の this を簡単に束縛できます。JavaScript でオブジェクトを利用したスクリプトを書く時にはとても便利ですね!

別のよくありそうな例

もうひとつ、良く有りそうな例を。

14行目で this を参照していますが、この時の this は Person オブジェクトでは無くて、グローバルオブジェクト(ブラウザなら通常 window オブジェクト)になります(ちなみにその this が決定されているのは、3行目の呼び出し部です)。

14 行目の this の部分で、Person オブジェクトを参照したい時に、よく次のようにするでしょう。

13 行目で期待する this の値を一旦別の変数に移して、その変数を 15 行目で参照しています。これは上手く行きます。しかし、関数オブジェクトの bind を使うと、次のようにも書けます。

15 行目で bind を使って、13〜15 行目に定義した無名関数オブジェクト内での this を指定しています。このケースではこの方がスマートですね!

読みやすさについてはケースバイケースだと思いますが、これは JavaScript でオブジェクトを扱う時の基本テクニックの一つです。このような bind の用法を知っておくことで、より読みやすいコードを書ける場面も増えると思います。

ちなみに、bind にはどんなオブジェクトでも渡すことができます。ここでは this を渡していますが、必要に応じて、様々なオブジェクトを、関数内の this として bind できるということを覚えておいてください。

bind による引数の部分適用

実は bind は this だけではなく関数の引数も束縛することが出来ます。
次の例を見てください。

4 行目の mul(2, 3) は、単純な関数呼び出しです。6とアラートされます。

7 行目で bind を利用して、引数の一つを 2 に束縛した新しい関数 mul2 を得ています。
8、9 行目の意味が分かるでしょうか? 関数 mul2 は、関数 mul の最初の引数が 2 に束縛されているものなので、常に 2 * b の演算を行ってアラートする関数になります。結果、ここではそれぞれ 2 * 4 ⇒ 8、2 * 16 ⇒ 32 というアラートが表示されます(ちなみに、前述の通り bind の第1引数には this とするオブジェクトを指定しますが、ここでは this は使っていないため null としています)。

また、11 行目からのように、引数が部分適用された関数を、更に部分適用する事もできます。

mul.bind(null, 2) で返される関数と等価なコードを書くと、次のようになります。

使いどころが難しい機能かも知れませんが、ライブラリなどの汎用性を高める為に利用することが出来そうですし、アイデア次第、使い方次第、ということになると思います。

引数の部分適用の例1

引数の部分適用の例を挙げてみます。

これは tags というコレクションオブジェクトから任意の tag を削除するコードです。tags.remove メソッドは jQuery.Deferred オブジェクトを返し、tag の削除に成功した時に done、失敗した時に fail にセットされたコールバック関数が呼ばれるというコードです。ここでコールバックでは alert を表示することしかしていません。これを bind を使って書き換えると、次のように書けます。

如何でしょうか? この例が見やすいかどかは人それぞれだと思いますが、このように使えるということを覚えていると、きっと何かの時に役立つかと思います。

もう一つ、もう少し使いどころがありそうな例を挙げてみます。

引数の部分適用の例2

次のコードは、1秒毎に3回 alert がコールされて「○秒後!」と表示します。もちろん、「1秒後!」「2秒後!」「3秒後!」となることを期待していますが、これは3回とも「4秒後!」と表示されてしまいます。クロージャ変数についてよくある問題ですね。

これは例えば次のようにして期待通りの動作をさせることが出来ます。

ただ、ちょっとややこしいですね…。

そこで、bind による引数の部分適用を利用すると、次のように書くことができます。

これはスッキリして、またしっくり来るのではないでしょうか (*’-‘*)

以上です。

ご存知の方はご存知というお話ですが、僕はつい半年位前まで知らなかったもので共有させて頂きました。

 

 

 

 

投稿日:

WordPress のマルチサイトで、ネットワークブログの投稿を一覧表示する


[2013-07-12 追加] 公式プラグインディレクトリに「WP Over Network」をリリースしました。管理画面からインストールできます。とりあえずの日本語の紹介はコチラのページになります。


[2013-06-07 追記] GitHub にプラグイン化したものをアップしています。良かったらご利用ください。フォーク歓迎。https://github.com/yuka2py/wp_over_network


WordPress をネットワーク化してマルチサイトを運用する際、ネットワーク上の各ブログの記事の更新情報をホストサイトのホームページなどに一覧表示させるという要件があると思います。

@HissyNC さんの「WordPressマルチサイトネットワークから新着記事を取得するコード(修正版)」を参考にして考えてみましたが、今回はネットワークサイトの更新情報をまとめたアーカイブページを持つ必要があったため、かわりに以下のような方法を行ってみました。

以下に簡単に解説します。

  • 《1》で wp_blogs テーブルよりブログの一覧を取得
  • 《2》で《1》で取得したブログから投稿を取得するサブクエリを準備
  • 《3》でクエリ全体を組み立て
  • 《4》で記事データと、総件数を取得
  • 《5》で wp_query の変数の一部を書き換え

大きなポイントは、《3》で各サイトの投稿テーブルを UNION ALL してしまうことと、《5》で wp_query を書き換えることです。《5》を行う事によって、wp_pagenavi などのプラグインでページナビゲーションの表示が可能になります。なかなか泥臭いことをやっていますね。 (; ^ω^)

上記の関数は、例えば次のようにして利用できます。

このサンプルは固定ページを準備して、固定ページのテンプレートに直接上記のコードを書いて、ネットワークブログのアーカイブページとして表示させるイメージです。

  • 15行目で投稿データを取得
  • 17行目で、wp_pagenavi を呼び出してページャーを表示しています。
  • 24行目でブログを切り替え、25行目で投稿データをセットアップ
  • 33行目でブログをカレントブログに戻します。

これで wp_pagenavi によるページナビゲーションもちゃんと表示されます。もちろんページの移動も可能です。

 

§

以下は、汎用的に使えるように幾つかオプションを足して、整理したものです。ご参考まで。

上記は、最初のサンプルとほぼ同様に、次のようにして利用できます。

 

以上です。

 

投稿日:

CakePHP2.x の Shell で Component を使う


CakePHP2.x の Shell で Component を使う、というよくありそうな要件です。

検索してみて色々出てくるのですが、微妙に上手く行かなかったり、上手くいくものの「こっちの方が正しいのでは?」と思えたりしたので、下記にメモしておきます。

特に難しいことをしているわけでなく、ComponentCollection を new し、そこから load するのが良さそうなのかな、ということですが、ComponentCollection を自分で new するのに少々疑問もあるのです。 (; ^ω^)

もしより良い方法があればどなたかご教示ください。