13
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Laravel5.4でメール通知付きの問い合わせフォームを作る

Last updated at Posted at 2017-08-20

#概要
Laravelを初めて触ってみたので、簡単なチュートリアルを参考にしながら、メール通知付き問い合わせフォーム機能を作ってみた!

#前準備

##日本語化
###日本語の言語ファイルを追加
https://github.com/caouecs/Laravel-lang/tree/master/src/ja のファイルを resources/lang の下に追加。

###localeをjaに変更

config/app.php
// 'locale' => 'en',
   'locale' => 'ja',

###timezoneをAsia/Tokyoに変更

config/app.php
// 'timezone' => 'UTC',
   'timezone' => 'Asia/Tokyo',

##Laravel Collectiveの設定
###インストール

$ composer require "laravelcollective/html":"^5.4.0"
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing laravelcollective/html (v5.4.8): Downloading (100%)         
Writing lock file
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postUpdate
> php artisan optimize
Generating optimized class loader
The compiled services file has been removed.

###設定

app/Services/Html/HtmlBuilder.php
<?php

namespace App\Services\Html;

class HtmlBuilder extends \Collective\Html\HtmlBuilder
{
    //
}
app/Services/Html/FormBuilder.php
<?php

namespace App\Services\Html;

class FormBuilder extends \Collective\Html\FormBuilder
{
    /**
     * Get the action for a "route" option.
     *
     * @param  array|string $options
     *
     * @return string
     */
    protected function getRouteAction($options)
    {
        if (is_array($options)) {
            return call_user_func_array([$this->url, 'route'], $options);
        }

        return $this->url->route($options);
    }
}
app/Services/Html/ServiceProvider.php
<?php

namespace App\Services\Html;

use Collective\Html\HtmlServiceProvider;

class ServiceProvider extends HtmlServiceProvider
{
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->registerHtmlBuilder();
        $this->registerFormBuilder();

        $this->app->alias('html', HtmlBuilder::class);
        $this->app->alias('form', FormBuilder::class);
    }

    /**
     * Register the HTML builder instance.
     *
     * @return void
     */
    protected function registerHtmlBuilder()
    {
        $this->app->singleton('html', function ($app) {
            return new HtmlBuilder($app['url'], $app['view']);
        });
    }

    /**
     * Register the form builder instance.
     *
     * @return void
     */
    protected function registerFormBuilder()
    {
        $this->app->singleton('form', function ($app) {
            $form = new FormBuilder($app['html'], $app['url'], $app['view'], $app['session.store']->getToken());

            return $form->setSessionStore($app['session.store']);
        });
    }

    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()
    {
        return [
            'html',
            'form',
            HtmlBuilder::class,
            FormBuilder::class,
        ];
    }
}
config/app.php

  App\Providers\EventServiceProvider::class,
  App\Providers\RouteServiceProvider::class,
+ App\Services\Html\ServiceProvider::class,

  'URL' => Illuminate\Support\Facades\URL::class,
  'Validator' => Illuminate\Support\Facades\Validator::class,
  'View' => Illuminate\Support\Facades\View::class,
+ 'Form'      => Collective\Html\FormFacade::class,
+ 'Html'      => Collective\Html\HtmlFacade::class,

##Laravel 5 Repositoriesの設定

###インストール

$ composer require prettus/l5-repository
Using version ^2.6 for prettus/l5-repository
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 2 installs, 0 updates, 0 removals
  - Installing prettus/laravel-validation (1.1.4): Downloading (100%)         
  - Installing prettus/l5-repository (2.6.20): Downloading (100%)         
prettus/l5-repository suggests installing league/fractal (Required to use the Fractal Presenter (0.12.*).)
prettus/l5-repository suggests installing robclancy/presenter (Required to use the Presenter Model (1.3.*))
Writing lock file
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postUpdate
> php artisan optimize
Generating optimized class loader
The compiled services file has been removed.

$ composer require prettus/laravel-validation
Using version ^1.1 for prettus/laravel-validation
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Nothing to install or update
Writing lock file
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postUpdate
> php artisan optimize
Generating optimized class loader
The compiled services file has been removed.

$ composer require league/fractal
Using version ^0.16.0 for league/fractal
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing league/fractal (0.16.0): Downloading (100%)         
league/fractal suggests installing pagerfanta/pagerfanta (Pagerfanta Paginator)
league/fractal suggests installing zendframework/zend-paginator (Zend Framework Paginator)
Writing lock file
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postUpdate
> php artisan optimize
Generating optimized class loader
The compiled services file has been removed.

###設定
Prettus\Repository\Providers\RepositoryServiceProvider::classはprovidersの最後に追加しないとおかしな動作をするらしい。

config/app.php
  App\Providers\AppServiceProvider::class,
  App\Providers\AuthServiceProvider::class,
+ App\Providers\RepositoryServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
  App\Providers\EventServiceProvider::class,
  App\Providers\RouteServiceProvider::class,
  App\Services\Html\ServiceProvider::class,

+ Prettus\Repository\Providers\RepositoryServiceProvider::class,
app/Providers/RepositoryServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

/**
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class RepositoryServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        $repositories = [
            // \App\Repositories\UserRepository::class,
        ];

        foreach ($repositories as $repository) {
            $this->app->bind($repository, $repository.'Eloquent');
        }
    }
}
$ php artisan vendor:publish
Copied Directory [/vendor/laravel/framework/src/Illuminate/Notifications/resources/views] To [/resources/views/vendor/notifications]
Copied Directory [/vendor/laravel/framework/src/Illuminate/Pagination/resources/views] To [/resources/views/vendor/pagination]
Copied File [/vendor/prettus/l5-repository/src/resources/config/repository.php] To [/config/repository.php]
Copied Directory [/vendor/laravel/framework/src/Illuminate/Mail/resources/views] To [/resources/views/vendor/mail]
Publishing complete.

#雛形作成
artisanで雛形を作成してみる。
php artisan make:entity Contactに関しては適当にyes/noしてしまったので、あとで見直したい。

$ php artisan make:controller --resource ContactController
Controller created successfully.

$ php artisan make:request ContactRequest
Request created successfully.

$ php artisan make:entity Contact

 Would you like to create a Presenter? [y|N] (yes/no) [no]:
 > no

 Would you like to create a Validator? [y|N] (yes/no) [no]:
 > N

 Would you like to create a Controller? [y|N] (yes/no) [no]:
 > y

Request created successfully.
Request created successfully.
Controller created successfully.
Repository created successfully.
Bindings created successfully.

$ php artisan make:migration create_contacts_table
Created Migration: 2017_08_17_160250_create_contacts_table

#Database Migration
マイグレーションファイルを一部修正する。

database/migrations/2015_12_01_000000_create_contacts_table.php
<?php

use Illuminate\Database\Migrations\Migration;

class CreateContactsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('contacts', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email');
            $table->string('subject');
            $table->text('content');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('contacts');
    }
}
$ php artisan migrate
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table
Migrating: 2017_08_17_155444_create_contacts_table
Migrated:  2017_08_17_155444_create_contacts_table

作成したDBを確認してみる。

$ mysql

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| homestead          |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.01 sec)

show tables;
+---------------------+
| Tables_in_homestead |
+---------------------+
| contacts            |
| migrations          |
| password_resets     |
| users               |
+---------------------+
4 rows in set (0.01 sec)

mysql> DESCRIBE contacts;
+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra          |
+------------+------------------+------+-----+---------+----------------+
| id         | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| name       | varchar(255)     | NO   |     | NULL    |                |
| email      | varchar(255)     | NO   |     | NULL    |                |
| subject    | varchar(255)     | NO   |     | NULL    |                |
| content    | text             | NO   |     | NULL    |                |
| created_at | timestamp        | YES  |     | NULL    |                |
| updated_at | timestamp        | YES  |     | NULL    |                |
+------------+------------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)

#Mass Assignment

どうやら設定として必要らしいので設定をしておく。

app/Entities/Contact.php
<?php

namespace App\Entities;

use Illuminate\Database\Eloquent\Model;
use Prettus\Repository\Contracts\Transformable;
use Prettus\Repository\Traits\TransformableTrait;

class Contact extends Model implements Transformable
{
    use TransformableTrait;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'subject',
        'content',
    ];

}

#ルーティング

indexとstoreを使うためにonlyで指定をかけている。

app/Http/routes.php
<?php

Route::resource('contacts', 'ContactController', ['only' => ['index', 'store']]);

#バリデーション
Form Request Validationを使うとバリデーションがコントローラから切り出せるのですっきりする。

###お問い合わせ画面のRequest

app/Http/Requests/ContactRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ContactRequest extends FormRequest
{
    use ConfirmRequestTrait;

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        // return false;
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name'    => 'required',
            'email'   => 'required|email',
            'subject' => 'required',
            'content' => 'required',
        ];
    }

    /**
     * Set custom messages for validator errors.
     *
     * @return array
     */
    public function messages()
    {
        return [
            //
        ];
    }

    /**
     * Set custom attributes for validator errors.
     *
     * @return array
     */
    public function attributes()
    {
        return [
            'name'    => 'お名前',
            'email'   => 'メールアドレス',
            'subject' => '件名',
            'content' => '内容',
        ];
    }
}

