2011/01/10

Symfony2 クイックツアー 第3部

日本Symfonyユーザ会にて日本語ドキュメントが公開されています。そちらを参考にしてください。
コントローラ | Symfony2日本語ドキュメント
http://docs.symfony.gr.jp/symfony2/quick_tour/the_controller.html
日本語訳(下書き):
Symfony - The Controller
http://symfony.com/doc/2.0/quick_tour/the_controller.html

3. コントローラ

第1部と第2部を読み終えても、まだ読み続けているの? あなたはもうすっかり Symfony2 中毒になっていますね! 余談はこれくらいにして、コントローラで何ができるのかを見ていきましょう。

3.1. フォーマットの使用

今日では、Web アプリケーションは単なる HTML ページ以上のモノを配信できるはずです。 Web サービスには、RSS フィード用の XML から、Ajax リクエスト用の JSON まで、選択するに足る種々のフォーマットがあります。 Symfony2 では、これらのフォーマットを直接サポートしています。 では、routing.yml を編集して、xml の値を持つ _format を追加してみましょう:

# src/Sensio/HelloBundle/Resources/config/routing.yml
hello:
    pattern:  /hello/{name}
    defaults: { _controller: HelloBundle:Hello:index, _format: xml }
<!-- src/Sensio/HelloBundle/Resources/config/routing.xml -->
<route id="hello" pattern="/hello/{name}">
    <default key="_controller">HelloBundle:Hello:index</default>
    <default key="_format">xml</default>
</route>
// src/Sensio/HelloBundle/Resources/config/routing.php
$collection->add('hello', new Route('/hello/{name}', array(
    '_controller' => 'HelloBundle:Hello:index',
    '_format'     => 'xml',
)));
コードの元になっているのは sandbox PR6 時点です。
追加するのは次の赤字の部分です。
defaults: { _controller: HelloBundle:Hello:index, _format: xml }

次に、index.html.twig がある場所と同じところに index.xml.twig テンプレートを作成します:

<!-- src/Sensio/HelloBundle/Resources/views/Hello/index.xml.twig -->
<hello>
    <name>{{ name }}</name>
</hello>

最後に、フォーマットに応じてテンプレートを選択する必要があるので、コントローラに対して次のような変更を行います:

// src/Sensio/HelloBundle/Controller/HelloController.php
public function indexAction($name, $_format)
{
    return $this->render(
        'HelloBundle:Hello:index.'.$_format.'.twig',
        array('name' => $name)
    );
}

これで完了です。 Symfony2 では、標準フォーマットに関しては、レスポンスに適切な Content-Type ヘッダを自動的に選択します。 あるアクションに対して、異なるフォーマットをサポートしたい場合には、パターンに {_format} プレースホルダーを使います:

# src/Sensio/HelloBundle/Resources/config/routing.yml
hello:
    pattern:      /hello/{name}.{_format}
    defaults:     { _controller: HelloBundle:Hello:index, _format: html }
    requirements: { _format: (html|xml|json) }
<!-- src/Sensio/HelloBundle/Resources/config/routing.xml -->
<route id="hello" pattern="/hello/{name}.{_format}">
    <default key="_controller">HelloBundle:Hello:index</default>
    <default key="_format">html</default>
    <requirement key="_format">(html|xml|json)</requirement>
</route>
// src/Sensio/HelloBundle/Resources/config/routing.php
$collection->add('hello', new Route('/hello/{name}.{_format}', array(
    '_controller' => 'HelloBundle:Hello:index',
    '_format'     => 'html',
), array(
    '_format' => '(html|xml|json)',
)));

この時点では、/hello/Fabien.xml または /hello/Fabien.json のような URL に対して、コントローラが呼び出されます。

requirements エントリーには、{_format} プレースホルダーが一致する必要のある正規表現を定義します。 この例では、/hello/Fabien.js リソースにリクエストしようとすると、_format の条件にマッチしないので、HTTP 404 エラーを返します。(訳注: リクエスト URI が /hello/Fabien.xml のとき、$name={name}=Fabien、$_format={_format}=xml が代入されるイメージです。)

3.2. レスポンスオブジェクト

さて、Hello コントローラに戻りましょう:

// src/Sensio/HelloBundle/Controller/HelloController.php

public function indexAction($name)
{
    return $this->render('HelloBundle:Hello:index.html.twig', array('name' => $name));
}

render() メソッドは、テンプレートをレンダーリングし、Response オブジェクトを返します。 レスポンスをブラウザーに送信する前に、それを調整することができます。例として、 Content-Type を変更してみましょう:

