2011/01/16

Symfony2 クイックツアー 第4部

日本Symfonyユーザ会にて日本語ドキュメントが公開されています。そちらを参考にしてください。
アーキテクチャ | Symfony2日本語ドキュメント
http://docs.symfony.gr.jp/symfony2/quick_tour/the_architecture.html
日本語訳(下書き):
4. The Architecture — Documentation
http://docs.symfony-reloaded.org/quick_tour/the_architecture.html

4. アーキテクチャ

君はヒーローだ! 最初から第3部までを読み終えても、まだ読み続けているなんて、誰が予想したでしょうか? 君の努力はすぐに報われるでしょう。 最初から第3部までは、あまり深くフレームワークの構造を見てきませんでした。 実のところ、Symfony2 は他のフレームワークとは大きく異なります。それではアーキテクチャの世界に飛び込みましょう。

4.1. ディレクトリ構造

Symfony2 アプリケーションのディレクトリ構造にはかなりの柔軟性がありますが、sandbox のディレクトリ構造が、Symfony2 アプリケーションで推奨する一般的な構造を反映しています:

  • app/: アプリケーション構成。
  • src/: プロジェクトの PHP コード。
  • vendor/: サードパーティ製の依存関係。
  • web/: Web の root ディレクトリ。

4.1.1. Web ディレクトリ

Web の root ディレクトリは、イメージ、スタイルシート、および JavaScript ファイルのような静的ファイルをすべて公開するためのホームです。 フロントコントローラのある場所でもあります:

// web/app.php
require_once __DIR__.'/../app/bootstrap.php';
require_once __DIR__.'/../app/AppKernel.php';

use Symfony\Component\HttpFoundation\Request;

$kernel = new AppKernel('prod', false);
$kernel->handle(Request::createFromGlobals())->send();

カーネルは最初に bootstrap.php ファイルの読み込みを必要とします。 bootstrap.php は、フレームワークのブート、およびオートローダーの登録に用います (後述)。

どのフロントコントローラであっても、アプリケーションをブートするため、app.php のようにカーネルクラス (AppKernel) を使います。

4.1.2. アプリケーションディレクトリ

AppKernel クラスは、アプリケーション構成の中で主要なエントリーポイントとなります。 それ自体は、app/ ディレクトリに格納されています。

このクラスは、3 つのメソッドを実装する必要があります:

  • registerRootDir(): コンフィギュレーションの root ディレクトリを返す (訳注: カーネルクラスのルートとなるディレクトリのこと)。
  • registerBundles(): アプリケーションを実行するのに必要となる全バンドルの配列を返す (Sensio\HelloBundle\HelloBundle へのリファレンスに注意してください)。
  • registerContainerConfiguration(): コンフィギュレーションをロードする (詳細は後述します)。

フレームワークの柔軟性をより良く理解するために、これらのメソッドのデフォルト実装を見てください。

PHP のオートローディングは、autoload.php を介して設定することができます:

// app/autoload.php
use Symfony\Component\ClassLoader\UniversalClassLoader;

$loader = new UniversalClassLoader();
$loader->registerNamespaces(array(
    'Symfony'                        => __DIR__.'/../vendor/symfony/src',
    'Sensio'                         => __DIR__.'/../src',
    'Doctrine\\Common\\DataFixtures' => __DIR__.'/../vendor/doctrine-data-fixtures/lib',
    'Doctrine\\Common'               => __DIR__.'/../vendor/doctrine-common/lib',
    'Doctrine\\DBAL\\Migrations'     => __DIR__.'/../vendor/doctrine-migrations/lib',
    'Doctrine\\MongoDB'              => __DIR__.'/../vendor/doctrine-mongodb/lib',
    'Doctrine\\ODM\\MongoDB'         => __DIR__.'/../vendor/doctrine-mongodb-odm/lib',
    'Doctrine\\DBAL'                 => __DIR__.'/../vendor/doctrine-dbal/lib',
    'Doctrine'                       => __DIR__.'/../vendor/doctrine/lib',
    'Zend'                           => __DIR__.'/../vendor/zend/library',
));
$loader->registerPrefixes(array(
    'Twig_Extensions_' => __DIR__.'/../vendor/twig-extensions/lib',
    'Twig_'            => __DIR__.'/../vendor/twig/lib',
    'Swift_'           => __DIR__.'/../vendor/swiftmailer/lib/classes',
));
$loader->register();

Symfony2 の中で UniversalClassLoader が、PHP 5.3 の名前空間による相互運用性の技術基準、あるいは PEAR のクラス命名規則を顧慮する、ファイルのオートロードに使われています。 ここで、すべての依存関係は、vendor/ ディレクトリ以下に格納されていることが確認できると思いますが、これは単なる慣習です。 それらは、グローバルなサーバ上や、ローカルなプロジェクトの、どこにでも格納することができます。

4.2. バンドルシステム

本節では、Symfony2 の最も強力な機能の 1 つである、バンドルシステムを紹介します。

