『名前をつけてやる』で RSS を出力するのに
CakePHP の RSS ヘルパーを使ってみたんだけど、
これが便利便利。
いったん組み込めばあとは簡単に RSS を生成できるし、
ほとんど追加作業なしで複数の RSS を吐くこともできる。
ただ手元に資料があんまりなくて
導入に少し戸惑ったのでやったことメモ。
「使い方まとめ」って書いたけど、
要するに「何をやったか」です。
例として、
- 通常 http://example.com/posts/index に出しているデータを RSS に吐き出したい。
- 個別のポストのページは /posts/view/[ID] で見る。
- PostsController から index のビューに $posts というデータが渡されている。
- トップページは /posts/index にルーティングされている
という状況設定で。
とにかく使えるようにする
次の4点をやれば、とりあえず使えるようになると思う。
- Router に parseExtensions を追加する
- コントローラーに RequestHandler を組み込む
- RSS 用のレイアウトを設置する
- RSS 用のビューを書く
1. Router に parseExtensions を追加する
app/config/routes.php に次の1行を追加するだけ。
Router::parseExtensions('rss');
2. コントローラーに RequestHandler を組み込む
RSS に出すデータを扱うコントローラーで
コンポーネントの設定に RequestHandler 追加するだけ。
今回の例で言えば Posts Controller ですね。
var $components = array('RequestHandler');
3. RSS 用のレイアウトを設置する
cake/libs/view/layouts/rss/default.ctp
というファイルが用意されているので、これを
app/views/layouts/rss/default.ctp
にコピーする。以上。
4. RSS 用のビューを書く
これはサンプルが用意されていない(と思う)ので
てけとーなのを書いて
app/views/posts/rss/index.ctp
に置く。
$this->set('channel', array ( 'title' => 'サイトのタイトル', 'link' => 'サイトのトップページの URL', 'description' => 'サイトの説明文' )); echo $rss->items($posts, 'transformRSS'); function transformRSS($posts) { return array( 'title' => $posts['Post']['title'], 'link' => array('action' => 'view', $posts['Post']['id']), 'guid' => array('action' => 'view', $posst['Post']['id']), 'description' => $posts['Post']['body'], 'pubDate' => $posts['Post']['created'] ); }
上記はサンプルなので、
transformRSS() の変換内容は
環境に合わせててけとーに。
以上の4つを設定して
http://example.com/posts.rss
にアクセスすると、RSS が取得できるはず。はず。
ただしこれだけではまだ寂しいので
もうちょっと詳しく見てみる。
もうちょっと詳しく見てみる
データはどうするか
RSS のビューの方で RSS 用に成形しているので、
特別なことをするのでなければ
普通にウェブページを出すのと同じデータを渡すだけでいいはず。
要するにコントローラーは別段いじる必要がないということね。
RSS の URL はどうなるか
とにかく URL の末尾に “.rss” をつけるだけでいい。
たとえば
http://example.com/posts/index
が吐き出すデータをRSS に渡したい場合は
http://example.com/posts/index.rss
という具合。
URL の末尾に “.rss” をつけるだけなので、
- http://example.com/.rss
- http://example.com/posts.rss
- http://example.com/posts/index.rss
など何でもアリ。
『名前をつけてやる』ではヘッダーで
http://namaewo.com/.rss
を指定してます。
さらに例えば
http://namaewo.com/names/by/msng
という URL で特定ユーザーのポストを表示するようにしてるんだけど、
その RSS も
http://namaewo.com/names/by/msng.rss
で取得できる。何て楽ちんな。
レイアウトとビューを RSS 用に切り替えるのは
parseExtensions と RequestHandler を一緒に使うと、
リクエストにあわせてレイアウトとビューを切り替え、
しかも拡張子と同じ名前のヘルパーがあれば
勝手にそれを呼び出してくれる。
だからこちらは何もしなくていい。
例えば Posts コントローラーを呼ぶとき
URL の末尾に “.rss” をつけたら
- レイアウトに /app/views/layouts/rss/default.ctp を使う
- ビューに /app/posts/rss/index.ctp を使う
- RSS ヘルパーを呼び出す
というのを自動でやってくれる。すばらしい。
サイトと RSS で出力を変えたい場合
また手前の例になるけど、
『名前をつけてやる』のサイトでは
1ページあたり10件の投稿を表示している。
ただこれはページめくりや Autopagerize があるからいけるのであって、
ものすごい勢いで投稿が続くと
10件なんてあっという間に埋まってしまう。
というわけで RSS の方には30件出すようにした。
前述のとおり、同じデータを出すなら
コントローラーに手を加えなくてもいいんだけど
こんなふうにサイトと RSS で出力件数を変える場合は
ひと手間加えましょう。
レイアウトの切り替えで活躍している RequestHandler には
isRSS() というメソッドがあるのでこれを使う。
実装とちょっと違うけど簡単に書くと
$num = $this->RequestHandler->isRSS() ? 30 : 10;
こんな感じですか。
気をつけること
デバッグの設定
app/config/core.php のデバッグ設定を
Configure::write('debug', 0);
にしておかないと
RSS に余計なものがまじってしまってエラーになるので
開発環境でも RSS のテストをするときは 0 にしておきましょう。
本番は当然 0 ですね。
ネームスペースの設定
RSS2.0 で個別の記事の投稿者を明示したいときは
<dc:creator> で指定することになると思うんだけど、
これを有効にするには
<rss xmlns:dc=”http://purl.org/dc/elements/1.1/” version=”2.0″>
という具合に rss 要素に xmlns 属性をつけて
ネームスペースを設定しないといけない。
以下「面倒な話はやめれ」という方は「ここまで」に飛んでください
先ほどコピーしたデフォルトのレイアウトファイルは
echo $rss->document( $rss->channel( array(), $channel, $content_for_layout ) );
などとなっていて
ここで RSS 文書を出力してるんだけど、
これでは rss 要素に属性を設定するようになってない。
この $rss->document() の部分のソースを見ると
function document($attrib = array(), $content = null) { if ($content === null) { $content = $attrib; $attrib = array(); } if (!isset($attrib['version']) || empty($attrib['version'])) { $attrib['version'] = $this->version; } return $this->elem('rss', $attrib, $content); }
第1引数 ($attrib) の配列の組み合わせが
rss 要素に与える属性と値の組み合わせになるんだけど
第2引数 ($content) が null の場合は
$content に 第1引数を代入して
$attrib は空の配列に置き換わる。
(その後、version 属性だけ $this->version (= 2.0) に設定される。)
先ほどのレイアウトファイルでは
第1引数が $rss->channel()、
第2引数はなし
となっているので、上述の処理を行うと
$attrib の内容は array(‘version’ => ‘2.0″) になり、
結果として rss 要素は
<rss version=”2.0″>
となる。
はい面倒な話ここまで。
具体的にどうすればいいかに行きます。
もっとオリコウな方法があると思うんだけど、
今回はレイアウトファイルの
echo $rss->document( $rss->channel( array(), $channel, $content_for_layout ) );
の部分を
echo $rss->document( array('xmlns:dc' => "http://purl.org/dc/elements/1.1/"), $rss->channel( array(), $channel, $content_for_layout ) );
というふうに書き換えました。
要するに2行目を追加ね。
こうやって rss 要素に xmlns:dc 属性をつけた上で、
上掲の app/views/posts/rss/index.ctp の
transformRSS() で返す配列に dc:creator を加えて
function transformRSS($posts) { return array( 'title' => $posts['Post']['title'], 'link' => array('action' => 'view', $posts['Post']['id']), 'guid' => array('action' => 'view', $posst['Post']['id']), 'description' => $posts['Post']['body'], 'dc:creator' => $posts['Post']['author'], 'pubDate' => $posts['Post']['created'] ); }
とでもしたらいいんじゃないですかね。
とりあえず以上
何か思い出したら追記します。
何か間違ってたら指摘してください。