BEAR.Sundayでコンタクトフォームを作ってみる⑤

BEAR.Sundayでコンタクトフォームを作ってみる④の続きです。

今までMVCで言うところの「コントローラ」に対応する「ページリソース」しか使ってなかったので、今日は「モデル」に対応する「アプリケーションリソース」も使ってみます。

なお、言うまでもないことですが、BEAR.SundayはそもそもMVCパターンではないフレームワークなので、「コントローラ」と「ページリソース」や「モデル」と「アプリケーションリソース」が全く同じものということではありません。

それでは、フォームに関する処理はアプリケーションリソースに移動します。

アプリケーションリソースの作成

アプリケーションリソースContact\Formを作成し、フォームの処理とメール送信のロジックを移動します。

src/Resource/App/Contact/Form.php

<?php
/**
 * Kenjis.Contact
 *
 * @author     Kenji Suzuki <https://github.com/kenjis>
 * @license    MIT License
 * @copyright  2014 Kenji Suzuki
 * @link       https://github.com/kenjis/Kenjis.Contact
 */

namespace Kenjis\Contact\Resource\App\Contact;

use BEAR\Resource\ResourceObject;
use BEAR\Resource\Code;
use Kenjis\Contact\Service\SwiftMailerFactory;
use Ray\Di\Di\Inject;

class Form extends ResourceObject
{
    private $mailer;

    /**
     * @Inject
     */
    public function __construct(SwiftMailerFactory $mailer)
    {
        $this->mailer = $mailer;
    }

    /**
     * @BEAR\Sunday\Annotation\Form
     */
    public function onGet()
    {
        return $this;
    }

    /**
     * @BEAR\Sunday\Annotation\Form
     */
    public function onPost($name, $email, $comment)
    {
        $this->sendmail($name, $email, $comment);

        $this['code'] = $this->code = Code::CREATED;
        $this['name']    = $name;
        $this['email']   = $email;
        $this['comment'] = $comment;

        return $this;
    }

    private function sendmail($name, $email, $comment)
    {
        $data = [
            'name'    => $name,
            'email'   => $email,
            'comment' => $comment,
        ];

        $mailer = $this->mailer->create();
        $mailer->setSubject('コンタクトフォーム')
            ->setFrom($data['email'], $data['name'])
            ->setTo('admin@example.org', '管理者')
            ->setTemplate('mailer/contact_form.twig', $data);

//        echo '<pre>'
//            . htmlspecialchars($mailer, ENT_QUOTES, 'UTF-8')
//            . '</pre>';

        $result = $mailer->send();
        return $result;
    }
}

対応するテンプレートも作成します。ページリソースのものをほぼそのまま移動するだけです。

src/Resource/App/Contact/Form.twig

<div id="contact_form">
    <h1>Contact Form</h1>
{% if code == 201 %}
    <p>
    Name: {{ name }}<br>
    Email: {{ email }}<br>
    Comment: {{ comment }}
    </p>
    <p>Thank you!</p>
{% else %}
    <form role="form" action="" method="post" enctype="multipart/form-data">
        {{ form(form['__csrf_token']['hint']) }}

        <div class="form-group{%if form['name']['error'] %} has-error{% endif %}">
            <label class="control-label" for="name">Name</label>
            {{ form(form['name']['hint']) }}
            <label class="control-label" for="name">{{ form['name']['error'] }}</label>
        </div>

        <div class="form-group{%if form['email']['error'] %} has-error{% endif %}">
            <label class="control-label" for="email">Email</label>
            {{ form(form['email']['hint']) }}
            <label class="control-label" for="email">{{ form['email']['error'] }}</label>
        </div>

        <div class="form-group{%if form['comment']['error'] %} has-error{% endif %}">
            <label class="control-label" for="comment">Comment</label>
            {{ form(form['comment']['hint']) }}
            <label class="control-label" for="comment">{{ form['comment']['error'] }}</label>
        </div>

        <input class="btn btn-default" type="submit" name="submit" value="Send">
    </form>
{% endif %}
</div><!-- end of id="contact_form" -->

ページリソースの変更

アプリケーションリソースに移動したロジックを削除し、ページリソースからアプリケーションリソースを呼び出すように変更します。

--- a/src/Resource/Page/Contact.php
+++ b/src/Resource/Page/Contact.php
@@ -11,62 +11,30 @@
 namespace Kenjis\Contact\Resource\Page;

 use BEAR\Resource\ResourceObject;