バンドルとは、他のソフトウエアでいうところのプラグインのようなものです。 では、なぜバンドルと呼び、プラグインと呼ばないのでしょうか? なぜなら、Symfony2 では、コアフレームワークの機能から、あなたがアプリケーションに記述するコードまでのすべてがバンドルだからです。 Symfony2 において、バンドルはファーストクラスオブジェクト (first-class citizens) に属します。 これにより、サードパーティ製バンドルにパッケージ化されたビルド済みの機能を使うため、もしくは、自作のバンドルを配布するための、柔軟性を提供します。 さらに、希望する方法で最適化するために、アプリケーションでどの機能を有効にするのかといった精選を簡単にしてくれます。

AppKernel クラスの registerBundles() メソッドで定義された通りに、アプリケーションはバンドルで構成されています:

// app/AppKernel.php
public function registerBundles()
{
    $bundles = array(
        new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
        new Symfony\Bundle\TwigBundle\TwigBundle(),

        // サードパーティ製のバンドルを有効にする
        new Symfony\Bundle\ZendBundle\ZendBundle(),
        new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
        new Symfony\Bundle\DoctrineBundle\DoctrineBundle(),
        //new Symfony\Bundle\DoctrineMigrationsBundle\DoctrineMigrationsBundle(),
        //new Symfony\Bundle\DoctrineMongoDBBundle\DoctrineMongoDBBundle(),

        // 自分のバンドルを登録する
        new Sensio\HelloBundle\HelloBundle(),
    );

    if ($this->isDebug()) {
        $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
    }

    return $bundles;
}

カーネルは、既に述べた HelloBundle に加えて、FrameworkBundleTwigBundleZendBundleSwiftmailerBundle、および DoctrineBundle も有効にすることに注目してください。 それらはすべて、コアフレームワークの一部です。

各バンドルは、YAML、XML、または PHP で記述された設定ファイルによってカスタマイズすることができます。 次のデフォルト設定を見てください:

# app/config/config.yml
framework:
    charset:       UTF-8
    error_handler: null
    csrf_protection:
        enabled: true
        secret: xxxxxxxxxx
    router:        { resource: "%kernel.root_dir%/config/routing.yml" }
    validation:    { enabled: true, annotations: true }
    templating:    { engines: ['twig'] } #assets_version: SomeVersionScheme
    session:
        default_locale: en
        lifetime:       3600
        auto_start:     true

# Twig 用の設定
twig:
    debug:            %kernel.debug%
    strict_variables: %kernel.debug%

## Doctrine 用の設定
#doctrine:
#   dbal:
#       dbname:   xxxxxxxx
#       user:     xxxxxxxx
#       password: ~
#       logging:  %kernel.debug%
#   orm:
#       auto_generate_proxy_classes: %kernel.debug%
#       mappings:
#           HelloBundle: ~

## Swiftmailer 用の設定
#swiftmailer:
#    transport:  smtp
#    encryption: ssl
#    auth_mode:  login
#    host:       smtp.gmail.com
#    username:   xxxxxxxx
#    password:   xxxxxxxx
<!-- app/config/config.xml -->
<framework:config charset="UTF-8" error-handler="null" cache-warmer="false">
    <framework:router resource="%kernel.root_dir%/config/routing.xml" cache-warmer="true" />
    <framework:validation enabled="true" annotations="true" />
    <framework:session default-locale="en" lifetime="3600" auto-start="true" />
    <framework:templating assets-version="SomeVersionScheme" cache-warmer="true">
        <framework:engine id="twig" />
    </framework:templating>
    <framework:csrf-protection enabled="true" secret="xxxxxxxxxx" />
</framework:config>

<!-- Twig 用の設定 -->
<twig:config debug="%kernel.debug%" strict-variables="%kernel.debug%" cache-warmer="true" />

<!-- Doctrine 用の設定 -->
<!--
<doctrine:config>
    <doctrine:dbal dbname="xxxxxxxx" user="xxxxxxxx" password="" logging="%kernel.debug%" />
    <doctrine:orm auto-generate-proxy-classes="%kernel.debug%">
        <doctrine:mappings>
            <doctrine:mapping name="HelloBundle" />
        </doctrine:mappings>
    </doctrine:orm>
</doctrine:config>
-->

<!-- Swiftmailer 用の設定 -->
<!--
<swiftmailer:config
    transport="smtp"
    encryption="ssl"
    auth-mode="login"
    host="smtp.gmail.com"
    username="xxxxxxxx"
    password="xxxxxxxx" />
-->
// app/config/config.php
$container->loadFromExtension('framework', array(
    'charset'         => 'UTF-8',
    'error_handler'   => null,
    'csrf-protection' => array('enabled' => true, 'secret' => 'xxxxxxxxxx'),
    'router'          => array('resource' => '%kernel.root_dir%/config/routing.php'),
    'validation'      => array('enabled' => true, 'annotations' => true),
    'templating'      => array(
        'engines' => array('twig'),
        #'assets_version' => "SomeVersionScheme",
    ),
    'session' => array(
        'default_locale' => "en",
        'lifetime'       => "3600",
        'auto_start'     => true,
    ),
));

