Symfony2 バンドルの作成

Symfony2では後にも先にもbundleの作成にはじまりbubdleの作成で終わると言っても過言でありません。バンドルとは何であるかはいろんなサイトさんですでに紹介済みなのでここであまり詳しく触れませんが、Symfony2フレームワークの最小単位のアプリケーションだと思っていればほぼほぼ間違いないです。というのもこのバンドルの作成と設定でもって機能ごとの分離といわゆるMVCの一連の動作を整理することができるからです。たった1枚のページを作成するためにもこのバンドルが必要で、このバンドルによって制御します。勿論フレームワークなのでたった1ページを作成するのみで実際にバンドル作成と設定で行う基本的な項目を見てみます。
http://docs.symfony.gr.jp/symfony2/book/page_creation.html

  1. バンドルの作成
  2. ルーティングの設定(仮想パスの設定)
  3. コントローラーの設定
  4. テンプレートの作成

という内容になります。


1. バンドルを作成する


バンドルはここではわかりやすい感じで、Dummy/TestBundleで作成します。Dummyはネームスペースとして/src/Dummyとしてディレクトリが作成されます。機能に応じたカテゴライズや分類に利用します。またTestBundleはバンドル名になりますが、xxxxBundleという名前にしないとダメです。こういうルールになっております。ルールに従いながら自分が整理しやすい名前にするのがよいです。またこの作成したバンドルはSymfony2のプロファイラーというデバック機能で確認することができます。(このプロファイラーもバンドルで作成されているアプリの1つになっています。)
バンドルは以下のコマンドで作成します。
$ php app/console generate:bundle --namespace=Dummy/TestBundle --format=yml
Symfony2のルート・ディレクトリに移動してこのコマンドを使うのがお作法で、これで問題なく機能します。またバンドル作成時には便利なダイアログが出てきて設定項目を変更することが可能ですが、ここでは省略してすべてをデフォルトの機能で設定します。(よっぽど上級者ではない限りデフォルトで十分です。)
$ php app/console generate:bundle --namespace=Dummy/TestBundle --format=yml
Welcome to the Symfony2 bundle generator
In your code, a bundle is often referenced by its name. It can be the
concatenation of all namespace parts but it's really up to you to come
up with a unique name (a good practice is to start with the vendor name).
Based on the namespace, we suggest DummyTestBundle.

Bundle name [DummyTestBundle]:(※省略してEnter)

The bundle can be generated anywhere. The suggested default directory uses
the standard conventions.

Target directory [/home/system/www/symfony2/src]:(※省略してEnter)

To help you get started faster, the command can generate some
code snippets for you.

Do you want to generate the whole directory structure [no]? (※省略してEnter)

Summary before generation
You are going to generate a "Dummy\TestBundle\DummyTestBundle" bundle
in "/home/system/www/symfony2/src/" using the "yml" format.

Do you confirm generation [yes]? (※省略してEnter)

Bundle generation
Generating the bundle code: OK
Checking that the bundle is autoloaded: OK
Confirm automatic update of your Kernel [yes]? (※省略してEnter)
Enabling the bundle inside the Kernel: OK
Confirm automatic update of the Routing [yes]? (※省略してEnter)
Importing the bundle routing resource: OK

バンドルの作成はこれで終わり。
作成されたバンドルのディレクトリ構造は以下のようになっています。
src/Dummy
└── TestBundle
├── Controller
│   └── DefaultController.php
├── DependencyInjection
│   ├── Configuration.php
│   └── DummyTestExtension.php
├── DummyTestBundle.php
├── Resources
│   ├── config
│   │   ├── routing.yml
│   │   └── services.yml
│   └── views
│   └── Default
│   └── index.html.twig
└── Tests
└── Controller
└── DefaultControllerTest.php

バンドルの削除
バンドルがもう使われなくなったとか間違って作成してしまったという際にはバンドルを削除します。バンドルの削除は、src以下のバンドル自体のファイル郡の削除とカーネルに登録したバンドルリスト(みたいなもの)を削除します。上記で作成したバンドルを削除するときは、src/Dummy以下すべてとapp/AppKernel.phpに書かれている以下の行を削除します。これはバンドルを作成するときに自動的に追加されている部分になります。が、削除するときには自動的に削除してくれるコマンドがないので手動で削除所します。
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
new Symfony\Bundle\AsseticBundle\AsseticBundle(),
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new Dummy\TestBundle\TestTestBundle(), ←これ削除!
);

