呆れるほど簡単なURLスラッグの作り方

I’ve seen this idea floated on a bunch of different blogs. Many offer more complicated methods or
behaviors/helpers to simplify things. This is the most basic, stupidly easy way to accomplish it.

今までにいくつもの異なるブログで、このアイデアに対する提案がなされるのを見てきました。その多くは、複雑な方法を提示するか、[複雑な方法を]単純にするためのビヘイビア/ヘルパーを提示するか、どちらかです。ここで紹介するのは最も基本的で、呆れるほどに簡単な方法です。

If you are viewing a single item within a Cake site, your URL will be something like /posts/view/
5, where “posts” is the model and “5” is the id of the item.

Cakeで[作られた]サイトで単独の項目を表示しているとき、URLは /posts/view/5 のようになっているでしょう。postsがモデル、5が項目のidです。

To generate a link to /posts/view/5 you’d use code like this:

/posts/view/5 に対するリンクを生成するには、こんな感じのコードを使うでしょう:

$html->link('CakePHP Tips', array('controller' => 'Post',
                                  'action' => 'view',
                                  5));

But you probably aren’t passing in the id directly, passing the element of a data array instead.
Something like:

しかしidを直接渡すようなことはまずなくて、代わりにデータ[を含む]配列の要素を渡します。次のように:

$html->link($post['Post']['title'], array('controller' => 'Post',
                                  'action' => 'view',
                                  $post['Post']['id']));

Assuming you’re using a standard action for your view, like:

view には標準的なアクションを用いていると仮定します。このように:

function view($id=null) { ... }

It is safe to create URLs with extra parameters. For example, the URL
/posts/view/5/cakephp-tips will render the exact same as /posts/view/5. That means you
can sneak the slug onto your link and not have to make any changes in your controller.
CakePHP even provides a method for creating slugs: Inflector::slug.

[ところで]URLは余分なパラメータを使って作ったとしても問題ありません。例えば /posts/view/5/cakephp-tips というURLは /posts/view/5 と全く同じ表示を行うでしょう。これはスラッグをリンクの上に忍び込ませることができ、なおかつコントローラには何の変更もいらないということです。さらにCakeはスラッグを作るためのメソッドまで提供してくれています:

You can now create your links like this:

だから次のようにリンクを作ることができます。

$html->link($post['Post']['title'], array
                                  (
                                   'controller' => 'Post',
                                   'action' => 'view',
                                   $post['Post']['id'],
                                   Inflector::slug($post['Post']['title'])
                                  )
            );

This will generate the URL /posts/view/5/cakephp_tips. With this method you don’t have to
worry about keeping track of slugs in your database or re-routing slugs if the title changes.

このコードは /posts/view/5/cakephp_tips というURLを生成するでしょう。この方法に関しては、スラッグを常にデータベースの中で管理しておくだとか、タイトルが変わったときにスラッグのルーティングをやり直すだとかいった心配は不要です。

Making The Slugs A Bit Smarter
スラッグをもう少し洗練する

Changing The Underscore To A Hyphen

アンダースコアをハイフンに変更する

If you prefer ‘-’ instead of ‘_’ as the replacement for spaces, just pass it as the second parameter
to Inflector::slug like this:

スペースの代替文字として ‘_’ ではなく ‘-’ をお望みなら、Inflector::slug の第2パラメータに渡してください。このように:

Inflector::slug($post['Post']['title'], '-')

Consistency And SEO Improvements

一貫性とSEOの改善

Using this method for your slugs means that anything is allowed in the URL and your site will still
display it. For instance, someone could make the URL be
/posts/view/5/cakephp_sucks_and_so_does_your_site and your site would happily display
the content indexed at id 5. Not only does this allow for malicious links, but it can hurt your SEO
by having so many different links point to the same content.

スラッグの生成にこの方法を用いるということは、URLの中に何を入れられても、それでもなおサイトの表示は行われる、ということです。例えば誰かがURLを /posts/view/5/cakephp_sucks_and_so_does_your_site にしたとしても、あなたのサイトは喜んで id 5 の内容を表示することでしょう。これは悪意のあるリンクを許すというだけではありません。同じコンテンツを指す多数の異なるリンクを持つことで、SEOにも悪影響を与えます。

It’s easy enough to check if the slug being requested matches the intended slug and redirect the
user if it doesn’t. In your controller’s action, after you load the post, put:

リクエストされたスラッグが意図したものと一致しているか調べ、一致していなければリダイレクトする[ように変更する]のは簡単です。コントローラのアクションの中で、投稿を読み出した後に、[次のコードを]加えてください。

If(Inflector::slug($post['Post']['title']) != $this->params['pass'][1]
   || count($this->params['pass']) != 2) {
  $post = $this->Post->read(null, $id);
  $this->redirect(array($id,
                        Inflector::slug($post['Post']['title']), 301));
}

Leave a Reply