// Twig 用の設定
$container->loadFromExtension('twig', array(
    'debug'            => '%kernel.debug%',
    'strict_variables' => '%kernel.debug%',
));

// Doctrine 用の設定
/*
$container->loadFromExtension('doctrine', array(
    'dbal' => array(
        'dbname'   => 'xxxxxxxx',
        'user'     => 'xxxxxxxx',
        'password' => '',
        'logging'  => '%kernel.debug%',
    ),
    'orm' => array(
        'auto_generate_proxy_classes' => '%kernel.debug%',
        'mappings' => array('HelloBundle' => array()),
    ),
));
*/

// Swiftmailer 用の設定
/*
$container->loadFromExtension('swiftmailer', array(
    'transport'  => "smtp",
    'encryption' => "ssl",
    'auth_mode'  => "login",
    'host'       => "smtp.gmail.com",
    'username'   => "xxxxxxxx",
    'password'   => "xxxxxxxx",
));
*/

framework のような各エントリには、バンドルの設定を定義します。

それぞれの環境では、特定の設定ファイルを提供することで、デフォルトの設定を上書きすることができます:

# app/config/config_dev.yml
imports:
    - { resource: config.yml }

framework:
    router:   { resource: "%kernel.root_dir%/config/routing_dev.yml" }
    profiler: { only_exceptions: false }

web_profiler:
    toolbar: true
    intercept_redirects: true

zend:
    logger:
        priority: debug
        path:     %kernel.logs_dir%/%kernel.environment%.log
<!-- app/config/config_dev.xml -->
<imports>
    <import resource="config.xml" />
</imports>

<framework:config>
    <framework:router resource="%kernel.root_dir%/config/routing_dev.xml" />
    <framework:profiler only-exceptions="false" />
</framework:config>

<webprofiler:config
    toolbar="true"
    intercept-redirects="true"
/>

<zend:config>
    <zend:logger priority="info" path="%kernel.logs_dir%/%kernel.environment%.log" />
</zend:config>
// app/config/config_dev.php
$loader->import('config.php');

$container->loadFromExtension('framework', array(
    'router'   => array('resource' => '%kernel.root_dir%/config/routing_dev.php'),
    'profiler' => array('only-exceptions' => false),
));

$container->loadFromExtension('web_profiler', array(
    'toolbar' => true,
    'intercept-redirects' => true,
));

$container->loadFromExtension('zend', array(
    'logger' => array(
        'priority' => 'info',
        'path'     => '%kernel.logs_dir%/%kernel.environment%.log',
    ),
));

Symfony2 がなぜそれほど柔軟であるか、わかりましたか? アプリケーション間で共有するバンドルは、ローカルまたはグローバルを選択し、格納します。

4.3. ベンダーの使用

アプリケーションがサードパーティ製のライブラリに依存する可能性はあります。 それらは、src/vendor/ ディレクトリに格納してください。 このディレクトリには、Symfony2 ライブラリ、SwiftMailer ライブラリ、Doctrine ORM、Twig テンプレートシステム、そして、選りすぐりの Zend Framework クラスが既に含まれています。

4.4. キャッシュとログ

Symfony2 はおそらく、最も速いフルスタックフレームワークの 1 つです。 でも、どうすればリクエストごとに何十もの YAML または XML ファイルを解析、解釈しても、高速にできるのでしょう? これは一部には、Symfony2 のキャッシュシステムによるものです。 アプリケーション構成は、一番最初のリクエスト時にだけ解析されて、cache/ アプリケーションディレクトリに格納されるプレーン PHP コードにコンパイルされます。 開発環境では、Symfony2 はファイルを変更する際、キャッシュを賢く書き出します。 しかし、本番環境では、コードを更新、または構成を変更する際、キャッシュをクリアすることはあなたの役割となります。

Web アプリケーションを開発する際に、さまざまな点でうまくいかなくなることがあります。 リクエストのすべてを logs/ アプリケーションディレクトリのログファイルによって知ることができ、ある問題を迅速に修正するのに役立ちます。

4.5. コマンドラインインタフェース

各アプリケーションには、あなたのアプリケーションを維持するのに役立つコマンドラインインタフェースツール (console) が付属しています。 退屈で反復的な作業を自動化することにより、生産性を向上させるコマンドを提供します。

その機能の詳細については、引数を指定しないで実行してください:

$ php app/console

--help オプションは、コマンドの使用方法を知る手助けになります:

$ php app/console router:debug --help

4.6. 最後に

クレイジーって言われてもいいが、この第 4 部を読んだ後に、物事をうまく運び、Symfony2 で仕事することの快適さを体感してください。 Symfony2 は、独自のやり方を改めるために、何もかもしてくれます。 そんなわけで、ふさわしいと思うようなリネームやディレクトリの移動を自由にしてください。

さて、これでクイックツアーは終わりです。 Symfony2 マスターになるためには、テストからメールを送信するまでの、たくさんのことを学ぶ必要がまだまだあります。 さあ、トピックを掘り下げる準備はできていますか? これより先は - 公式ガイドページに移動し、好きなトピックを選んでください。

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

0 コメント: