Home | Symfony2Doc »クイックツアー »コントローラー

ご注意

Symfony2日本語翻訳ドキュメントは内容が古くなっております。公式サイトの英語ドキュメントを参照してください。

Note

  • 対象バージョン:2.3以降
  • 翻訳更新日:2013/11/23

コントローラー

チュートリアルの 3 つめのステップとして、この章ではコントローラーの機能をさらに見ていきます。

フォーマットを使う

今日では、Web アプリケーションは単なる HTML ページ以外の形式で応答することも要求されるようになっています。 RSS フィードや Web サービス向けの XML 形式、Ajax リクエスト向けの JSON 形式など、さまざまなフォーマットが存在します。 Symfony2 におけるフォーマットのサポートは、とても単純です。 ルートを編集して、_format 変数のデフォルト値として xml を指定してみましょう。

// src/Acme/DemoBundle/Controller/DemoController.php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

// ...

/**
 * @Route("/hello/{name}", defaults={"_format"="xml"}, name="_demo_hello")
 * @Template()
 */
public function helloAction($name)
{
    return array('name' => $name);
}

_format の値で定義されているリクエストのフォーマットを使って、Symfony2 が自動的に適切なテンプレートを決定します。 ここでは hello.xml.twig になります。

<!-- src/Acme/DemoBundle/Resources/views/Demo/hello.xml.twig -->
<hello>
    <name>{{ name }}</name>
</hello>

これだけです。レスポンスに対して適切な Content-Type ヘッダーが Symfony2 によって自動的に選択されます。 単一のアクションで複数の異なるフォーマットをサポートしたい場合は、ルートパターンに {_format} プレースホルダを使います。

// src/Acme/DemoBundle/Controller/DemoController.php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

// ...

/**
 * @Route("/hello/{name}.{_format}", defaults={"_format"="html"}, requirements={"_format"="html|xml|json"}, name="_demo_hello")
 * @Template()
 */
public function helloAction($name)
{
    return array('name' => $name);
}

このコントローラーは、/demo/hello/Fabien.xml/demo/hello/Fabien.json といった URL で呼び出されるようになります。

requirements エントリには、プレースホルダの値をチェックするための正規表現を定義します。 この例では、もし /demo/hello/Fabien.js というリソースへのリクエストがあった場合、_format の正規表現にマッチしないため、HTTP の 404 エラーが返されます。

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

ユーザーを別のページへリダイレクトさせたい場合は、redirect() メソッドを使います。

return $this->redirect($this->generateUrl('_demo_hello', array('name' => 'Lucas')));

generateUrl() メソッドの機能は、テンプレートで使った path() 関数と同じです。 ルート名とパラメータの配列を引数にとり、ルート名に関連付けられたパターンから URL を生成して返します。

アクションから別のアクションへフォワードするのも同じように簡単で、forward() メソッドを使います。 内部的には、フォワード先のアクションへの “サブリクエスト” が作られ、そのサブリクエストを実行した結果の Response オブジェクトが返されます。

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

// ... $response に対して何らかの処理を行うか、そのまま return する

リクエストから情報を取得する

ルーティングのプレースホルダーで設定した値のほかに、コントローラーから Request オブジェクトに直接アクセスすることもできます。

$request = $this->getRequest();

$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') }}

セッションにデータを格納する

HTTP プロトコルはステートレスですが、Symfony2 にはクライアント(ブラウザを使っている実際の人かもしれませんし、あるいはボットや Web サービスかもしれません)を表現した、使いやすいセッションオブジェクトが Symfony2 には組み込まれています。 PHP ネイティブのセッション機能を使って実装されており、複数のリクエストに渡って属性を保存できます。

セッションへの情報の保存とセッションからの情報の取得は、任意のコントローラーから簡単に行えます。

$session = $this->getRequest()->getSession();

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

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

// キーが存在しない場合のデフォルト値を指定
$filters = $session->get('filters', array());

直後のリクエストでのみ有効な小さなメッセージ(flash メッセージと呼ぶ)をセッションに保存することもできます。

// (コントローラー内)直後のリクエスト向けにメッセージを保存する
$session->getFlashBag()->add('notice', 'アクションの処理が完了しました。');