-use Ray\Di\Di\Inject;
-use Kenjis\Contact\Service\SwiftMailerFactory;
-use BEAR\Resource\Code;
+use BEAR\Sunday\Inject\ResourceInject;

 class Contact extends ResourceObject
 {
-    /**
-     * @Inject
-     */
-    public function __construct(SwiftMailerFactory $mailer)
-    {
-        $this->mailer = $mailer;
-    }
+    use ResourceInject;

-    /**
-     * @BEAR\Sunday\Annotation\Form
-     */
     public function onGet()
     {
+        $this['contact_form'] = $this->resource->get
+            ->uri('app://self/contact/form')
+            ->eager->request();
+
         return $this;
     }

-    /**
-     * @BEAR\Sunday\Annotation\Form
-     */
     public function onPost($name, $email, $comment)
     {
-        $this->sendmail($name, $email, $comment);
+        $this['contact_form'] = $this->resource->post
+            ->uri('app://self/contact/form')
+            ->withQuery(['name' => $name, 'email' => $email, 'comment' => $comment])
+            ->eager->request();

-        $this['code'] = $this->code = Code::CREATED;
-        $this['name']    = $name;
-        $this['email']   = $email;
-        $this['comment'] = $comment;
+        $this->code = $this['contact_form']->code;

         return $this;
     }
-
-    private function sendmail($name, $email, $comment)
-    {
-        $data = [
-            'name'    => $name,
-            'email'   => $email,
-            'comment' => $comment,
-        ];
-
-        $mailer = $this->mailer->create();
-        $mailer->setSubject('コンタクトフォーム')
-            ->setFrom($data['email'], $data['name'])
-            ->setTo('admin@example.org', '管理者')
-            ->setTemplate('mailer/contact_form.twig', $data);
-
-//        echo '<pre>'
-//            . htmlspecialchars($mailer, ENT_QUOTES, 'UTF-8')
-//            . '</pre>';
-
-        $result = $mailer->send();
-        return $result;
-    }
 }

onGet()メソッドでは、以下のようにしてアプリケーションリソースContact\FormをGETでリクエストしています。

        $this['contact_form'] = $this->resource->get
            ->uri('app://self/contact/form')
            ->eager->request();

テンプレートも変更します。

--- a/src/Resource/Page/Contact.twig
+++ b/src/Resource/Page/Contact.twig
@@ -8,41 +8,7 @@
 </head>
 <body>
 <div class="container">
-    <h1>Contact Form</h1>
-
-{% if code == 201 %}
-    <p>
-    Name: {{ name }}<br>
-    Email: {{ email }}<br>
-    Comment: {{ comment }}
-    </p>
-    <p>Thank you!</p>
-{% else %}
-    <form role="form" action="" method="post" enctype="multipart/form-data">
-        {{ form(form['__csrf_token']['hint']) }}
-
-        <div class="form-group{%if form['name']['error'] %} has-error{% endif %}">
-            <label class="control-label" for="name">Name</label>
-            {{ form(form['name']['hint']) }}
-            <label class="control-label" for="name">{{ form['name']['error'] }}</label>
-        </div>
-
-        <div class="form-group{%if form['email']['error'] %} has-error{% endif %}">
-            <label class="control-label" for="email">Email</label>
-            {{ form(form['email']['hint']) }}
-            <label class="control-label" for="email">{{ form['email']['error'] }}</label>
-        </div>
-
-        <div class="form-group{%if form['comment']['error'] %} has-error{% endif %}">
-            <label class="control-label" for="comment">Comment</label>
-            {{ form(form['comment']['hint']) }}
-            <label class="control-label" for="comment">{{ form['comment']['error'] }}</label>
-        </div>
-
-        <input class="btn btn-default" type="submit" name="submit" value="Send">
-    </form>
-{% endif %}
-
+    {{ contact_form|raw }}
 </div>
 </body>
 </html>

フォーム部分は、変数contact_formにセットされていますので、以下のように変更します。contact_formはHTMLなので|rawを付けてエスケープされないようにします。

    {{ contact_form|raw }}

インターセプターの設定の変更

フォームを処理するクラスが変わりましたので、インターセプターをバインドするクラスも変更する必要があります。

--- a/src/Module/AppModule.php
+++ b/src/Module/AppModule.php
@@ -42,7 +42,7 @@ class AppModule extends AbstractModule

         // aspect @Form annotaion
         $this->bindInterceptor(
-            $this->matcher->subclassesOf('Kenjis\Contact\Resource\Page\Contact'),
+            $this->matcher->subclassesOf('Kenjis\Contact\Resource\App\Contact\Form'),
             $this->matcher->annotatedWith('BEAR\Sunday\Annotation\Form'),
             [$this->requestInjection('Kenjis\Contact\Interceptor\Contact\Form')]
         );

これで、フォームがアプリケーションリソースになりました。

ブラウザから http://0.0.0.0:8000/contact にアクセスしてみます。

▼コンタクトフォーム

フォームのまわりに枠ができ、その左上に「app://self/contact/form」と表示されています。この部分がアプリケーションリソースであることがわかります。

何も入力せずに[Send]ボタンを押すと、検証エラーが表示されます。

▼検証エラー

なお、このデフォルトで表示されるリソース名とアイコン(haloと呼ばれています)が邪魔でページが見づらく消したい場合があります。そのような場合は、URLに?halo=0を付けてアクセスするとオフになります(再度有効にしたい場合は?halo=1)。

▼haloをオフに

かなり完成してきました。今日はここまでにします。

BEAR.Sundayでコンタクトフォームを作ってみる⑥へ続く。

過去記事

関連

Date: 2014/08/15

Tags: bear