use ConfirmRequestTraitを追加することで、確認画面付きのフォームになる。authorizeメソッドの返り値をtrueにしておかないと、403エラーになるので注意。

###確認画面の共通処理

app/Http/Requests/ConfirmRequestTrait.php
<?php

namespace App\Http\Requests;

use Illuminate\Contracts\Validation\Validator;

trait ConfirmRequestTrait
{
    /**
     * Set custom messages for validator errors.
     *
     * @param \Illuminate\Contracts\Validation\Factory $factory
     *
     * @return \Illuminate\Contracts\Validation\Validator
     */
    public function validator($factory)
    {
        // 値検証前の処理
        if (method_exists($this, 'beforeValidate')) {
            $this->beforeValidate();
        }

        // 確認画面用フラグのバリデーションを追加
        $rules = array_merge($this->rules(), [
            'confirming' => 'required|accepted',
        ]);

        $validator = $factory->make(
            $this->all(),
            $rules,
            $this->messages(),
            $this->attributes()
        );

        $validator->after(function ($validator) {
            $failed = $validator->failed();

            // 確認画面用フラグのバリデーションを除外
            unset($failed['confirming']);

            // 確認画面用フラグ以外にエラーが無い場合は確認画面を表示
            if (count($failed) === 0) {
                $this->merge(['confirming' => 'true']);
            }

            // 値検証後の処理
            if (method_exists($this, 'afterValidate')) {
                $this->afterValidate($validator);
            }
        });

        return $validator;
    }

    /**
     * Format the errors from the given Validator instance.
     *
     * @param  \Illuminate\Contracts\Validation\Validator  $validator
     *
     * @return array
     */
    protected function formatErrors(Validator $validator)
    {
        $errors = parent::formatErrors($validator);

        // 確認画面用フラグのエラーメッセージを削除
        unset($errors['confirming']);

        return $errors;
    }
}

#Repository Service Provider
make:entityで生成されたContactRepositoryを登録する。

app/Providers/RepositoryServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