で、もう一つ。app/config/routing.ymlに登録されている該当バンドルを削除します。
dummy_test_test:
resource: "@TestTestBundle/Resources/config/routing.yml"
prefix: /

これで物理的な削除は終わりですが、たぶんこれで他のページなんかにアクセスするとエラーが出ます。というのは設定されているすべてのパラメーターはキャッシュされているので、最後にキャッシュを削除しないとダメです。またSymfony2ではキャッシュファイルの物理削除はあんまりよくないです。なので、コマンドを使いましょう。
$ php app/console cache:clear --no-warmup


2.ルーティング


ルーティングはバンドルが実際にWEBページとして機能するためのパスを設定します。Symfony2では、phpファイルを置いたパスがアクセスパスにはなりません。バンドル内で設定したパス(仮想パス)がそのページのアクセスパスになります。つまりディレクトリ構造やファイルパスとは全く関係なしにSymfony2のフレームワークが全体として機能してアプリを動かすという構造になっているわけです。フレームワークに慣れている人だったらすぐにわかるのですが、あんまり慣れていない人はいろいろやって慣れるしかないですね。
ルーティングの設定は、src/Dummy/Resources/config/routing.ymlで行います。
dummy_test_homepage:
pattern: /hello/{name}
defaults: { _controller: DummyTestBundle:Default:index }

さて、デフォルトではこのようになっています。この設定は、web/app_dev.php/hello/hogeでアクセスするとページが表示されるという設定になっています。試しに、
http://example.com/[Symfony2をインストールしたところ]/web/app_dev.php/hello/hoge
にアクセスしてみてください。「Hello hoge!」と表示される筈です。この場合、helloという仮想パスにhogeというパラメーターを与えて表示するという設定になっているわけです。このhogeの部分は{name}によって定義されています。
このデフォルトの仮想パスを、web/app_dev.php/dummy/test/hogeでアクセスできるように変更してみます。pattern:のパスを/hello/{name}から/dummy/test/{name}に書き換えて保存します。
dummy_test_homepage:
pattern: /dummy/test/{name}
defaults: { _controller: DummyTestBundle:Default:index }

こうすると仮想パスが切り替わって、設定したパスでアクセスが可能になります。
http://example.com/[Symfony2をインストールしたところ]/web/app_dev.php/dummy/test/hoge
このルーティング(仮想パス)はSymfony2をインストールしたディレクトリの配下だったらどこにでも設定が可能です。これでページ自体のアクセスが可能になりました。
余談ですが、ここでは練習のためにweb/app_dev.phpにアクセスしています。しかし実際にデプロイした際のアクセス先は、web/app.phpになります。このapp.phpはhttpアクセス時の中心的な役割を演じていて、web/以下にリダイレクトして「web/仮想パス」という美しいパスに切り替わります。これは後々わかるようになるので、ここではapp_dev.phpで制作を続けていて全然問題ありません。


3. コントローラーの設定


コントローラーは、データを取得しそれらに何らかの加工を加えテンプレートに送る作業をする場所です。いわばフレームワークの中核になる部分です。ここではデータの取得(特にデータベースなどからの取得)ではなくサンプルとなるデータをコントローラーに直接書きます。コントローラーへデータを呼び出す方法は後述します。
さてバンドルを作成した時点でデフォルトのコントローラーがすでに作成されています。
src/Dummy/TestBundle/Controller/DefaultController.php
ここに作成されたコントローラーはデフォルトで機能するようにすでに初期設定がされております。中身を見ると以下のようになっています。このコントローラーが先ほどのルーティング(仮想パス)と結びついて機能しているわけですが、このコントローラーの定義もルーティングの設定と同様に、
src/Dummy/Resources/config/routing.yml
にかかれています。こんな感じになっています。
defaults: { _controller: DummyTestBundle:Default:index }
DummyTestBundle:Default:indexはコントローラーの理論名(指し示している名前)でこのコントローラーの実際のファイルはDummy/TestBundle/Controller/DefaultController.phpとなっていて、さらにその中のクラスのindexActionにマッピングされています。
DummyTestBundle:Default:index
src/Dummy/TestBundle/Controller/DefaultController.php → class indexAction{}