// (テンプレート内)直後のリクエストでメッセージを表示する

{% for flashMessage in app.session.flashbag.get('notice') %}
    <div>{{ flashMessage }}</div>
{% endfor %}

この機能は、ユーザーを別のページへリダイレクトさせる前に処理の完了メッセージを設定し、リダイレクト先のページでメッセージを表示する必要がある場合に便利です。 get() の代わりに has() を使った場合、対応する flash メッセージはクリアされないので、さらに次のリクエストでも参照可能です。

リソースのセキュリティーを設定する

Symfony Standard Edition には、よく使われる要件にあう単純なセキュリティーコンフィギュレーションが含まれています。

# app/config/security.yml
security:
    encoders:
        Symfony\Component\Security\Core\User\User: plaintext

    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    providers:
        in_memory:
            memory:
                users:
                    user:  { password: userpass, roles: [ 'ROLE_USER' ] }
                    admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }

    firewalls:
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false

        login:
            pattern:  ^/demo/secured/login$
            security: false

        secured_area:
            pattern:    ^/demo/secured/
            form_login:
                check_path: /demo/secured/login_check
                login_path: /demo/secured/login
            logout:
                path:   /demo/secured/logout
                target: /demo/

このコンフィギュレーションでは、/demo/secured/ で始まる任意の URL にアクセスしたユーザーにログインを要求するよう設定しています。また、useradmin という 2 種類のユーザーを定義しています。 さらに、admin ユーザーには ROLE_USER ロールを含む ROLE_ADMIN ロールが付与されています(role_hierarchy 設定を参照してください)。

Tip

可読性のために、この単純なコンフィギュレーションではパスワードが平文で記述されていますが、encoders セクションのコンフィギュレーションにより任意のハッシュアルゴリズムを設定できます。

http://localhost/app_dev.php/demo/secured/hello という URL へアクセスした場合、このリソースはファイアウォールで保護されているため、ユーザーは自動的にログインフォームへリダイレクトされます。

Note

Symfony2 セキュリティーレイヤーはとても柔軟で、たとえば Doctrine ORM 向けのユーザープロバイダーや、HTTP 基本認証、HTTP ダイジェスト認証、X509 証明書での認証といった認証プロバイダーなどが組み込まれています。 セキュリティーレイヤーの使い方と設定方法の詳細については、ガイドブックの “セキュリティ” の章を参照してください。

リソースをキャッシュする

構築したサイトのトラフィックが日に日に増えてくると、同一のリソースを何度も生成することを避けたいと考えるでしょう。 Symfony2 では HTTP キャッシュヘッダーを使ってリソースのキャッシュを管理できます。単純なキャッシュ戦略では、@Cache() アノテーションを使うと便利です。

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;

/**
 * @Route("/hello/{name}", name="_demo_hello")
 * @Template()
 * @Cache(maxage="86400")
 */
public function helloAction($name)
{
    return array('name' => $name);
}

この例では、リソースは 1 日キャッシュされます。 コンテンツの要件に合わせて単に期限を指定するのではなくバリデーションを使ったり、期限とバリデーションを組み合わせて使うこともできます。

リソースのキャッシュは、Symfony2 に組み込まれたリバースプロキシで制御されます。 また、一般的な HTTP キャッシュヘッダーを使ってキャッシュの制御を行うようになっているため、組み込みのリバースプロキシの代わりに Varnish や Squid に置き換えることもでき、アプリケーションを容易にスケールさせられます。

Note

ページ全体をキャッシュできない場合はどうするのでしょうか? Symfony2 には Edge Side Include (ESI) を使ったソリューションもあり、これもネイティブで組み込まれています。 キャッシュや ESI の詳細については、ガイドブックの “HTTP キャッシュ” の章を参照してください。

まとめ

この章はこれで終わりです。 10 分もかからなかったのではないでしょうか。 最初の章でバンドルという概念を簡単に解説したのを覚えていますか? 私たちが今学んでいる機能は、コアのフレームワークバンドルの機能の一部なのです。 バンドルの仕組みがあるおかげで、Symfony2 のすべての機能は拡張可能かつ置き換え可能です。 これが、次の章のトピックです。

blog comments powered by Disqus