/**
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class RepositoryServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        $repositories = [
            \App\Repositories\ContactRepository::class,
        ];

        foreach ($repositories as $repository) {
            $this->app->bind($repository, $repository.'Eloquent');
        }
    }
}

#Blade Templates

###共通部分

resources/views/layouts/master.blade.php
<!DOCTYPE html>
<html lang="{{ App::getLocale() }}">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>@yield('title') - App Name</title>
        @section('styles')
            <link rel="stylesheet" href="{{ elixir('css/app.css') }}">
        @show
        <!--[if lt IE 9]>
            <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
            <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
        <![endif]-->
    </head>
    <body class="@yield('body-class')">
        <div class="container">
            @yield('content')
        </div>
        @section('scripts')
            <script src="{{ elixir('js/main.js') }}"></script>
        @show
    </body>
</html>

###フォーム画面

resources/views/contacts/index.blade.php
@extends('layouts.master')

@section('title', 'お問い合わせ')

@section('content')
    @if(count($errors) > 0)
        <div class="alert alert-danger">
            <ul>
                @foreach($errors->all() as $error)
                    <li>{{ $error }}</li>
                @endforeach
            </ul>
        </div>
    @endif
    <div class="panel panel-default">
        <div class="panel-heading">
            <h1 class="panel-title">お問い合わせ</h1>
        </div>
        <div class="panel-body">
            {!! Form::open(['route' => ['contacts.store'], 'method' => 'post']) !!}
                <input type="hidden" name="confirming" value="{{ old('confirming', 'false') }}">
                <div class="form-group required {{ $errors->has('name') ? 'has-error' : '' }}">
                    <label class="control-label" for="name">お名前</label>
                    @if(old('confirming', 'false') === 'false')
                        <input type="text" class="form-control" name="name" value="{{ old('name') }}">
                    @else
                        <p class="form-control-static">{{ old('name') }}</p>
                        <input type="hidden" name="name" value="{{ old('name') }}">
                    @endif
                    @if($errors->has('name'))
                        <p class="help-block">{{ $errors->first('name') }}</p>
                    @endif
                </div>
                <div class="form-group required {{ $errors->has('email') ? 'has-error' : '' }}">
                    <label class="control-label" for="email">メールアドレス</label>
                    @if(old('confirming', 'false') === 'false')
                        <input type="email" class="form-control" name="email" value="{{ old('email') }}">
                    @else
                        <p class="form-control-static">{{ old('email') }}</p>
                        <input type="hidden" name="email" value="{{ old('email') }}">
                    @endif
                    @if($errors->has('email'))
                        <p class="help-block">{{ $errors->first('email') }}</p>
                    @endif
                </div>
                <div class="form-group required {{ $errors->has('subject') ? 'has-error' : '' }}">
                    <label class="control-label" for="subject">件名</label>
                    @if(old('confirming', 'false') === 'false')
                        <input type="text" class="form-control" name="subject" value="{{ old('subject') }}">
                    @else
                        <p class="form-control-static">{{ old('subject') }}</p>
                        <input type="hidden" name="subject" value="{{ old('subject') }}">
                    @endif
                    @if($errors->has('subject'))
                        <p class="help-block">{{ $errors->first('subject') }}</p>
                    @endif
                </div>
                <div class="form-group required {{ $errors->has('content') ? 'has-error' : '' }}">
                    <label class="control-label" for="content">内容</label>
                    @if(old('confirming', 'false') === 'false')
                        <textarea type="text" class="form-control" name="content" rows="10">{{
                            old('content')
                        }}</textarea>
                    @else
                        <p class="form-control-static">{!! nl2br(e(old('content'))) !!}</p>
                        <input type="hidden" name="content" value="{{ old('content') }}">
                    @endif
                    @if($errors->has('content'))
                        <p class="help-block">{{ $errors->first('content') }}</p>
                    @endif
                </div>
                <div class="form-group text-center">
                    @if(old('confirming', 'false') === 'false')
                        <button type="submit" class="btn btn-primary">確認</button>
                    @else
                        <button type="submit" name="action" value="post" class="btn btn-primary">送信</button>
                        <button type="submit" name="action" value="back" class="btn btn-default">戻る</button>
                    @endif
                </div>
            {!! Form::close() !!}
        </div>
    </div>
@endsection

###投稿完了画面

resources/views/contacts/thanks.blade.php
@extends('layouts.master')

@section('title', 'お問い合わせ')

@section('content')
    <div class="panel panel-default">
        <div class="panel-heading">
            <h1 class="panel-title">お問い合わせ</h1>
        </div>
        <div class="panel-body">
            <div class="well well-lg text-center">お問い合わせありがとうございました</div>
        </div>
    </div>
@endsection

#コントローラ
storeメソッドの引数にContactRequestを指定するとForm Request Validationで値の検証ができるので、そのままデータベースに突っ込んでもOK。

app/Http/Controllers/ContactController.php
<?php

namespace App\Http\Controllers;

use App\Http\Requests\ContactRequest;
use App\Repositories\ContactRepository;

class ContactController extends Controller
{
    /**
     * @var ContactRepository
     */
    protected $contacts;

    /**
     * コンストラクタ
     *
     * @param ContactRepository $contacts
     */
    public function __construct(ContactRepository $contacts)
    {
        $this->contacts = $contacts;
    }

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view('contacts.index');
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param ContactRequest $request
     *
     * @return \Illuminate\Http\Response
     */
    public function store(ContactRequest $request)
    {
        // 確認画面で戻るボタンが押された場合
        if ($request->get('action') === 'back') {
            // 入力画面へ戻る
            return redirect()
                ->route('contacts.index')
                ->withInput($request->except(['action', 'confirming']));
        }

        // データベースに登録
        $this->contacts->create($request->all());

        // ブラウザリロード等での二重送信防止
        $request->session()->regenerateToken();

        // 完了画面を表示
        return view('contacts.thanks');
    }
}

###ルーティングのエラー
作成したものを確認するために一度http://homestead.app/contactsにアクセスしてみる。そんなページないぞと怒られる。

スクリーンショット 2017-08-17 17.37.29.png

laravel5.2を題材にしたチュートリアルを参照したため、5.4でrouteを設定するファイルの場所が違った。下記の場所に書いてみる。

routes/web.php
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::resource('contacts', 'ContactController', ['only' => ['index', 'store']]);

###ContactRepositoryを読み込めてないエラー
違うエラーに遭遇した。

スクリーンショット 2017-08-17 17.52.47.png

app/Providers/RepositoryServiceProvider.phpでContactRepositoryをうまく呼び出せていなかった。

app/Providers/RepositoryServiceProvider.php
public function register()
    {
        $repositories = [
            // \App\Repositories\UserRepository::class,
            \App\Repositories\ContactRepository::class,
        ];

        foreach ($repositories as $repository) {
            $this->app->bind($repository, $repository.'Eloquent');
        }
    }

###Call to undefined method Illuminate\Session\Store::getToken()
エラー内容が変わる。contacts/index.blade.phpで定義されてないメソッドが呼ばれていると怒られる。

スクリーンショット 2017-08-17 18.12.17.png

これも5.2から5.4へのUpgradeの関係みたい。getToken()をtoken()に変更する。
Call to undefined method Illuminate\Session\Store::getToken()

app/Services/Html/ServiceProvider.php
protected function registerFormBuilder()
    {
        $this->app->singleton('form', function ($app) {
            $form = new FormBuilder($app['html'], $app['url'], $app['view'], $app['session.store']->token());

            return $form->setSessionStore($app['session.store']);
        });
    }

###js/main.jsがないと怒られる
main.jsを読み込んでいる部分をコメントアウトする。そもそもLaravel Elixirを入れてないので、エラーが出て当たり前。

resources/views/layouts/master.blade.php
<!DOCTYPE html>
<html lang="{{ App::getLocale() }}">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>@yield('title') - App Name</title>
        @section('styles')
            <link rel="stylesheet" href="{{ elixir('css/app.css') }}">
        @show
        <!--[if lt IE 9]>
            <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
            <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
        <![endif]-->
    </head>
    <body class="@yield('body-class')">
        <div class="container">
            @yield('content')
        </div>
        @section('scripts')
        {{-- <script src="{{ elixir('js/main.js') }}"></script> --}}
        @show
    </body>
</html>

表示された!

###お問い合わせページ

スクリーンショット 2017-08-17 19.05.47.png

###バリデーション
スクリーンショット 2017-08-17 19.06.45.png

###確認画面
スクリーンショット 2017-08-17 19.07.40.png

###確認画面から戻った画面

スクリーンショット 2017-08-17 19.08.38.png

###完了画面
スクリーンショット 2017-08-17 19.08.58.png

#データが入っているか確認
確かに先ほど入れたデータが入っている!

mysql> select * from contacts;
+----+------+---------------+---------+---------------+---------------------+---------------------+
| id | name | email         | subject | content       | created_at          | updated_at          |
+----+------+---------------+---------+---------------+---------------------+---------------------+
|  1 | test | test@test.com | test    | testです。    | 2017-08-17 19:08:56 | 2017-08-17 19:08:56 |
+----+------+---------------+---------+---------------+---------------------+---------------------+

#メール通知機能を実装

###ContactResponseクラスを生成

artisan(アルチザン)コマンドからContactResponseクラスを生成する。

$ php artisan make:mail ContactResponse

生成直後のクラス名。

App\Mail\Mail.php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class Greet extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->view('view.name');
    }
}

###Mailableを編集する
お問い合わせ内容を適当にviewに渡します。

<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class ContactResponse extends Mailable
{
    use Queueable, SerializesModels;

    protected $options;
    protected $content;
    // protected $attach;

    public function __construct($options, $content /*, $attach */)
    {
        $this->options = $options;
        $this->content = $content;
        // $this->attach  = $attach;
    }
    public function build()
    {
        return $this->subject('お問い合わせありがとうございました。')
                    // ->attachData($this->attach['binary'], $this->attach['file_name']);
                    ->view('emails.contact')
                    ->with([
                        'options' => $this->options,
                        'content' => $this->content,
                    ]);
    }
}

###テンプレート

問い合わせてきた人の名前とか件名や内容を表示してます。

resources/views/emails/contact.blade.php
Mailテストくんからのご挨拶です。<br>
{{ $options['name'] }}さん、お問い合わせありがとうございます。<br>
<br>
以下がお問い合わせ内容になります。<br>
-------------------------------------------------------------<br>
件名:{{ $options['subject'] }}<br>
<br>
内容:<br>
{{ $content }}<br>

##メール送信

ContactControllerでお問い合わせがきたら、自動でメールを返信するようにします。

app/Http/Controllers/ContactController.php
<?php

namespace App\Http\Controllers;

use App\Http\Requests\ContactRequest;
use App\Repositories\ContactRepository;

class ContactController extends Controller
{
...
    public function store(ContactRequest $request)
    {
        // 確認画面で戻るボタンが押された場合
        if ($request->get('action') === 'back') {
            // 入力画面へ戻る
            return redirect()
                ->route('contacts.index')
                ->withInput($request->except(['action', 'confirming']));
        }

        // データベースに登録
        $this->contacts->create($request->all());

        // ブラウザリロード等での二重送信防止
        $request->session()->regenerateToken();

        // 返答メールの送信
        $email   = $request->email;
        $options = array('name' => $request->name, 'subject' => $request->subject);
        $content = $request->content;
        \Mail::to($email)->send(new \App\Mail\ContactResponse($options, $content /* , $attach */));

        // 完了画面を表示
        return view('contacts.thanks');
    }
}

メールが来ていることを確認して終了!

こんな感じで表示されればOKです。

スクリーンショット 2017-08-18 19.44.44.png

#感想
Laravel 5で確認画面付き問い合わせフォームを作るの記事がかなりうまくできていて、お問い合わせフォームの流れを作るまでは結構サクサクいった。(もちろん5.2→5.4でいろいろ修正することはあったけど。)それ以上にメールの実装に時間がかかってしまった。まだまだなのでこれを発展させていきたい。

#参照記事
Laravel 5で確認画面付き問い合わせフォームを作る
Laravel 5.4 通知
Markdown メール通知を作成する
[Laravel]Mailableで楽勝なメール処理

13
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?