CakePHPのRSSヘルパーの使い方まとめ

名前をつけてやる』で RSS を出力するのに
CakePHP の RSS ヘルパーを使ってみたんだけど、
これが便利便利。
いったん組み込めばあとは簡単に RSS を生成できるし、
ほとんど追加作業なしで複数の RSS を吐くこともできる。

ただ手元に資料があんまりなくて
導入に少し戸惑ったのでやったことメモ。
「使い方まとめ」って書いたけど、
要するに「何をやったか」です。

例として、

  • 通常 http://example.com/posts/index に出しているデータを RSS に吐き出したい。
  • 個別のポストのページは /posts/view/[ID] で見る。
  • PostsController から index のビューに $posts というデータが渡されている。
  • トップページは /posts/index にルーティングされている

という状況設定で。

とにかく使えるようにする

次の4点をやれば、とりあえず使えるようになると思う。

  1. Router に parseExtensions を追加する
  2. コントローラーに RequestHandler を組み込む
  3. RSS 用のレイアウトを設置する
  4. 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']
    );
}

とでもしたらいいんじゃないですかね。

とりあえず以上

何か思い出したら追記します。
何か間違ってたら指摘してください。

  • このエントリーをはてなブックマークに追加