Symfony2でFormを作成する時はTwigテンプレートに直接書いてもいいんでしょうけど、Symfonyではコンポーネントを使うのがいいっぽいので、それに従ってFormを作る勉強をしました。ものすごくちゃんとしているFrameworkなので結構面倒くさいのですが、ものすごくちゃんとしているだけに結構感動的です。
Formは、エンティティーの作成、コントローラーでコンポーネントを呼んでFormのパーツをいろいろ準備、テンプレートへレンダリング、DBとの連携みたいな感じでそれぞれ機能が分かれています。でも繋がると結構わかりやすいです。
バンドルを作成する
php app/console generate:bundle --namespace=Acme/StoreBundle
こんな風に作っておきます。
エンティティーの作成
Formのパーツ(項目)は、classのプロパティーとして設定します。publicで設定した項目はどこででも出し入れできるのですが、protectで設定した項目はゲッターとセッターを通じて内部的にやり取りします。(決済のカード情報とかそういうものを扱うのがよいです。)Javaなんかをやっている人には結構おなじみのやり方ですが、ヘンテコPHPしか扱ってない人には比較的わけのわからない世界となっております。// src/Acme/StoreBundle/Entity/Product.php namespace Acme\StoreBundle\Entity; class Product { // Formのパーツ public $name; public $email; protected $telphone; public function getTelphone() { return $this->telphone; } public function setTelphone($telphone) { $this->price = $telphone; } }
ルーティングの設定
http://example.com/app_dev.php/store_product
(http://example.com/symfony/web/app_dev.php/store_product)
みたいなところでアクセスできるようにします。
#src/Acme/StoreBundle/Resources/config/routing.yml store_product: pattern: /store_product defaults: { _controller: AcmeStoreBundle:Default:index }
コントローラーでFormを組み立てる
ここがややこしい。まずはuseで最初に書いたエンティティーを呼び出します。use Acme\StoreBundle\Entity\Product;
それからここではPOSTで送信することを想定しているので、
use Symfony\Component\HttpFoundation\Request;
を呼び出します。これはSymfony2にもともとくっついているコンポーネントです。余談ではありますが、POSTとかGETとかはこのRequestで処理するみたいです。
Formを組み立てる最初の処理は、エンティティーをオブジェクトにして保持しておくことです。なので、エンティティーのProductをnewして、どかっと変数にぶち込んでおくことです。ここにガバっと入ってくるので、後からいろいろ使う準備をしておきます。
次にcreateFormBuilderに先ほどのエンティティーを丸ごと入力してFormを作成します。これにどんどんどんどんaddします。
この時いわゆるnameと型を指定します。
->add('name', 'text')
型はだいたい揃っていて、ドキュメントにその一覧があります。
http://docs.symfony.gr.jp/symfony2/book/forms.html#book-forms-type-reference
不足ないかと思います。
$this->createFormBuilder($product)…で作成されたFormは、$formに入ってきます。このオブジェクトをいろいろやることでformっぽいことがいろいろできるようになります。下記のコードでやっていることはリクエストがあったら、リクエストの中身をダンプ。リクエストがなかったらフォームをレンダリングして入力待ち。ということになります。
// src/Acme/StoreBundle/Controller/DefaultController.php namespace Acme\StoreBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Acme\StoreBundle\Entity\Product; use Symfony\Component\HttpFoundation\Request; class DefaultController extends Controller { public function indexAction(Request $request) { // Productオブジェクトを作成し、ダミーデータを設定する $product = new Product(); //$product->name = 'Test product'; //$product->setPrice('50.00'); $form = $this->createFormBuilder($product) ->add('name', 'text') ->add('email', 'text') ->add('telphone', 'text') ->getForm(); if ($request->getMethod() == 'POST') { $form->handleRequest($request); if ($form->isValid()) { // データベースへの保存など、何らかのアクションを実行する var_dump($request->request); exit; } } return $this->render('AcmeStoreBundle:Default:index.html.twig', array( 'form' => $form->createView(), )); } }$request->getMethod()でPOSTが見つかったらすなわち何らかの内容が送信されてきたことになるので、バリデーションとかDBにインサートとかデータの加工とかメールを飛ばすとかいろいろな処理をします。リクエストがない場合は、フォームをレンダリングしますが、createView()というプロパティーを使ってtwigに送り込んでいます。
Twigの設定(テンプレートの設定)
TwigでFormを描画するには、通常の変数を取り込んで表示するというやり方とはやや違う特殊な方法をとります。というのもcreateView()で送り込まれた値をそのまま全部取り込んでいるからです。Formのパーツ(inputやselect、textareaなどなど)は、{{ form_widget(form) }}という変数で丸ごと取り込んでいます。{# src/Acme/StoreBundle/Resources/views/Default/index.html.twig #} <form action="{{ path('store_product') }}" method="post" {{ form_enctype(form) }}> {{ form_widget(form) }} <input type="submit" /> </form>
これで表面上のデータのやりとりは出来た感じになります。
しかし自動的につく変なバリデーションとか、Formのinputにclassを付与したりといろいろやらなければならない細かいことが沢山ありますので、これもがんばってやってゆく所存です。
次回はFormから送信したデータをあれこれします。