Jobeetをやってみる 5日目

ルーティングについて学ぶ

設定ファイルについて

ルーティングの設定は routing.yml に記述されており、上から順にマッチしていく

アプリルートのカスタマイズ

初期設定ではルートの設定が /job になっていて、ドキュメントルートにアクセスしてもJobeetが表示されないようになっている。
まずはこれを変更する

# apps/frontend/config/routing.yml
homepage:
  url:   /
  param: { module: job, action: index }

そしたらlayoutのJobeet TOPへのリンクも修正する

<?php /* apps/frontend/templates/layout.php at 16 */ ?>
<h1><a href="<?php echo url_for('@homepage') ?>"><img src="http://www.symfony-project.org/images/jobeet.gif" alt="Jobeet Job Board" /></a></h1>

詳細表示ページのカスタマイズ

下記のようにアクセスできると、URLで表示しているページの内容を理解できるようになる
/job/sensio-labs/paris-france/1/web-developer
これになるように設定を変更していく

設定を変更

# apps/frontend/config/routing.yml
# 一番上に設定を追加する
job_show_user:
  url:   /job/:company/:location/:id/:position
  param: { module: job, action: show }

詳細ページへのリンクを修正する

<?php /* apps/frontend/modules/job/templates/indexSuccess.php at 7 */ ?>
<a href="<?php url_for("job/show?id={$job->getId()}&company={$job->getCompany()}&location={$job->getLocation()}&position={$job->getPosition()}") ?>">

配列で書く方法もある

<?php /* apps/frontend/modules/job/templates/indexSuccess.php at 7 */ ?>
<a href="<?php echo url_for(array(
  'module'    => 'job',
  'action'    => 'show',
  'id'        => $job->getId(),
  'company'   => $job->getCompany(),
  'location'  => $job->getLocation(),
  'position'  => $job->getPosition(),
)) ?>">

パラメータの書式指定

requirements の設定値で指定が可能

# apps/frontend/config/routing.yml
job_show_user:
  url:   /job/:company/:location/:id/:position
  param: { module: job, action: show }
  requirements:
    id: \d+

許可するHTTPメソッドを指定

指定できるのは GET, POST, HEAD, DELETE, PUT

今回はGETのみ許可する

# apps/frontend/config/routing.yml
job_show_user:
  url:   /job/:company/:location/:id/:position
  param: { module: job, action: show }
  requirements:
    id: \d+
    sf_method: [get]

Routeクラスを利用する

先程のリンクの張り方は冗長過ぎて、毎回書いていると可読性が低くなる
そんな時は、Routeクラスを利用して設定を名前で利用することができる

設定の変更
# apps/frontend/config/routing.yml
job_show_user:
  url:     /job/:company/:location/:id/:position
  class:   sfDoctrineRoute
  options: { model: JobeetJob, type: object }
  param:   { module: job, action: show }
  requirements:
    id: \d+
    sf_method: [get]

リンクの記述方法

記述方法は2通り

<?php /* apps/frontend/modules/job/templates/indexSuccess.php at 7 */ ?>
<a href="<?php echo url_for(array('sf_route' => 'job_show_user', 'sf_subject' => $job)) ?>">
<?php /* apps/frontend/modules/job/templates/indexSuccess.php at 7 */ ?>
<a href="<?php echo url_for(array('job_show_user', $job) ?>">

英数字以外の扱い

jobデータを取得する際に、英数字(非単語)以外を除去するようにする

<?php
// lib/model/doctrine/JobeetJob.class.php
public function getCompanySlug()
{
  return Jobeet::slugify($this->getCompany());
}

public function getPositionSlug()
{
  return Jobeet::slugify($this->getPosition());
}

public function getLocationSlug()
{
  return Jobeet::slugify($this->getLocation());
}
<?php
// lib/Jobeet.class.php
class Jobeet
{
  public static function slugify($text)
  {
    $text = preg_replace('/\W+/', '-', $text);
    $text = strtolower(trim($text, '-'));
    return $text;
  }
}
# apps/frontend/config/routing.yml
job_show_user:
  url:     /job/:company_slug/:location_slug/:id/:position_slug
  class:   sfDoctrineRoute
  options: { model: JobeetJob, type: object }
  param:   { module: job, action: show }
  requirements:
    id: \d+
    sf_method: [get]


