お問い合わせフォームを作ろう
Nette でお問い合わせフォームを作り、送られたデータをメールで送るところまでを見ていきましょう。さっそく始めます。
まず新しいプロジェクトを作る必要があります。方法ははじめにのページで説明しています。それができたら、フォームを作り始められます。
最も簡単なのは、プレゼンターの中に直接フォームを作る方法です。すでにある
HomePresenter を使えます。フォームを表す contactForm
というコンポーネントを追加しましょう。プレゼンターのコードに、そのコンポーネントを作るファクトリメソッド
createComponentContactForm() を足します。
use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;
class HomePresenter extends Presenter
{
protected function createComponentContactForm(): Form
{
$form = new Form;
$form->addText('name', 'お名前:')
->setRequired('お名前を入力してください');
$form->addEmail('email', 'メールアドレス:')
->setRequired('メールアドレスを入力してください');
$form->addTextArea('message', 'メッセージ:')
->setRequired('メッセージを入力してください');
$form->addSubmit('send', '送信');
$form->onSuccess[] = $this->contactFormSucceeded(...);
return $form;
}
private function contactFormSucceeded(Form $form, $data): void
{
// メールの送信
}
}
ご覧のとおり、メソッドを 2 つ作りました。ひとつめの createComponentContactForm()
は新しいフォームのインスタンスを作ります。名前、メールアドレス、メッセージの項目を、それぞれ
addText()、addEmail()、addTextArea()
メソッドで追加しています。送信ボタンも足しました。では、ユーザーが項目を空のままにしたらどうなるでしょうか。その場合は必須であることを伝えるべきです。それを
setRequired() メソッドで実現しました。最後に onSuccess にイベントハンドラを結びつけています。これはフォームが正しく送信されたときに発火します。ここでは
contactFormSucceeded
メソッドを呼び、送られたデータの処理を担当させます。このメソッドはこのあと実装します。
contactForm コンポーネントを Home/default.latte
テンプレートで描きましょう。
{block content}
<h1>お問い合わせフォーム</h1>
{control contactForm}
メールの送信そのもののために、ContactFacade
という新しいクラスを作り、app/Model/ContactFacade.php に置きます。
namespace App\Model;
use Nette\Mail\Mailer;
use Nette\Mail\Message;
class ContactFacade
{
public function __construct(
private Mailer $mailer,
) {
}
public function sendMessage(string $email, string $name, string $message): void
{
$mail = new Message;
$mail->addTo('admin@example.com') // あなたのメールアドレス
->setFrom($email, $name)
->setSubject('お問い合わせフォームからのメッセージ')
->setBody($message);
$this->mailer->send($mail);
}
}
sendMessage() メソッドがメールを作って送ります。そのために mailer
サービスを使い、コンストラクタで依存関係として受け取っています。詳しくはメールの送信をご覧ください。
ではプレゼンターに戻って contactFormSucceeded()
メソッドを仕上げましょう。フォームから送られたデータを渡して、ContactFacade
クラスの sendMessage() メソッドを呼びます。では ContactFacade
オブジェクトはどうやって手に入れるのでしょうか。依存性注入を使い、コンストラクタで要求します。
use App\Model\ContactFacade;
use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;
class HomePresenter extends Presenter
{
public function __construct(
private ContactFacade $facade,
) {
}
protected function createComponentContactForm(): Form
{
// ...
}
public function contactFormSucceeded(stdClass $data): void
{
$this->facade->sendMessage($data->email, $data->name, $data->message);
$this->flashMessage('メッセージを送信しました');
$this->redirect('this');
}
}
メールを送ったあと、送信を知らせるフラッシュメッセージをユーザーに表示します。それからリダイレクトして、ブラウザの再読み込みでフォームが再送信されないようにします。
ここまで正しく設定できていれば、お問い合わせフォームからメールを送れるはずです。おめでとうございます。
HTML メールのテンプレート
今のところ、フォームから送られたメッセージだけを含むプレーンテキストのメールが送られます。しかしメールに
HTML を使えば、見た目をより魅力的にできます。そのためのテンプレートを Latte
で作り、app/Model/contactEmail.latte として保存します。
<html>
<title>お問い合わせフォームからのメッセージ</title>
<body>
<p><strong>お名前:</strong> {$name}</p>
<p><strong>メールアドレス:</strong> {$email}</p>
<p><strong>メッセージ:</strong> {$message}</p>
</body>
</html>
あとは、このテンプレートを使うよう ContactFacade
を書き換えるだけです。コンストラクタで LatteFactory クラスを要求します。これは Latte
のテンプレートレンダラーである Latte\Engine
オブジェクトを作れます。renderToString()
メソッドでテンプレートを文字列に描きます。第 1
パラメータはテンプレートファイルへのパス、第 2 パラメータはそこに渡す変数の配列です。
namespace App\Model;
use Nette\Bridges\ApplicationLatte\LatteFactory;
use Nette\Mail\Mailer;
use Nette\Mail\Message;
class ContactFacade
{
public function __construct(
private Mailer $mailer,
private LatteFactory $latteFactory,
) {
}
public function sendMessage(string $email, string $name, string $message): void
{
$latte = $this->latteFactory->create();
$body = $latte->renderToString(__DIR__ . '/contactEmail.latte', [
'email' => $email,
'name' => $name,
'message' => $message,
]);
$mail = new Message;
$mail->addTo('admin@example.com') // あなたのメールアドレス
->setFrom($email, $name)
->setHtmlBody($body);
$this->mailer->send($mail);
}
}
生成した HTML のメール本文は、もとの setBody() ではなく setHtmlBody()
メソッドに渡します。setSubject()
でメールの件名を指定する必要もありません。ライブラリがテンプレートの <title>
要素から自動的に取り出してくれるからです。
設定
ContactFacade クラスのコードには、管理者のメールアドレス admin@example.com
がまだ直接書かれています。これは設定ファイルに移したほうがよいでしょう。どうすればよいでしょうか。
まず ContactFacade
クラスを書き換え、直接書かれたメールアドレスの文字列を、コンストラクタで渡される変数に置き換えます。
class ContactFacade
{
public function __construct(
private Mailer $mailer,
private LatteFactory $latteFactory,
private string $adminEmail,
) {
}
public function sendMessage(string $email, string $name, string $message): void
{
// ...
$mail = new Message;
$mail->addTo($this->adminEmail)
->setFrom($email, $name)
->setHtmlBody($body);
// ...
}
}
次の段階は、この変数の値を設定で与えることです。app/config/services.neon
ファイルに次を足します。
services:
- App\Model\ContactFacade(adminEmail: admin@example.com)
これで完了です。services
セクションに項目が多く、メールアドレスがその中で埋もれてしまうと感じるなら、パラメータにできます。次のように書き換えてください。
services:
- App\Model\ContactFacade(adminEmail: %adminEmail%)
そしてこのパラメータを app/config/common.neon ファイルで定義します。
parameters:
adminEmail: admin@example.com
これで出来上がりです。