CakePHP3でモデルを使わないでお問い合わせフォームを作りたい

お問い合わせフォームをとにかく作りたかったんです。

でもモデルからDBのテーブルから全部作って…というわけではなく、入力フォームがあってメールで送信できる、というようなお問い合わせフォームにしたかったんです。

でもバリデーションチェックはしたいんです。

上記のような場合、モデルのないフォームがおすすめです。

割とブログ記事も多いのですが、実際に役立ったので自分も書きます。

【自分の環境】
macOS Catalina
PHP7.4.2
CakePHP3.8
MAMP5.7
Apache2.2
MySQL5.7

「モデルのないフォーム」

この名称で知られているようです。

公式ドキュメントもあります。

モデルのないフォーム - 3.9

では実際に作っていきましょう。

必要なのは3つのファイル

必要なのは以下の3つのファイルです。

Formディレクトリがなかったら作成しましょう。

/src/Form/ContactForm.php (フォーム)

/src/Controller/ContactsController.php (コントローラ)

/src/Template/Contacts/index.php (ビューテンプレート)

割と手軽ですよね。

ContactForm.php(フォーム)を作る

今回は体裁として名前欄、メール欄、お問い合わせ内容欄の3つを設けます。

それぞれname、email、bodyという値の命名です。

<?php

namespace App\Form;

use Cake\Form\Form;
use Cake\Form\Schema;
use Cake\Validation\Validator;
use Cake\Mailer\Email;

class ContactForm extends Form
{

    // お問い合わせフォームのスキーマを定義する
    protected function _buildSchema(Schema $schema)
    {
        $schema
            ->addField('name', ['type' => 'string'])
            ->addField('email', ['type' => 'string'])
            ->addField('body', ['type' => 'text']);

        return $schema;
    }

    // バリデーション内容を定義する
    protected function _buildValidator(Validator $validator)
    {        
        $validator
            ->notEmpty('name','名前を入力してください。');

        $validator
            ->notEmpty('email','メールアドレスを入力してください。')
            ->add('email', 'format', [
                'rule' => 'email',
                'message' => 'メールアドレスを入力してください。']);

        $validator
            ->notEmpty('body','本文を入力してください。');

        return $validator;
    }

    // バリデーション後に実行したい処理を記述する
    protected function _execute(array $data)
    {
        // メールを送信する処理(今回は省略)

        return true;
    }
}

ご覧のようにファンクションは3つあります。

スキーマを定義する_buildSchemaファンクション。

バリデーション内容を定義する_buildValidatorファンクション。

バリデーション後に実行したい処理を記述する_executeファンクション。

内容は他のファイルでも見たようなかんじで、あまり難しいことは書いてないので、特に説明はしません。

ContactsController.php(コントローラ)を作る

次にコントローラです。

<?php

namespace App\Controller;

use App\Form\ContactsForm;

class ContactsController extends AppController
{
    public function initialize()
    {
        parent::initialize();

        $this->loadComponent('Flash');
        $this->viewBuilder()->setLayout(false);
    }

    public function index()
    {
        $contacts = new ContactForm();

        if ($this->request->is('post')) {
            if ($contacts->validate($this->request->getData())) {
                if ($contacts->execute($this->request->getData())) {
                    $this->Flash->success(__('ご意見・ご要望を送信しました!'));
                } else {
                    $this->Flash->error(__('送信に失敗しました。'));
                }
            }else{
                $this->Flash->error(__('送信に失敗しました。'));
            }
        }

        $this->set(compact('contacts'));
    }
}

普通のコントローラと変わりませんが、上の方で以下の記述をしています。

「use App\Form\ContactForm;」

これで先ほどのContactFormを使うよ、と宣言しています。

indexアクションで入力があった時の処理を書いています。

ちなみに自分の場合はどうしてもバリデーションが作動しなかったので、「$contacts->validate($this->request->getData())」と明示的にバリデーションさせています。

本来はその先の「$contacts->execute($this->request->getData())」でバリデーションが動くらしいのですが、自分の場合はvalidate()としていることはお伝えしておきます。

いま少し言いましたが、execute()メソッドではデータが有効な時のふるまいを定義します。

ここではフラッシュを表示させています。

index.php(ビューテンプレート)を作る

最後にビューテンプレートを作ります。

<?php echo $this->Html->css('contacts/index'); ?>

<?= $this->Flash->render() ?>

<div class="main">

    <div class="users form">

        <div class="logo">
            <?= $this->Html->image('logo.png', [
                "alt" => "cake",
                'url' => ['controller'=>'pages','action'=>'top'],
                'width'=>'230',
                'height'=>'100'
                ]); ?>
        </div>

        <?= $this->Form->create($contacts) ?>
        <fieldset>
            <legend>ご意見・ご要望フォーム</legend>
            <?= '<p>名前</p>' ?>
            <?=  $this->Form->text('name',['size'=>30]) ?>
            <?= $this->Form->error('name'); ?>
            <?= '<p>メールアドレス</p>' ?>
            <?= $this->Form->text('email',['size'=>30]) ?>
            <?= $this->Form->error('email'); ?>
            <?= '<p>ご意見・ご要望</p>' ?>
            <?= $this->Form->textarea('body',['rows'=>10,'cols'=>40]) ?>
            <?= $this->Form->error('body'); ?>
            <br>
            <?= $this->Form->button('送信する!') ?>
            <?= $this->Form->end() ?>
        </fieldset>
    </div>
</div>

これに関しては、フォームの有無に関わらない内容なので、特に長い説明はしません。

名前欄、メール欄、お問い合わせ内容欄があります。

中盤ですが、「$this->Form->create($contacts)」として、$contactsを入れることを忘れないでください。

これを入れないとバリデーションメッセージが出なかったり、いろいろと困ります。

おまけ

フォームとしては説明は以上です。

ただお問い合わせフォームとして大事なのがメール送信です。

実際にフォームの_executeファンクションで書いていますが、記述は省略しています。

ここに関しては長くなるので、次回、別記事で説明します。

終わりに

以上となります。

モデルなしで手軽にお問い合わせフォームが作れるのは便利ですよね。

実際に動かすともっとわかってくると思います。

ぜひトライしてみてください。

メール送信に関しては次回詳しく説明します。

ありがとうございました。