0 follower

URLの取り扱い

Webアプリケーションの包括的なURLの取り扱いには2つの側面があります。1つ目は ユーザーのURLからのリクエストをアプリケーションが理解できる形に解析する事。 2つ目はWebアプリケーションによって解析されるURLの作成方法を提供することで、 この二つはCUrlManagerの手助けによって行われます。

1. URLの作り方

URLはコントローラービューの中に直接コーディングしてしまう事も出来ますが、 次の様に動的な書き方をすることで融通が利く場合が多いでしょう:

$url=$this->createUrl($route,$params);

$thisはコントローラのインスタンス; $routeはリクエストのroute そして$paramはURLに付加されるGETパラメータです。

デフォルトでは、createUrl によって作成されるURLは いわゆるgetクエリの書式になります。例えば、 $route='post/read' かつ $params=array('id'=>100) の場合のURLは以下の通りです:

/index.php?r=post/read&id=100

GETクエリの書式はパラメータ名=値の一組を&で繋げた形になっていて、 r= の部分はリクエストされた [route] (/doc/guide/basics.controller#route) を示しています。このURLの書式は いくつかの言葉ではない文字を含んでいる為、あまりユーザーフレンドリーとは 言えないでしょう。

この様なURLを、GETパラメータをURLのパスへ置き換えてクエリ文字列を除いた パスフォーマットと呼ばれる形式にする事で分かり易い形式へ変更できます:

/index.php/post/read/id/100

URLの書式を変えるには、アプリケーションコンポーネントの urlManagerを以下で記述する様に設定します。 設定によってcreateUrlは自動的に新しい書式の URLを作成する様になり、アプリケーションは作成されたURLを正しく認識 出来る様になります:

array(
    ......
    'components'=>array(
        ......
        'urlManager'=>array(
            'urlFormat'=>'path',
        ),
    ),
);

urlManagerのクラスはCWebApplicationCurlManagerですでに宣言済みなので明記する必要が無い点に注意して下さい。

ヒント: createUrlで作成されたURLは相対URLです。 絶対URLが必要な時は、Yii::app()->hostInfoをプリフィックスにするか createAbsoluteUrlをコールします。

2. ユーザーフレンドリーなURL

パスがURLに用いられる場合、いくつかのルールを指定する事でURLをもっと ユーザーフレンドリーにできます。例えば/index.php/post/read/id/100 といった長いURLの代わりに/post/100の様な短いURLを作成することができます。 URLのルールの作成と解析は両方ともCUrlManagerによって行われます。

URLの規則を指定するには、アプリケーションコンポーネント urlManagerrules プロパティを設定する必要があります:

array(
    ......
    'components'=>array(
        ......
        'urlManager'=>array(
            'urlFormat'=>'path',
            'rules'=>array(
                'pattern1'=>'route1',
                'pattern2'=>'route2',
                'pattern3'=>'route3',
            ),
        ),
    ),
);

rulesはパターン-ルートの組み合わせから成る配列によって指定されます。 配列の一つ一つは単独のルールから成り立っています。ruleのパターンは、 デリミタ(区切り文字)とモデファイア(修飾子のオプション)を取り除いた形の 正規表現パターンでなければなりません。このパターンは、パスインフォに マッチさせる為に使われます。そして、 route は正しいコントローラのルート を示していなければなりません。

Named Parameter の使用

一つ一つのruleは、いくつかのGETパラメータと結びつける事が出来ます。 その場合の書式は以下の様になります:

<ParamName:ParamPattern>

ParamNameにはGETパラメータの名前、オプションのParamPatternは 正規表現でGETパラメータの値にマッチさせた物が入る必要があります。 URLを作成する時には、この正規表現に結びついたGETパラメータの値によって 置き換えられたURLが作成されます。 URLが解析される時は、パターンの 解析後の結果がGETパラメータに入ります。

では、URLのルールがどうやって動くのか試してみましょう。ここでは3つの ルールがあると仮定します:

array(
    'posts'=>'post/list',
    'post/<id:\d+>'=>'post/read',
    'post/<year:\d{4}>/<title>'=>'post/read',
)
  • $this->createUrl('post/list') をコールした場合、1番目のルールが 適用されて /index.php/posts が作成されます。

  • $this->createUrl('post/read', array('id'=>100))をコールした場合、 2番目のルールが適用されて /index.php/post/100 が作成されます。

  • $this->createUrl('post/read', array('year'=>2008, 'title'=>'a sample post')) をコールした場合、3番目のルールが適用される事になり /index.php/post/2008/a%20sample%20post が作成されます。

  • $this->createUrl('post/read')をコールした場合、どのルールも適用 されないので /index.php/post/read が作成されます。

要点をまとめますと、createUrl でURLを 作成した時、createUrlメソッドに渡されたルートパラメータとGETパラメータの 配列は、どの URLのルールが適用されるかを決定するために用いられます。 もしルールで定められたパラメータが全てcreateUrlに 渡されたGETパラメータ配列に結びついていて、そしてもし、ルールで定められた ルートと、メソッドに渡されたルートパラメータがマッチしていれば、そのルール はURLの作成に適用されるということです。

もし、createUrl メソッドに、ルールで定められた 以上のパラメータが渡された場合、追加のパラメータはクエリ文字列として表示 されます。例えば先ほどのルールと同じ条件の場合に、$this->createUrl( 'post/read', array('id'=>100, 'year'=>2008))とした場合、URLは /index.php/post/100?year=2008になります。これらのルールで定めた以上の 追加のパラメータもスラッシュ区切りのパスインフォ形式のURLとして扱いたい場合 /*を追加します。つまりこの場合は、ルールを post/<id:\d+>/* とすることで /index.php/post/100/year/2008 というURLを作成させるようにできます。

ここまでで述べた様に、URLのルールの目的のもう一つの側面は、リクエスト されたURLを解析する事です。これは当然ですがURLの作成の逆の動作です。例えば ユーザが/index.php/post/100 というURLをリクエストした時、2番目のルールが 適用される事になり、post/read のルートが呼ばれ、GETパラメータの中には array('id'=>100)というパラメータ($_GETでアクセス可能)が入ります。

注意: URL ルールの使用は、アプリケーションパフォーマンスを低下させます。 これは、リクエスト URL のパースの際、CUrlManager がマッチするルールを探そうとする為です。 ルールの数が多ければ多いほど、パフォーマンスへの影響は強くなります。 その為、通信量の大きいWebアプリケーションの作成時は、URLルールの作成を 最小限に留めるべきです。

ルートのパラメータ化

バージョン 1.0.5 以降、ルールのルート部分(訳注:ルールを記述する配列の値の部分)で Named Parameter を参照できるようになりました。 これは、ルールがマッチングクライテリアに基づき複数のルートに適用される事を可能にします。 また、それは、アプリケーションに必要なルールの数を減少させ、それにより、総合的なパフォーマンスの向上に役立つかもしれません。

Named Parameter と共にルートのパラメータ化方法を説明するのに、下記のルールを使用します:

array(
    '<_c:(post|comment)>/<id:\d+>/<_a:(create|update|delete)>' => '<_c>/<_a>',
    '<_c:(post|comment)>/<id:\d+>' => '<_c>/read',
    '<_c:(post|comment)>s' => '<_c>/list',
)

上記では、ルールのルート部分で、_c_a の 2 つの Named Parameter を使用します。 前者は、コントローラ ID postcomment のどちらかにマッチし、 後者は、アクション ID createupdatedelete のいずれかにマッチします。 URL に現れるかもしれない GET パラメータと衝突しない限り、異なるパラメータを指定できます。

上のルールを使用し、URL /index.php/post/123/create へアクセスすると、 GET パラメータ id=123 を伴った、ルート post/create とパースされます。 また、ルート comment/list と GET パラメータ page=2 を渡すために、 /index.php/comments?page=2 という URL を使用できます。

index.phpの隠し方

URLをもっと綺麗にするために、もう一つの方法があります。例えば、 エントリースクリプトのindex.phpをURLから隠すことです。この方法は urlManager アプリケーションコンポーネントの他 にWebサーバの設定が必要になります。

URL からエントリースクリプトが消えても、エントリースクリプトを扱い続ける 為には、まずはじめにWebサーバーの設定が必要です。 [Apache HTTPserver] (http://httpd.apache.org/)の場合、URLリライティングエンジンを有効化し、 幾つかのリライティングルールを指定します。どちらも..htaccessファイルを エントリースクリプトと同じディレクトリ上に配置することで実現できます。 以下が例です:

Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on

# ディレクトリ名やファイル名が実在する場合は変換を行いません。
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# それ以外の場合は、index.phpへ進みます。
RewriteRule . index.php

この場合は、urlManagerコンポーネントの showScriptNameプロパティをfalseに設定 します。

さあ、これでもし$this->createUrl('post/read',array('id'=>100))を コールした場合、/post/100 というURLが作成される様になりました。ここで 重要な点は、このURLがWebアプリケーションにも正しく認識されるものである という事です。

URLにおける擬似的な拡張子

URLに拡張子を付加することができます。例えば、/post/100 の代わりに /post/100.html の形にする事ができます。これによって、URLをより静的なURLの 様に見せることができます。そうする場合は単純に、 urlManager コンポーネントの urlSuffix プロパティを使用したい拡張子に設定する だけです。