お問い合わせフォームの作成

Netteでお問い合わせフォームを作成し、メールで送信する方法を見ていきましょう。さあ、始めましょう!

まず、新しいプロジェクトを作成する必要があります。その方法は はじめに ページで説明されています。その後、フォームの作成を開始できます。

最も簡単な方法は、Presenter内で直接フォームを作成する ことです。事前に準備された 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;
	}

	public function contactFormSucceeded(Form $form, $data): void
	{
		// メールの送信
	}
}

ご覧のとおり、2つのメソッドを作成しました。最初のメソッド createComponentContactForm() は新しいフォームを作成します。このフォームには、名前、メール、メッセージのフィールドがあり、これらは addText()addEmail()addTextArea() メソッドで追加します。フォームを送信するためのボタンも追加しました。 しかし、ユーザーがフィールドを空欄にした場合はどうでしょうか?その場合、それが必須フィールドであることを知らせるべきです。これは setRequired() メソッドで実現しました。 最後に、フォームが正常に送信された場合にトリガーされる イベント onSuccess も追加しました。私たちの場合、送信されたフォームの処理を担当する contactFormSucceeded メソッドを呼び出します。これはすぐにコードに追加します。

contantForm コンポーネントを Home/default.latte テンプレートでレンダリングさせます。

{block content}
<h1>お問い合わせフォーム</h1>
{control contactForm}

メールの送信自体については、ContactFacade という名前の新しいクラスを作成し、それを app/Model/ContactFacade.php ファイルに配置します。

<?php
declare(strict_types=1);

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() メソッドはメールを作成して送信します。これには、コンストラクタを介して依存関係として渡される、いわゆるメーラーを使用します。メールの送信 について詳しく読んでください。

次に、Presenterに戻り、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 を変更することです。コンストラクタで、Latte\Engine オブジェクト、つまり Latteテンプレートレンダラー を作成できる LatteFactory クラスを要求します。renderToString() メソッドを使用して、テンプレートをファイルにレンダリングします。最初のパラメータはテンプレートへのパス、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() メソッドに渡します。また、ライブラリがテンプレートの <title> 要素から件名を取得するため、setSubject() でメールの件名を指定する必要もありません。

設定

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);
		// ...
	}
}

そして2番目のステップは、設定でこの変数の値を指定することです。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

これで完了です!