前回 Post エンティティと Comment エンティティの関連付けを行いました。 ですので、今回は Post の表示画面に Comment の入力フォームを作ってみましょう。

テンプレートエンジンは Twig

機能的にはSmarty3に似ています。 Twigの開発元はSymfony2と同じSensioLabです。 テンプレートがコンパイルされて、ネイティブなPHPクラスに変換される部分が大きな特徴です。

タイプ量はかなり削減できます。

{# コメント #}

{# 出力: <?php echo $var?> と同じ #}
{{ var }}

{# フィルタ(変換)<?php echo htmlspecialchars($var, ENT_QUOTES, 'utf-8') ?> と同じ #}
{{ var|escape }}

CommentController を console から生成

$ php app/console generate:controller

------------------------------------------------
  Welcome to the Symfony2 controller generator  
------------------------------------------------


Every page, and even sections of a page, are rendered by a controller.
This command helps you generate them easily.

First, you need to give the controller name you want to generate.
You must use the shortcut notation like AcmeBlogBundle:Post

Controller name: QuartetBlogBundle:Comment

Determine the format to use for the routing.

Routing format (php, xml, yml, annotation) [annotation]: 

Determine the format to use for templating.

Template format (twig, php) [twig]: 

Instead of starting with a blank controller, you can add some actions now. An action
is a PHP function or method that executes, for example, when a given route is matched.
Actions should be suffixed by Action.


New action name (press <return> to stop adding actions): createAction
Action route [/create]: 
Templatename (optional) [QuartetBlogBundle:Comment:create.html.twig]: 

New action name (press <return> to stop adding actions): 

-----------------------------
  Summary before generation  
-----------------------------

You are going to generate a "QuartetBlogBundle:Comment" controller
using the "annotation" format for the routing and the "twig" format
for templating
Do you confirm generation [yes]? 

-------------------------
  Controller generation  
-------------------------

Generating the bundle code: OK

-----------------------------------------------
  You can now start using the generated code!  
-----------------------------------------------

$

これで CommentController.phpcreateAction が生成されます。

Comment フォームを consoleから生成

$ php app/console doctrine:generate:form QuartetBlogBundle:Comment
The new CommentType.php class file has been created under /usr/local/var/www/symfony-blog-tuts/src/Quartet/Bundle/BlogBundle/Form/CommentType.php.
$

これで CommentType.php が生成されます。

PostController::showActionにCommentTypeを表示するようにします。

記事表示画面の下にコメント欄がある典型的な感じです。

CommentType からフォームのViewを作ります。

下記の処理を追加します。

  1. Formオブジェクトを作成
  2. FormViewオブジェクトに変換
  3. レスポンスに追加する
<?php
//PostController

// ↓2行追記
use Quartet\Bundle\BlogBundle\Entity\Comment;
use Quartet\Bundle\BlogBundle\Form\CommentType;

/**
 * Finds and displays a Post entity.
 *
 * @Route("/{id}", name="post_show")
 * @Method("GET")
 * @Template()
 */
public function showAction($id)
{
    $em = $this->getDoctrine()->getManager();

    $entity = $em->getRepository('QuartetBlogBundle:Post')->find($id);

    if (!$entity) {
        throw $this->createNotFoundException('Unable to find Post entity.');
    }

    $deleteForm = $this->createDeleteForm($id);

    // ↓追記
    $commentForm = $this->createForm(new CommentType(), new Comment());

    return array(
        'entity'      => $entity,
        'delete_form' => $deleteForm->createView(),
        // ↓追記
        'comment_form' => $commentForm->createView(),
    );
}

追加するとこんな感じになると思います。

FormをViewにレンダリング

CommentType を修正

<?php
// CommentType
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        //->add('post') コメントする際に投稿を選ぶ事はないので削除
        ->add('content')
    ;
}

次に BlogBundle/Resources/views/Post/show.html.twig を開いてViewを編集します。 form_widget()PostController から渡した FormView オブジェクトを渡すといい感じにフォームを表示してくれます。

// BlogBundle/Resources/views/Post/show.html.twig
<form action="" method="post">
    {{ form_widget(comment_form) }}
    <input type="submit" value="送信" />
</form>

他にも方法は色々あります。

{# formタグを関数で記述する方法 #}
{{ form_start(comment_form, {'action': path('$routingName'), method: 'POST'}) }}
{{ form_widget(comment_form) }}
    <input type="submit" value="送信" />
{{ form_end(comment_form) }}
{# 全てを1つの関数で記述する方法 #}

{{ form(comment_form }}
フォームのレンダリングに関しては[Rendering a Form in a Template Forms (current) - Symfony](http://symfony.com/doc/current/book/#rendering-a-form-in-a-template)に詳しいドキュメントがあります。

URLを<form>に設定

Symfony2はリバースルーティングする際に ルーティングの名前 を利用します。

補足: ルーティング ブラウザがリクエストしたURLに対して、どのアクションを実行するか?という設定の事。

補足2: リバースルーティング ルーティングの逆の事(アクションを指定してURLに変換する。) ユーザーにURLを提供する為に、プログラム上にURLを書くのはナンセンスです。 ([URL → アクション]の定義をルーティングで定義しているから、アクションを指定すればURLぐらい作れるだろう。というお話。)

今回はルーティングの設定をAnnotationで行っているのでルーティングの設定は、 各コントローラーのメソッド に書いてあります。

<?php
// CommentController.php
class CommentController extends Controller
{
    /**
     * @Route("/create") <- これ
     * @Template()
     */
    public function createAction()
    {
    }
}

デフォルトのままだとルーティング名がないので設定します。 ついでに色々ないので設定します。

  • どの Post のコメントなのか分からないので、post_id パラメーター
  • コントローラーに プレフィックスルーティング
<?php
// CommentController.php

use Symfony\Component\HttpFoundation\Response;

class CommentController extends Controller
{
    /**
     * @Route("/create/{post_id}", name="comment_create")
     * @Template()
     */
    public function createAction($post_id)
    {
        return new Response("PostId:{$post_id}");
    }
}

ルーティング名を設定したのでフォームに記入

// Post/show.html.twig
{# path(~) の部分です。パラメーターを忘れた時は例外が出るのでミスはすぐに分かります。 #}
{{ form_start(comment_form, {'action': path('comment_create', { post_id: entity.id }), method: 'POST'}) }}
{{ form_widget(comment_form) }}
    <input type="submit" value="送信" />
{{ form_end(comment_form) }}

これで、記事ページにコメント欄が表示されるようになります。

補足: コンソール php app/console debug:router で全てのルーティングを確認できます。

表示してみましょう

http://localhost/sf-blog-tuts/web/app_dev.php/post/1

767a4a7e-fa6c-1b01-903c-24355aa452cf-1024x572

コメント欄が表示されました!

コメントを入力して送信してみると、Post.id が渡せている事が分かります。

abb6e0d9-a214-f958-8e4d-1e14a0a4a3c3-1024x572