LoginSignup
0
0

More than 5 years have passed since last update.

Symfonyでタスク管理アプリ作ってみた(フォーム編)

Last updated at Posted at 2017-01-23

エンティティを作ったら、フォームの作成です。なんだかんだで、ウェブサイトの開発ではフォームの取扱が大きいです。

フレームワークの勉強のため、Symfony3でタスク管理アプリ作ってみたのパート3です。

Symfonyでのフォーム取扱

Symfonyでフォームの取扱はFormsを利用します。

エンティティからセッターを削除したので、エンティティをSymfonyのフォームに使えなくなってしまいました。そこで、フォーム用のDTOクラスを作成しました。

フォームだけのために、エンティティと同じようなクラスをわざわざ作るのは面倒、というか妙な気がします。セッター削除したのは失敗だったかと思ったのですが、おもったより簡単だったのと、フォームだけで利用するアノテーションがあるので、結果的にはエンティティがスッキリするのではと思ってます。

フォーム用DTO

フォームDTOのTaskDTOクラスです。

<?php
namespace AppBundle\Controller\CrudService;

use AppBundle\Entity\EntityTrait;
use Symfony\Component\Validator\Constraints as Assert;

class TaskDTO
{
    use EntityTrait;

    /**
     * @var string
     * @Assert\NotBlank()
     */
    public $title;

    /**
     * @var string
     */
    public $details;

    /**
     * @var \DateTime
     * @Assert\Type("\DateTime")
     */
    public $doneBy;
}

フォームから登録する値はパブリックのプロパティとして定義しました。フォーム内でしか使わないDTOならこれで十分じゃないか、という話をどこかで読んだので採用しました。今のところ問題なし。

ここでもアノテーションが活躍します。タスクのタイトルは必須ということで@Assert\NotBlank()アノテーションを使って指定しています。

フォームオブジェクトの作成

Symfonyでのフォームオブジェクトの作成例です。Controller内であれば、$this->createFormBuilder()でフォーム作成を始められます。また、同じフォームを2度利用するので、別メソッドに切り分けておきます。

private function getCreateForm()
{
    $task = new TaskDTO();
    return $this->createFormBuilder($task)
        ->add('title', TextType::class, ['label' => 'Task name', 'required' => true])
        ->add('doneBy', DateType::class, ['widget' => 'single_text', 'required' => false, 'label' => 'done by'])
        ->add('details', TextareaType::class, ['required' => false, 'label' => 'details'])
        ->getForm();
}

ここでのrequiredパラメターですが、あくまでHTMLのJavaScript上でチェックするだけなので注意が必要です。サーバー側でチェックするには(例えば)先のフォーム用DTOでアノテーションを使う必要があります。

フォームの描画

このメソッドで構築した$formをtwigテンプレートに渡して、フォームを描画します。

return $this->render('task/project/create.html.twig', [
    'form' => $this->getCreateForm(),
]);

そしてtwigテンプレート内で、$formオブジェクトを描画します。

    {{ form_start(form) }}

    {{ form_errors(form) }}

    <div class="form-group">
        {{ form_label(form.title) }}
        {{ form_widget(form.title, {"attr": "placeholder":"task name"}}) }}
        {{ form_errors(form.title) }}
    </div>
    ...

bootstrap3レイアウトを利用

今回はBootstrap3を使っているので、フォームの表現をデフォルトで変更してしまいます。app/config/config.yml内のtwigセクションで次の設定を加えます。

# Twig Configuration
twig:
    form_themes:
        - 'bootstrap_3_layout.html.twig'

すると、Bootstrap3用にレンダリングされました。とても便利。

フォームデータの受取

フォームからサブミットされたデータで、タスクを登録します。まずSymfonyが作成するRequestオブジェクトを利用します。コードとしては、こんな感じになりました。

public function insertAction(Request $request): Response
{
    $form = $this->getCreateForm()
    $form = $form->handleRequest($request);
    if (!$form->isValid()) {
        return $this->render('task/project/create.html.twig', [
            'form' => $this->getCreateForm(),
        ]);
    }
    $dto  = $form->getData();
    $task = new Task($dto->toArray());
    $em   = $this->getDoctrine()->getManager();
    $em->persist($task);
    $em->flush();
}

Callbackの導入

ちょっと複雑なバリデーションを行う方法として、Callbackという機能がSymfonyにはあります。例えば、TaskのdoneByに過去の日付けを入れたくない、と言ったケースを考えて見ます。

先のTaskDTOにバリデーション用のメソッドを追加して、@Assert\Callback()とアノテートするだけ。これでエラーチェックを行うことができます。こんなコードになります。

class TaskDTO 
{

    /**
     * @param \DateTime $now
     */
    public function __construct(\DateTime $now = null)
    {
        $this->now = $now ? clone($now): null;
        if ($this->now) {
            $this->now->setTime(0,0,0);
        }
    }

    /**
     * @param ExecutionContextInterface $context
     * @Assert\Callback()
     */
    public function validateDoneByHasFutureDate(ExecutionContextInterface $context)
    {
        if ($this->doneBy && $this->now && $this->doneBy < $this->now) {
            $context->buildViolation('please select future date as done-by.')
                    ->atPath('doneBy')
                    ->addViolation();
        }
    }
}

アノテーションやバリデーションが入り込んでくると考えると、エンティティとフォーム用DTOを分けてよかった気がします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0