キャッシュをクリアして、URIが下記のようになればOK
/frontend_dev.php/job/sensio-labs/paris-france/1/web-developer

ModelをRoute Classから取得する

Doctrineから取得していましたが、route.ymlにて指定したModelを取得することが可能なので、Routeクラスから取得するように変更します

<?php
// apps/frontend/modules/job/actions/actions.class.php
public function executeShow(sfWebRequest $request)
{
  $this->job = $this->getRoute()->getObject();
  $this->forward404Unless($this->job);
}

404エラーページ

<?php
$this->forward404Unless($this->job);

を削除しても404 error pageが表示されます。
これはgetRoute()が自動で行なっているもので、optionsにallow_emptyをtrueにすると抑制できます。

# apps/frontend/config/routing.yml
job_show_user:
  url:     /job/:company_slug/:location_slug/:id/:position_slug
  class:   sfDoctrineRoute
  options: { model: JobeetJob, type: object, allow_empty: true }
  param:   { module: job, action: show }
  requirements:
    id: \d+
    sf_method: [get]

Template内でのルーティング

<?php echo link_to($job->getPosition(), 'job_show_user', $job) ?>
絶対パスを利用する場合
<?php echo link_to($job->getPosition(), 'job_show_user', $job, true) ?>

<a href="/job/sensio-labs/paris-france/1/web-developer">Web Developer</a>

Action内でのルーティング

<?php
$this->redirect($this->generateUrl('job_show_user', $job));

また、redirect()にもforward()と同様のオーバーロードが利用されており、redirectIf()とredirectUnless()が利用できます

Collection Route Class

index. new, edit, create, update, deleteアクションのルーティングがまだdefaultの設定のままになっています。
defaultの設定は

default:
  url: /:module/:action/*

となっており、全てのアクションを受け入れてしまいます。

なので、本来はページ毎にルーティングを設定します。
今回はCRUD環境なのでモデルから自動でルーティングの設定をします。

# apps/frontend/config/routing.yml
job:
  class:   sfDoctrineRouteCollection
  options: { model: JobeetJob }

job_show_user:
  url:     /job/:company_slug/:location_slug/:id/:position_slug
  class:   sfDoctrineRoute
  options: { model: JobeetJob, type: object }
  param:   { module: job, action: show }
  requirements:
    id: \d+
    sf_method: [get]

# default rules
homepage:
  url:   /
  param: { module: job, action: index }
RouteCollectionについて

RouteCollectionを利用した場合、以下の設定をしたのと同じ状態になります。

job:
  url:      /job.:sf_format
  class:    sfDoctrineRoute
  options:  { model: JobeetJob, type: list }
  param:    { module: job, action: index, sf_format: html }
  requirements: { sf_method: get }

job_new:
  url:      /job/new.:sf_format
  class:    sfDoctrineRoute
  options:  { model: JobeetJob, type: object }
  param:    { module: job, action: new, sf_format: html }
  requirements: { sf_method: get }

job_create:
  url:      /job.:sf_format
  class:    sfDoctrineRoute
  options:  { model: JobeetJob, type: object }
  param:    { module: job, action: create, sf_format: html }
  requirements: { sf_method: post }

job_edit:
  url:      /job/:id/edit.:sf_format
  class:    sfDoctrineRoute
  options:  { model: JobeetJob, type: object }
  param:    { module: job, action: edit, sf_format: html }
  requirements: { sf_method: get }

job_update:
  url:      /job/:id.:sf_format
  class:    sfDoctrineRoute
  options:  { model: JobeetJob, type: object }
  param:    { module: job, action: update, sf_format: html }
  requirements: { sf_method: put }

job_delete:
  url:      /job/:id.:sf_format
  class:    sfDoctrineRoute
  options:  { model: JobeetJob, type: object }
  param:    { module: job, action: delete, sf_format: html }
  requirements: { sf_method: delete }

job_show:
  url:      /job/:id.:sf_format
  class:    sfDoctrineRoute
  options:  { model: JobeetJob, type: object }
  param:    { module: job, action: show, sf_format: html }
  requirements: { sf_method: get }

sf_***について

詳しいことは明日説明みたいなので、ここでは深く考えない

ルーティングの設定の確認

設定されているルーティングの一覧を見るには

$ symfony app:routes frontend

ルーティングの詳細情報を見るには

$ symfony app:routes frontend ルーティング名