というわけで、自分でコントローラーを作成する際には理論名とそれにマッピングするファイル名を変えてあげればいいです。例えば、
defaults: { _controller: DummyTestBundle:Welcome:index }という理論名の場合は、src/Dummy/TestBundle/Controller/WelcomeController.phpというコントローラーにマッピングされ、クラス内のindexActionが実行されることになります。(実際にコントローラーのマッピングを変更した場合は、app/cache/dev以下のキャッシュファイルを削除する必要があります。これを削除しないとエラーになります。(また削除する際にはコマンドも使えます。php app/console cache:clear --env=dev --no-debug)これらはapache権限で作成されるファイルなのでグループとかそういうの設定していないとRootじゃないと削除できないかもです。その際はパーミッションとグループの適切な設定を)
ここでコントローラーの中身を見てみます。コントローラーは最初の段階ではシンプルなクラスファイルでメソットはindexActionのみです。メソッドには$nameというパラメータを渡していますが、これは先の仮想パスで指定した最後の文字列
http://example.com/[Symfony2をインストールしたところ]/web/app_dev.php/dummy/test/hoge
という部分で、この文字列がコントローラーに何かしらの引数を与えて様々な機能を与えることができます。与えられた$nameはコントローラー内で何らかの処理をしてテンプレートに引き渡すことができます。つまり、httpリクエスト→コントローラー→テンプレートという風に情報が流れてゆくことになっているわけです。コントローラーではデータを貰い受け何らかの処理をしてテンプレートに引き渡す作業をしているので、どのテンプレートに引き渡す(どのテンプレートを使う)かの設定も行います。
namespace Dummy\TestBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
{
public function indexAction($name)
{
return $this->render('DummyTestBundle:Default:index.html.twig', array('name' => $name));
}
}

indexActionで最終的にreturnで返す値はテンプレートに描画する値になります。ここでは$this->renderオブジェクトにテンプレートの理論名と配列を渡しています。ここでも理論名と実際のテンプレートのパスがシンクロしています。パスやテンプレート名の変更の際はこの理論名とマッピング先のファイル名またはディレクトリ名を変更します。
DummyTestBundle:Default:index.html.twig
src/Dummy/TestBundle/Resources/views/Default/index.html.twig


4. テンプレートの設定


テンプレートはSmartyとかいうものじゃなくてtwigです。Smartyはphpそのままでええじゃないかというエンジンになっているのでtwigでよかったです。しかしSymfony2では最終的な描画方法はtwigかプレーンのphpかのどちらかを選べます。phpにしてみると非常に楽なのですが、開発を重ねると皆が皆、勝手にincludeしちゃったり抽象クラスにそれ相応のものがあるのに自分でやたらと長いコードを実装しちゃったりで、これまた厄介なことになってくるのでtwigにしておいた方が無難です。好みの問題ではありますが、フレームワークとして機能させるためにはtwigを使うのがよいです。
さて、テンプレートはコントローラーで指定したものになります。バンドル作成時に自動的に作成されたデフォルトのテンプレートを開いてみると、
Hello {{ name }}!
というシンプルなものになっています。これが最終的に描画されたhtmlページの内容になります。引数でわたってきた$nameが{{ name }}として描画されています。このテンプレートには自由にHTMLを書くことができます。ここまで来るとデザイナーさんやHTMLのコーダーさんに渡して自由にやってもらうがよいです。$this->renderオブジェクトに渡されたものが確実にこのテンプレートにやってくるので後はシステムの人間の仕事ではないかもしれません。
twigは元々はSymfony2とは独立したものです。ですので、twigの使い方は個別に学んだ方が妥当ですが、ここでは簡単にコントローラーからtwigに値を渡す方法だけ触れておきます。
return $this->render('DummyTestBundle:Default:index.html.twig', array('name' => $name));
で渡す値の第二パラメータは連想配列になっています。この値は指定するだけでそのままテンプレートで扱うことができます。array('name' => $name)は{{name}}として扱えるというわけです。ですからここには任意の変数を指定することができます。
array('name' => $name, 'name1' => $name1, 'name2' => $name2,)は、そのまま{{name}}{{name1}}{{name2}}として値を呼び出すことができます。
また余談ですが、仮想パスにGETの値を付与することもできます。
http://sys.omnioo.com/symfony2/web/app_dev.php/dummy/test/hoge?mode=testvalue
とアクセスするとコントローラー内で$_GET['mode']として扱うことができます。当然testvalueという文字列が格納されます。