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

BEAR.Sundayでの「Hello World!」①がGoogle検索「BEAR.Sunday Hello World」で1位をゲットしました!

ということで、そろそろBEAR.SundayのHello Worldにも飽きてきたと思いますので、先に進みたいと思います。

次のお題はコンタクトフォームです。

BEAR.Sundayのインストール

bear/skeletonを使ってインストールします。最新の開発版をインストールするためにdev-developを指定します。

$ composer create-project bear/skeleton:dev-develop Kenjis.Contact
$ cd Kenjis.Contact
$ composer install

依存パッケージの更新と追加

bear/packageをdevelopブランチに、ray/diをmasterブランチに、そして、メール送信のためにSwiftMailerを追加します。

--- a/composer.json
+++ b/composer.json
@@ -3,7 +3,9 @@
     "description":"n/a",
     "license": "proprietary",
     "require": {
-        "bear/package": "~0.11"
+        "bear/package": "dev-develop",
+        "ray/di": "dev-master",
+        "swiftmailer/swiftmailer": "@stable"
     },
     "require-dev": {
         "bear/dev-package": "~0.1@dev"
$ composer update

SwiftMailerを使う準備

SwiftMailerクラスの作成

そのままSwiftMailerを使うこともできますが、ここでは、より簡単に使えるように、Twigと合わせてテンプレートを使えるようにしたSwiftMailerクラスを作成しておきます。

src/Service/SwiftMailer.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\Service;

class SwiftMailer
{
    private $mailer;
    private $twig;

    private $subject;
    private $from;
    private $to;

    private $template;
    private $templateVars;

    public function __construct(\Swift_Mailer $mailer, \Twig_Environment $twig)
    {
        $this->mailer = $mailer;
        $this->twig = $twig;

        // logger for debug
//        $logger = new \Swift_Plugins_Loggers_EchoLogger();
//        $this->mailer->registerPlugin(new \Swift_Plugins_LoggerPlugin($logger));
    }

    /**
     * @return \Swift_Message
     */
    private function build()
    {
        $body = $this->twig->render($this->template, $this->templateVars);

        $message = \Swift_Message::newInstance()
            ->setSubject($this->subject)
            ->setFrom($this->from)
            ->setTo($this->to)
            ->setBody($body);

        return $message;
    }

    /**
     * @param string $template template filename
     * @param array $vars variables to pass template
     */
    public function setTemplate($template, array $vars)
    {
        $this->template = $template;
        $this->templateVars = $vars;
        return $this;
    }

    public function setSubject($subject)
    {
        $this->subject = $subject;
        return $this;
    }

    public function setFrom($address, $name)
    {
        $this->from = [$address => $name];
        return $this;
    }

    public function setTo($address, $name)
    {
        $this->to = [$address => $name];
        return $this;
    }

    /**
     * Send mail
     *
     * @return int the number of recipients who were accepted for delivery
     */
    public function send()
    {
        $message = $this->build();
        return $this->mailer->send($message);
    }

    /**
     * Get this message as a complete string
     *
     * @return string
     */
    public function __toString()
    {
        return $this->build()->toString();
    }
}

SwiftMailerFactoryクラスの作成

上のSwiftMailerクラスを生成するファクトリも作成しておきます。

src/Service/SwiftMailerFactory.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\Service;

use Ray\Di\Di\Inject;
use Ray\Di\Di\Named;

class SwiftMailerFactory
{
    /**
     * @var string
     */
    private $context;

    private $twig;

    /**
     * @Inject
     * @Named("context=app_context")
     */
    public function __construct($context)
    {
        $this->context = $context;
    }

    /**
     * @Inject
     */
    public function setTwig(\Twig_Environment $twig)
    {
        $this->twig = $twig;
    }

    /**
     * @return \Swift_Mailer
     */
    public function create()
    {
        if ($this->context === 'test') {
            $transport = \Swift_NullTransport::newInstance();
        } else {
            $transport = \Swift_SmtpTransport::newInstance('smtp.gmail.com', '465', 'ssl')
                ->setUsername($_ENV['MAILER_GMAIL_ID'])
                ->setPassword($_ENV['MAILER_GMAIL_PASSWORD']);
        }

        $mailer = \Swift_Mailer::newInstance($transport);

        return new SwiftMailer($mailer, $this->twig);
    }
}

コンストラクタインジェクション(@Inject)で名前付きバインディング(@Named)を使い、$contextにBEAR.Sundayのapp_context(アプリケーションコンテキスト、いわゆる環境。デフォルトではprod、dev、test、apiのいずれか)を注入しています。

setTwig()メソッドでは、セッターインジェクション(@Inject)を使い、$twigにTwig_Environmentインスタンスを注入しています。

create()メソッドではコンテキストにより、SwiftMailerのトランスポートオブジェクトを変更しています。test環境ではSwift_NullTransportを使いメールの転送を行いません。test環境以外ではGmailをSMTPサーバに利用します。

メール用のテンプレートの作成

作成したSwiftMailerクラスで使うメール用のテンプレートを作成します。

var/lib/twig/template/mailer/contact_form.twig

{% autoescape false %}
名前: {{ name }}
電子メール: {{ email }}
コメント:
{{ comment }}
{% endautoescape %}

サーバ起動スクリプトの作成

GmailをSMTPサーバとして利用するにはGmailアカウントの情報が必要です。

ここでは、以下のシェルスクリプトを作成し、環境変数でGmailアカウントの情報をWebサーバに渡すようにします。

server.sh

#!/bin/sh

export MAILER_GMAIL_ID=アカウント@gmail.com
export MAILER_GMAIL_PASSWORD=パスワード

# clear BEAR.Sunday's cache
php bin/clear.php

vendor/bin/bear.server --port=8000 --context=dev .
#php -S 0.0.0.0:8000 -t var/www/ bootstrap/contexts/dev.php

メール送信のテスト

SwiftMailerを使う準備ができましたので、メール送信をテストしてみます。

とりあえず、ページリソースContactを作成し、GETされた場合にメールを送信してみます。

src/Resource/Page/Contact.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\Page;

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

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

    public function onGet()
    {
        $data = [
            'name'    => 'BEAR.Sunday',
            'email'   => 'bear@example.jp',
            '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 (string) $result;
    }
}

デバッグのために$mailerをechoしてメッセージの文字列を表示しています。 また、SwiftMailerのsend()メソッドは処理したメールの数(整数)を返しますので、それを文字列にキャストして返して表示します。

サーバ起動スクリプトを実行し、PHPのビルトインサーバを起動します。

$ sh server.sh

これで、http://0.0.0.0:8000/contact にブラウザからアクセスすると、Gmail経由でメールが送信されるはずです。

うまくいかない場合は、SwiftMailerクラスのコンストラクタの最後にあるEchoLoggerプラグインを登録するコードを有効にすると、SMTPサーバとのやりとりのログがechoされるようになります。

src/Service/SwiftMailer.php

    public function __construct(\Swift_Mailer $mailer, \Twig_Environment $twig)
    {
        $this->mailer = $mailer;
        $this->twig = $twig;

        // logger for debug
//        $logger = new \Swift_Plugins_Loggers_EchoLogger();
//        $this->mailer->registerPlugin(new \Swift_Plugins_LoggerPlugin($logger));
    }

というわけで、メール送信だけで終わってしまいましたが、今日はここまでにします。

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

関連

Date: 2014/08/11

Tags: bear, swiftmailer