public function indexAction($name)
{
    $response = $this->render('HelloBundle:Hello:index.html.twig', array('name' => $name));
    $response->headers->set('Content-Type', 'text/plain');

    return $response;
}

シンプルなテンプレート用に、手動で Response オブジェクトを作成して、数ミリ秒を節約することもできます:

public function indexAction($name)
{
    return new Response('Hello '.$name);
}

コントローラで Ajax リクエストのために JSON レスポンスを送り返す必要があるとき、これは本当に役立ちます。

3.3. エラーの管理

実体が見つからない場合、HTTP プロトコルで上手に処理するべきなので、404 レスポンスを返します。 これは、組込みの HTTP 例外をスローすることで簡単にできます:

public function indexAction()
{
    $product = // データベースからオブジェクトを取得
    if (!$product) {
        throw new NotFoundHttpException('The product does not exist.');
    }

    return $this->render(...);
}

NotFoundHttpException は、ブラウザーに HTTP 404 レスポンスを返します。

3.4. リダイレクトとフォワード

ユーザーを別ページにリダイレクトする場合は、RedirectResponse クラスを使用します:

return new RedirectResponse($this->generateUrl('hello', array('name' => 'Lucas')));

generateUrl() メソッドは、router ヘルパーを使用する、前の generate() メソッドと同じです。 このメソッドは、ルート名とパラメータの配列を引数にとり、わかりやすい関連 URL を返します。

forward() メソッドで、簡単に別ページにアクションをフォワードすることもできます。 actions ヘルパーに関しては、内部でサブリクエストを行いますが、forward() メソッドでは変更を加えることのできる Response オブジェクトを返します:

$response = $this->forward('HelloBundle:Hello:fancy', array('name' => $name, 'color' => 'green'));

// レスポンスに対して何かを行う、またはレスポンスを直接返す

3.5. リクエストオブジェクト

コントローラは、ルーティングのプレースホルダー設定値の他に、Request オブジェクトへのアクセス権も持っています:

$request = $this->get('request');

$request->isXmlHttpRequest(); // Ajax リクエストかどうか?

$request->getPreferredLanguage(array('en', 'fr'));

$request->query->get('page'); // $_GET パラメータを取得

$request->request->get('page'); // $_POST パラメータを取得

テンプレートでは、app.request 変数経由で、Request オブジェクトにアクセスすることもできます:

{{ app.request.query.get('page') }}

{{ app.request.parameter('page') }}

3.6. セッション

HTTP プロトコルがステートレスでも、Symfony2 はクライアント (ブラウザーを使用している人や、ボット、もしくは Web サービス) を表現する素晴らしいセッションオブジェクトを提供します。 Symfony2 は、2 つのリクエスト間において、PHP 固有のセッションを用いて、セッション属性をクッキーに保存します。

任意のコントローラから簡単に、セッション情報の保存と取得ができます:

$session = $this->get('request')->getSession();

// 後のユーザーリクエスト時に再利用する属性を保存
$session->set('foo', 'bar');

// 別のリクエスト用の別のコントローラに
$foo = $session->get('foo');

// ユーザーロケールを設定
$session->setLocale('fr');

すぐ次のリクエストでのみ利用可能なスモールメッセージを格納することもできます(訳注: setFlash メソッドでセッションに格納したメッセージは、そのメッセージを格納したリクエストの後、その次のリクエスト完了後に自動的に削除されます。):

// すぐ次のリクエスト用のメッセージを保存 (コントローラで)
$session->setFlash('notice', 'Congratulations, your action succeeded!');

// 次のリクエスト時に復活するメッセージを表示 (テンプレートで)
{{ app.session.flash('notice') }}

3.7. 最後に

これで終わりです。 10 分もかからなかったと思います。 第 1 部ではバンドルを簡単に紹介しました。 これまでに学んできた機能のすべては、コアフレームワークのバンドルの一部になります。 バンドルのおかげで、Symfony2 にあるものすべてを拡張または置換することができるのです。 それが本チュートリアルの次部のトピックになります。

翻訳元:
updated redirected response - 2011-02-21 09:15:24
https://github.com/symfony/symfony-docs/blob/master/quick_tour/the_controller.rst
注意: 誤訳が多く含まれている可能性があるため、文章の一部引用はなるべくしないでください。 掲載内容に関しては参考程度にしてください。 誤った情報を拡散しないようにご協力をお願いします。

0 コメント: