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

#概要
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](https://laravelcollective.com/docs/5.4/html)の設定
###インストール

```
$ 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](https://github.com/andersao/l5-repository)の設定

###インストール

```
$ 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](https://laravel.com/docs/5.4/eloquent#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](https://laravel.com/docs/5.4/validation#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](https://qiita-image-store.s3.amazonaws.com/0/167850/24cfdbe8-1d7f-0554-d653-9970bec97323.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](https://qiita-image-store.s3.amazonaws.com/0/167850/e0dc57dc-4116-f40d-d036-0777855e1cdf.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](https://qiita-image-store.s3.amazonaws.com/0/167850/d0343aac-4b4e-5d93-71d5-9bd14a3a9cc1.png)

これも5.2から5.4へのUpgradeの関係みたい。getToken()をtoken()に変更する。
[Call to undefined method Illuminate\Session\Store::getToken()](http://blog.prakhar.info/call-to-undefined-method-illuminatesessionstoregettoken/)

```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](https://laravel.com/docs/5.1/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](https://qiita-image-store.s3.amazonaws.com/0/167850/1254ffab-96e2-26e7-1534-4cbfd0f45488.png)

###バリデーション
![スクリーンショット 2017-08-17 19.06.45.png](https://qiita-image-store.s3.amazonaws.com/0/167850/139bbbab-c26e-08b3-0e6c-07882032c3ed.png)

###確認画面
![スクリーンショット 2017-08-17 19.07.40.png](https://qiita-image-store.s3.amazonaws.com/0/167850/9498a6c7-0a74-0409-d1f2-46c851c4001a.png)

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

![スクリーンショット 2017-08-17 19.08.38.png](https://qiita-image-store.s3.amazonaws.com/0/167850/343d7147-009d-5b3a-d222-eb4db94cb118.png)

###完了画面
![スクリーンショット 2017-08-17 19.08.58.png](https://qiita-image-store.s3.amazonaws.com/0/167850/50d39cc3-e398-4500-2d3b-126ca77ed12f.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です。

<img width="439" alt="スクリーンショット 2017-08-18 19.44.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/167850/23e5014b-822f-ae62-15c7-32d1a79fb61a.png">

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

#参照記事
[Laravel 5で確認画面付き問い合わせフォームを作る](http://qiita.com/ponko2/items/fd7ac38b964e10f16f52)
[Laravel 5.4 通知](https://readouble.com/laravel/5.4/ja/notifications.html)
[Markdown メール通知を作成する](https://larapet.hinaloe.net/2017/03/09/markdown-mail-notification/)
[[Laravel]Mailableで楽勝なメール処理](http://atuweb.net/201706_laravel-mail-mailable/)