20200122のlaravelに関する記事は10件です。

⛰【Vue.js】MariaDBのJSON型カラムから取得したデータの指定の値を変数名で取り出す為にパースする

環境

Vue.js 6.12.0
PHP 7.3.10
Laravel 6.5.0
MariaDB

やりたいこと

MariaDBのに下記のようなデータが格納されていてそれをLaravelのAPIで取得する。
その内のcontentカラム(JSON型)のデータからdata_kindの値を判断基準として条件分岐を行い、
valueの内容である「テストの内容です?」や「赤文字で強調する!!」や円周率をVueので表示する為にJSONをパースする

id content del_flg
1 {"data_kind": "1", "value": "テストの内容です?"} 0
2 {"data_kind": "2", "value": "赤文字で強調する!!"} 0
3 {"data_kind": "3", "value": "円周率を表示"} 0
4 {"data_kind": "4", "value": "削除済み???"} 1

やったこと

下に全体で色々書いてますが一番重要なのは下記のパース部分です
これが無いとJSONではなくJSONの形をしたただの文字列としてデータが扱われるので値を取り出すことができません

          // 取得データをforEachで全てJSON.parseにかける
          res.data.recordList.forEach(value => {
            value["content"] = JSON.parse(value["content"]);
          });

全体

Hoge.vue
// テンプレ部分
<template>
  <section class="container">

    <div v-for="data in tableData" :key="content.id">
      <!-- 通常表示 -->
      <div v-if="data.content.data_kind === '1'">{{ data.content.value }}</div>
      <!-- クラスを付けて装飾を変更 -->
      <div v-else-if="data.content.data_kind === '2'" class="redBold">{{ data.content.value }}</div>
      <!-- 円周率を表示 -->
      <div v-else-if="data.content.data_kind === '3'">3.141592653589323846....</div>
    </div>

  </section>
</template>

// データ取得とパース部分
<script>
export default {
  data() {
    return {
      tableData: []
    };
  },
  methods: {
    getContent() {
      axios
        .get("/api/getContent", {
          params: {
            delFlg: 0
          }
        })
        .then(res => {
          // 取得データをforEachで全てJSON.parseにかける
          res.data.recordList.forEach(value => {
            value["content"] = JSON.parse(value["content"]);
          });
          this.tableData = res.data.recordList;
        });
    }
  },
  mounted() {
    this.getContent();
  }
};
</script>

// 装飾
<style lang="sass" scoped>
.redBold
  color: red
  font-weight: bold
</style>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWSで作ったLaravelアプリケーションをXserverにデプロイする

はじめに

タイトル通りですが、LaravelアプリケーションのデプロイをXserverで試してみました。

AWSでアプリケーションは作成したのですが、
XAMPPで作成した方も以下のやり方でできると思います。

まとめ

さっそくですがやり方を以下にまとめました。

※XAMPPでアプリケーションを作成した方は⑥以降を参考にしていただければと思います。

①AWSでLaravelアプリケーションを作成。

②作成したアプリケーションのフォルダをダウンロードしてXAMPP環境下(htdocs内)に保存する。

③XAMPPでphpMyAdminを起動。アプリケーション用のDB(DB名:laravel)を作成する。

④.envをXAMPP環境下でDBが使えるようにに編集。

.env
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

⑤コマンドプロンプトで同フォルダに移動してテーブル作成

$ cd 作成したアプリのフォルダ
$ php artisan migrate//このコマンドでテーブルが作成されます。

⑥FTP(FileZillaを使用しました)で転送したいドメイン内のpublic_htmlへ作成したアプリのpublic内のファイルをすべて転送

⑦publicフォルダ以外のファイルをまとめて新しく作ったフォルダに転送(public_htmlと同じ階層下)

フォルダ名はlaraveltestとしました。
コメント 2020-01-22 230052.png

⑧public_htmlに転送したindex.phpのrequire先を新しく作ったフォルダ先に変更

index.php
require __DIR__.'/../laraveltest/vendor/autoload.php';//28行目
~~
$app = require_once __DIR__.'/../laraveltest/bootstrap/app.php';//38行目

⑨XAMPP環境下のphpMyAdminで同アプリ用に作ったテーブルをエクスポート(.sqlファイル)

⑩先ほどエクスポートしたsqlファイルをXserver環境下のphpMyAdminにインポートしてテーブル作成

⑪転送した.envを以下のように編集して保存

.env
APP_URL=http://独自ドメイン/

DB_connection=mysql
DB_HOST=自身のサーバ名.xserver.jp
DB_PORT=3306
DB_DATABASE=自身のデータベース名
DB_USERNAME=自身のユーザー名
DB_PASSWORD=自身で設定したパスワード

⑫対象のドメインへアクセスして問題ないか確認。

参考

参考にさせていただいた記事は以下です。
https://qiita.com/hitotch/items/5c8c2858c883e69cd507

最後に

完全に個人的備忘録です。
もしかしたらかなり遠回りな方法でデプロイしているかもしれませんので、
他にも良い方法がありましたら教えていただけますと幸いです。
また、初投稿で書き方もあまりわからなかったのでかなり雑な記事になってしまいました。。。
 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel:ブラウザ上の大量のinput要素に自動的に動作確認用のダミーデータを挿入する方法

はじめに

Laravelに限らず開発をする際において、ブラウザ上で動作確認のテストをすることは重要だと思います。(テストコードを書けという意見もありますが、初心者のうちはテストコードなんて書くのが難しかったりしますので、そこは多めにみてください…)

ブラウザ上で動作確認のテストをする際、大量のinput要素に一個一個手打ちでデータを入れていくのはとても手間がかかり、面倒な作業です。例えば、それが100個のinput要素だったりした時には面倒で面倒で仕方ないと思います。そこで、特定のURLにアクセスすると自動的に動作確認用のダミーデータを挿入する方法を書いていこうと思います。

サンプルコードと解説

今回はサンプルなので実際に使う際は自分なりに変えて使ってみてください。
例えば下記のように、こんなマイグレーションファイルがあったとします。

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('content1');
            $table->string('content2');
            $table->string('content3');
            $table->string('content4');
            $table->string('content5');
            $table->string('content6');
            $table->string('content7');
            $table->string('content8');
            $table->string('content9');
            $table->string('content10');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}

contentを今回は10個用意しました。

さて、次はbladeですが、このように記述します。

@extends('layouts.app')

@section('content')

    <form action="{{ url('/posts/create') }}" method="post">
        @csrf
        @method('POST')

        <label for="content1">content1</label><br>
        <input type="text" name="content1" id="content1" value="{{ old('content1', ($post) ? $post->content1 : '') }}"><br>

        <label for="content2">content2</label><br>
        <input type="text" name="content2" id="content2" value="{{ old('content2', ($post) ? $post->content2 : '') }}"><br>

        <label for="content3">content3</label><br>
        <input type="text" name="content3" id="content3" value="{{ old('content3', ($post) ? $post->content3 : '') }}"><br>

        <label for="content4">content4</label><br>
        <input type="text" name="content4" id="content4" value="{{ old('content4', ($post) ? $post->content4 : '') }}"><br>

        <label for="content5">content5</label><br>
        <input type="text" name="content5" id="content5" value="{{ old('content5', ($post) ? $post->content5 : '') }}"><br>

        <label for="content6">content6</label><br>
        <input type="text" name="content6" id="content6" value="{{ old('content6', ($post) ? $post->content6 : '') }}"><br>

        <label for="content7">content7</label><br>
        <input type="text" name="content7" id="content7" value="{{ old('content7', ($post) ? $post->content7 : '') }}"><br>

        <label for="content8">content8</label><br>
        <input type="text" name="content8" id="content8" value="{{ old('content8', ($post) ? $post->content8 : '') }}"><br>

        <label for="content9">content9</label><br>
        <input type="text" name="content9" id="content9" value="{{ old('content9', ($post) ? $post->content9 : '') }}"><br>

        <label for="content10">content10</label><br>
        <input type="text" name="content10" id="content10" value="{{ old('content10', ($post) ? $post->content10 : '') }}"><br>

        <input type="submit" value="送信">
    </form>

@endsection

続いて、web.phpも書いていきます。

Route::get('/', 'PostsController@index');
Route::get('/posts/create/{type?}', 'PostsController@create');
Route::post('/posts/create', 'PostsController@store');

2行目に書いてある/posts/create/{type?}が今回重要になってきます。{type?}はLaravelの任意パラメータというものになります。詳しくはドキュメントを参考にしてください。

このように記述し、アプリ名/posts/createにアクセスすると、下のようなフォームができていると思います。
image.png

フォームができていることを確認したら次はコントローラーを記述していきます。
今回はサンプルで作ったのでバリデーションなどは書いていません。適宜、自分のサービスに合わせてバリデーションを書いてください。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Post;

class PostsController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $posts = Post::all();

        return view('posts.index',[
            'posts' => $posts,
        ]);
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create($type = null)
    {   
        $post = [];

        if(!is_null($type)){
            $post = new Post;
            $dummy_data = config('form_dummy_data');
            if(array_key_exists($type, $dummy_data)){
                foreach($dummy_data[$type] as $_key => $_val){
                    $post->$_key = $_val;
                }
            }
        }

        return view('posts.create',[
            'post' => $post,
        ]);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $post = new Post;
        $post->content1 = $request->content1;
        $post->content2 = $request->content2;
        $post->content3 = $request->content3;
        $post->content4 = $request->content4;
        $post->content5 = $request->content5;
        $post->content6 = $request->content6;
        $post->content7 = $request->content7;
        $post->content8 = $request->content8;
        $post->content9 = $request->content9;
        $post->content10 = $request->content10;
        $post->save();

        return redirect('/');
    }
}

ここで重要になるのはcreateメソッドです。一部抜粋します。

public function create($type = null)
    {   
        $post = [];

        if(!is_null($type)){
            $post = new Post;
            $dummy_data = config('form_dummy_data');
            if(array_key_exists($type, $dummy_data)){
                foreach($dummy_data[$type] as $_key => $_val){
                    $post->$_key = $_val;
                }
            }
        }

        return view('posts.create',[
            'post' => $post,
        ]);
    }

ダミーデータをconfigから呼んでいます。
では、そのダミーデータをconfigディレクトリにファイルを作成して、記述しましょう。
この時に使うファイル名は上で書いたform_dummy_data.phpとします。

<?php

return [
    // バリデーションを通過する入力データ
    'post_create_true' => [
        'content1'  =>  'content1',
        'content2'  =>  'content2',
        'content3'  =>  'content3',
        'content4'  =>  'content4',
        'content5'  =>  'content5',
        'content6'  =>  'content6',
        'content7'  =>  'content7',
        'content8'  =>  'content8',
        'content9'  =>  'content9',
        'content10' =>  'content10',
    ],

    // バリデーションを通過しない入力データ
    'post_create_false' => [
        'content1'  =>  'content1',
        'content2'  =>  'content2',
        'content3'  =>  'content3',
        'content4'  =>  'content4',
        'content5'  =>  'content5',
        'content6'  =>  'content6',
        'content7'  =>  'content7',
        'content8'  =>  'content8',
        'content9'  =>  'content9',
        'content10' =>  'content10',
    ]
];

trueとfalseで分けているのは、コメントの通り、バリデーションを通すデータと通さないデータに分けているからです。

これでいったん完成なのですが、それでは今度は、アプリ名/posts/create/post_create_trueか、アプリ名/posts/create/post_create_falseにアクセスしてみてください。フォームに自動的にデータが挿入された状態になっていると思います。
image.png

最後に

ブラウザ上で大量のinput要素に自動的にダミーデータを挿入する方法を書きました。
本来ならテストコードを書くべきなのですが、冒頭にも述べた通り、初心者には難しかったり、テストを書く時間がない場合など様々な場面で使えると思います。
ダミーデータも自分のサービスに合わせて作り変えたりして活用してみてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelのDockerでX-debugを有効にする

Enable X-debug on Docker for Laravel


始める前に

dockerを使用してx-debugを設定するさまざまな方法に関するチュートリアルがたくさんあります。一部は時代遅れで、一部は他のテクニックを使用します。

Before starting

There are a lot of tutorials on different ways to configure x-debug using docker, some are outdated, some use other techniques, this tutorial is on the configuration that works for me, but I don´t guarantee that it will work for you.


APIの作成方法の前のチュートリアルに従ってください

Follow previous tutorial on how to make an API

nginx.confを編集します

nginx.confファイルにはserver_nameが必要です

the nginx.conf file needs a server_name

server {
  listen 80;
  server_name localhost;
Dockerfileを編集

Dockerfileを編集して、x-debugプラグインのインストールを追加し、docker-pluginを有効にします

Edit the Dockerfile to add x-debug plugin install and enable the docker-plugin

RUN pecl install xdebug && docker-php-ext-enable xdebug

#COPY xdebug.ini /etc/php/7.3/mods-available/xdebug.ini
RUN echo "xdebug.remote_enable=1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
     && echo "xdebug.remote_autostart=1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
     && echo "xdebug.remote_connect_back = 1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
     && echo "xdebug.profiler_enable = 1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini \
     && echo "xdebug.remote_port=9000" >>  /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
docker-compose.yml編集

app-serverコンテナ内のdocker-composeファイルでx-debugを有効にします

Enable x-debug on docker-compose file, in the app-server container

services:
  app-server:
    build: .cloud/docker
    image: laravel-api #name of the image
    environment:
      PHP_XDEBUG_ENABLED: 1
    depends_on:
PHP Stormを構成する

PHP設定内で、プロパティを次のように設定します。

Inside the PHP settings, set the properties as follow

サーバーをセットアップする

右上のメニューから新しい構成をセットアップします

Setup a new configuration, from the upper right menu

次のウィンドウで、セットアップ新しいPHPのウェブサイト、左上隅からの+記号をクリックして、

In the next window, setup a new PHP web site, by clickin the + sign from the upper left corner

サーバーリストから[...]ボタンをクリックして、新しいサーバーを作成します。

create a new server, by clicking the [...] button from the server list.

localhostアドレスを追加し、プロジェクトをdockerサーバー(この場合は/ applicationディレクトリ)にマップします。

Add the localhost address, and map the project to the docker server, in our case, the /application directory.

これにより、PHPStormで受信したリクエストをデバッグできます。

With this, you will be able to debug incoming request on PHPStorm.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelの認証処理に独自の制約を追加する

ログインするときにパスワードによる認証だけでなく、独自の制約を追加したい場合があると思います。
例えばユーザが仮登録ではない場合(本登録)のみログインとか、ある権限を有する場合のみログインなどです。
よくある話なので実装も何回か経験していますが、毎回調べながらなので今回記事としてまとめてみました。
とはいってもLaravelのバージョンによって認証周りは結構違うんですよね。
今回試すのはLaravel 6.12.0です(もう12!!)。

https://laravel.com/docs/6.x/authentication
https://readouble.com/laravel/6.x/ja/authentication.html

準備

$ composer create-project --prefer-dist laravel/laravel auth-sample
$ cd auth-sample
$ composer require laravel/ui --dev
$ php artisan ui vue --auth
$ php artisan make:migration alter_table_users_add_column_disabled --table=users
$ php artisan migrate
$ yarn install
$ yarn run dev
$ php artisan serve
database/migrations/alter_table_users_add_column_disabled.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AlterTableUsersAddColumnDisabled extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->tinyInteger('disabled')->default(0)->after('remember_token');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('disabled');
        });
    }
}

スクリーンショット 2020-01-22 15.46.55.png

今回の認証の仕様

単純にデフォルトの認証ならば、メールアドレスとパスワードのみでログイン出来ます。
そこに今回はdisabledフラグを追加して、disabled = 0ならばログインという仕様とします。
どうすれば認証処理で新たな制約を加えることが出来るのか。

認証のテスト

まずはテストを書いてみます。

$ php artisan make:test LoginTest
tests/Feature/LoginTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class LoginTest extends TestCase
{
    use RefreshDatabase;

    /**
     * 間違ったパスワードのログイン失敗のテスト
     *
     * @return void
     */
    public function testInvalidPasswordLogin()
    {
        $user = factory(\App\User::class)->create(['email' => 'dummy@test.jp', 'disabled' => 0]);

        $response = $this->get('/login');

        $response->assertStatus(200);

        $response = $this->post('/login', ['email' => 'dummy@test.jp', 'password' => 'dummy']);

        $response->assertStatus(302);
        $response->assertRedirect('/login'); // 認証不可なのでログイン画面にリダイレクト
        $this->assertFalse($this->isAuthenticated('web'));
    }

    /**
     * ログイン成功のテスト
     *
     * @return void
     */
    public function testLogin()
    {
        $user = factory(\App\User::class)->create(['email' => 'enable@test.jp', 'disabled' => 0]);

        $response = $this->post('/login', ['email' => 'enable@test.jp', 'password' => 'password']);

        $response->assertStatus(302);
        $response->assertRedirect('/home');
        $this->assertAuthenticatedAs($user, $guard = 'web');
    }

    /**
     * disabled = 1 のログイン失敗のテスト
     *
     * @return void
     */
    public function testDisableLogin()
    {
        $user = factory(\App\User::class)->create(['email' => 'disable@test.jp', 'disabled' => 1]);

        $response = $this->get('/login');

        $response->assertStatus(200);

        $response = $this->post('/login', ['email' => 'disable@test.jp', 'password' => 'password']);

        $response->assertStatus(302);
        $response->assertRedirect('/login'); // 認証不可なのでログイン画面にリダイレクト
        $this->assertFalse($this->isAuthenticated('web'));
    }
}
$ vendor/bin/phpunit tests/Feature/LoginTest.php 
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

..F                                                                 3 / 3 (100%)

Time: 326 ms, Memory: 24.00 MB

There was 1 failure:

1) Tests\Feature\LoginTest::testDisableLogin
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'http://localhost/login'
+'http://localhost/home'

/Users/takahashikiyoshi/dev/valet/auth-sample/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:259
/Users/takahashikiyoshi/dev/valet/auth-sample/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:204
/Users/takahashikiyoshi/dev/valet/auth-sample/tests/Feature/LoginTest.php:65

FAILURES!
Tests: 3, Assertions: 15, Failures: 1.

disabled = 1のユーザが、認証不可で/loginにリダイレクトされなければいけないところを、正常にログインして/homeにリダイレクトされています。
このテストが成功するように修正していきます。

認証処理のソースコードを追う

ログインのソースコードを追ってみましょう。

LoginController

app/Http/Controllers/Auth/LoginController.php
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }
}

ログインのコントローラではAuthenticatesUsersトレイトが使われていますね。

AuthenticatesUsers

vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php
<?php

namespace Illuminate\Foundation\Auth;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;

trait AuthenticatesUsers
{
    use RedirectsUsers, ThrottlesLogins;

    /**
     * Show the application's login form.
     *
     * @return \Illuminate\Http\Response
     */
    public function showLoginForm()
    {
        return view('auth.login');
    }

    /**
     * Handle a login request to the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    public function login(Request $request)
    {
        $this->validateLogin($request);

        // If the class is using the ThrottlesLogins trait, we can automatically throttle
        // the login attempts for this application. We'll key this by the username and
        // the IP address of the client making these requests into this application.
        if (method_exists($this, 'hasTooManyLoginAttempts') &&
            $this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);

            return $this->sendLockoutResponse($request);
        }

        if ($this->attemptLogin($request)) {
            return $this->sendLoginResponse($request);
        }

        // If the login attempt was unsuccessful we will increment the number of attempts
        // to login and redirect the user back to the login form. Of course, when this
        // user surpasses their maximum number of attempts they will get locked out.
        $this->incrementLoginAttempts($request);

        return $this->sendFailedLoginResponse($request);
    }

    /**
     * Validate the user login request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return void
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    protected function validateLogin(Request $request)
    {
        $request->validate([
            $this->username() => 'required|string',
            'password' => 'required|string',
        ]);
    }

    /**
     * Attempt to log the user into the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return bool
     */
    protected function attemptLogin(Request $request)
    {
        return $this->guard()->attempt(
            $this->credentials($request), $request->filled('remember')
        );
    }

    /**
     * Get the needed authorization credentials from the request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    protected function credentials(Request $request)
    {
        return $request->only($this->username(), 'password');
    }

    /**
     * Send the response after the user was authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    protected function sendLoginResponse(Request $request)
    {
        $request->session()->regenerate();

        $this->clearLoginAttempts($request);

        return $this->authenticated($request, $this->guard()->user())
                ?: redirect()->intended($this->redirectPath());
    }

    /**
     * The user has been authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  mixed  $user
     * @return mixed
     */
    protected function authenticated(Request $request, $user)
    {
        //
    }

    /**
     * Get the failed login response instance.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    protected function sendFailedLoginResponse(Request $request)
    {
        throw ValidationException::withMessages([
            $this->username() => [trans('auth.failed')],
        ]);
    }

    /**
     * Get the login username to be used by the controller.
     *
     * @return string
     */
    public function username()
    {
        return 'email';
    }

    /**
     * Log the user out of the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function logout(Request $request)
    {
        $this->guard()->logout();

        $request->session()->invalidate();

        $request->session()->regenerateToken();

        return $this->loggedOut($request) ?: redirect('/');
    }

    /**
     * The user has logged out of the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return mixed
     */
    protected function loggedOut(Request $request)
    {
        //
    }

    /**
     * Get the guard to be used during authentication.
     *
     * @return \Illuminate\Contracts\Auth\StatefulGuard
     */
    protected function guard()
    {
        return Auth::guard();
    }
}

login()メソッドの中でattemptLogin()メソッド、Auth::guard()attempt()が呼ばれています。
attempt()を調べたらvendor/laravel/framework/src/Illuminate/Auth/SessionGuard.phpに行き着きました。
認証のガードやプロバイダは、config/auth.phpに記述されていますが、これがいまひとつ自分は理解出来ていません:cry:

SessionGuard

vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php
<?php

namespace Illuminate\Auth;

class SessionGuard implements StatefulGuard, SupportsBasicAuth
{

    // 省略

    /**
     * Attempt to authenticate a user using the given credentials.
     *
     * @param  array  $credentials
     * @param  bool  $remember
     * @return bool
     */
    public function attempt(array $credentials = [], $remember = false)
    {
        $this->fireAttemptEvent($credentials, $remember);

        $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);

        // If an implementation of UserInterface was returned, we'll ask the provider
        // to validate the user against the given credentials, and if they are in
        // fact valid we'll log the users into the application and return true.
        if ($this->hasValidCredentials($user, $credentials)) {
            $this->login($user, $remember);

            return true;
        }

        // If the authentication attempt fails we will fire an event so that the user
        // may be notified of any suspicious attempts to access their account from
        // an unrecognized user. A developer may listen to this event as needed.
        $this->fireFailedEvent($user, $credentials);

        return false;
    }

    // 省略
}

retrieveByCredentials()で認証情報からユーザを取得しています。
次に出てくるのが、Eloquentを使っているならvendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.phpです。

EloquentUserProvider

vendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.php
<?php

namespace Illuminate\Auth;

class EloquentUserProvider implements UserProvider
{

    // 省略

    /**
     * Retrieve a user by the given credentials.
     *
     * @param  array  $credentials
     * @return \Illuminate\Contracts\Auth\Authenticatable|null
     */
    public function retrieveByCredentials(array $credentials)
    {
        if (empty($credentials) ||
           (count($credentials) === 1 &&
            array_key_exists('password', $credentials))) {
            return;
        }

        // First we will add each credential element to the query as a where clause.
        // Then we can execute the query and, if we found a user, return it in a
        // Eloquent User "model" that will be utilized by the Guard instances.
        $query = $this->newModelQuery();

        foreach ($credentials as $key => $value) {
            if (Str::contains($key, 'password')) {
                continue;
            }

            if (is_array($value) || $value instanceof Arrayable) {
                $query->whereIn($key, $value);
            } else {
                $query->where($key, $value);
            }
        }

        return $query->first();
    }

    // 省略
}

よく知られているように?、Laravelの認証では、まずパスワード以外の情報でユーザを取得してきてから、パスワードをチェックします。
ということは、retrieveByCredentials(array $credentials)$credentialsdisabled = 0の条件を渡せればいいわけです。
遡って$credentialsはどう取得されるかというと、AuthenticatesUsersトレイトのcredentials()メソッドで取得されています。
しかし、

    /**
     * Get the needed authorization credentials from the request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    protected function credentials(Request $request)
    {
        return $request->only($this->username(), 'password');
    }

username()で定義された項目(デフォルトではメールアドレス)とパスワードしか返さない実装となっています。
ここをコントローラでオーバーライドすればいいのでは!?

修正後LoginController

app/Http/Controllers/Auth/LoginController.php
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    /**
     * Get the needed authorization credentials from the request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    protected function credentials(Request $request)
    {
        $credentials = $request->only($this->username(), 'password');
        $credentials['disabled'] = 0;
        return $credentials;
    }
}

はたして、、、

$ vendor/bin/phpunit tests/Feature/LoginTest.php 
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

...                                                                 3 / 3 (100%)

Time: 283 ms, Memory: 24.00 MB

OK (3 tests, 16 assertions)

成功しました:beer:

まとめ

今回はapp/Http/Controllers/Auth/LoginController.phpの修正だけで出来ました。
公式ドキュメントにはガードとプロバイダを使った独自の認証について書かれていますが、難しい。。。
なので、つい今回みたいな小手先の修正となってしまいます。
シンプルな仕様ならLaravelは超簡単ですが、複雑なシステムを作ろうとすると奥が深いですね。。(それはどれも同じでは^^;)

参考URL

https://qiita.com/tomoeine/items/40a966bf3801633cf90f

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel カスタムバリデーション導入

はじめに

  • Laravel ではバリデーションの機能がある。
  • デフォルトでもそれなりに使えるけど、カスタムした方が使える時もままある
  • ちょっと分からなくて調べたりしたのでそれを記述する

前提

laravel のバージョン

$ php artisan -V
Laravel Framework 5.8.16

使いたい

①カスタムバリデーションの作成をする

  • Validation のクラスを作成する。
  • 今回は、場所はapp/Services/ に作成する
  • メソッド名は validateの後ろにオリジナルの名前。この名前がバリデーションの名前になる。
  • 下記のメソッドは、半角英数字とスペースを許可するってこと。多分。
app/Services/CustomValidator.php
<?php

namespace App\Services;

class CustomValidator extends \Illuminate\Validation\Validator
{
    public function validateAlphanumeric($attribute, $value)
    {
        return (preg_match("/^[a-z0-9 ]+$/i", $value));
    }
}

② 呼び出せるようにサービスプロパイダーで有効にする

  • クラスを作ったままだと呼べないので、サービスプロパイダーという場所に登録する
  • AppServiceProvider に登録を行う
app/ServiceProviders/AppServiceProvider.php
<?php

namespace App\ServiceProviders;

use Illuminate\Support\ServiceProvider;

use App\Services\CustomValidator;   // 自分で作成したValidationのクラス

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        // 自分で作成した Validation のクラス
        \Validator::resolver(function($translator, $data, $rules, $messages) {
            return new CustomValidator($translator, $data, $rules, $messages);
        });
    }

③フォーム単位?で使いたい。

  • コントローラで呼び出せるように Request クラスを生成して、割り当てていく。
  • 下記のコマンドで app/Http/Requests/TestRequest.php を作成する
$ php artisan make:request TestRequest
  • 作成した Request クラスを編集して、バリデーションをはめてく
  • バリデーションの名前は validate を抜いた名前でスネークケースにした名前にする
app/Http/Requests/TestRequest.php
<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class TestRequest extends Request
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            // 自分で作成したカスタムバリデーションの名前を name = "test_box" の
            // テキストボックスに当てはめる
            'test_box' => 'alpha_numeric',   
        ];
    }
}
  • コントローラ側でも使えるようにしていく
app/Http/Controllers/TestControllers.php
<?php

namespace App\Http\Controllers\Test;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

use App\Http\Request\TestRequest;   // 作成した Request のクラスを使う

class TestController extends Controller
{
    // 作成した Request クラスを使う
    public function showForm(TestRequest $request)
    {
        処理を色々省略
        return view('test.form');
    }
}

④バリデーションエラーの時のメッセージを多言語化

  • バリデーションのエラーメッセージを多言語化できる。
  • /resources/lang/ja の下に validation.php を作成で日本語ファイル
  • /resources/lang/en の下に validation.php を作成で英語ファイル
/resources/lang/ja/validation.php
<?php

return [

    'alpha_numeric'  => '半角英数字または半角スペース以外は登録できません',
];
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】SendGridのWeb APIを利用してメール送信を実装

実装手順

SendGridでの設定は省略します。

  1. .envにトークンを設定
  2. ライブラリをインストール
  3. githubのサンプルコードで仮実装
  4. 処理を分ける
  5. テンプレートを用意する。

.envにトークンを設定

.env
SENDGRID_API_KEY=<SndGridで取得したトークン>

ライブラリをインストール

composer require sendgrid/sendgrid

githubのサンプルコードで仮実装

とりあえず、サンプルコードを動かしてみます。
必要なものをuseして、適当なメソッドに貼り付けます。
ルーティングの設定を忘れずに。

TestMailController.php
(省略)

use SendGrid;
use SendGrid\Mail\Mail;

(省略)

public function send(Mail $email)
{
    $email->setFrom("test@<登録したドメイン>", "Example User"); // 送信元
    $email->setSubject("Sending with Twilio SendGrid is Fun"); // タイトル
    $email->addTo("<受け取れるメールアドレス>", "Example User"); // 送信先
    $email->addContent("text/plain", "and easy to do anywhere, even with PHP"); // プレーンテキストメール
    $email->addContent(
        "text/html", "<strong>and easy to do anywhere, even with PHP</strong>"  // HTMLメール
    );

    $sendgrid = new SendGrid(env('SENDGRID_API_KEY'));

    try {
        $response = $sendgrid->send($email);
        print $response->statusCode() . "\n";
        print_r($response->headers());
        print $response->body() . "\n";
    } catch (Exception $e) {
        echo 'Caught exception: '. $e->getMessage() ."\n";
    }
}

送信が完了したら、202から始まるテキストが表示されます。

処理を分ける

SendGrid以外のサービスを利用することになった場合でも、少ない修正で済むようにする!
ということまではしていません。あしからず。

まずは、$sendgrid = new SendGrid(env('SENDGRID_API_KEY'));の部分をDIできるように、バインディングします。
以下のように登録することで、引数にトークンが渡された状態でDIされます。

AppServiceProvider.php
use SendGrid;

(省略)

public function register()
{
    $this->app->bind('SendGrid', function ($app) {
        return new SendGrid(env('SENDGRID_API_KEY'));
    });
}

というわけで、TestMailControllerを以下の通り修正

TestMailController.php
public function send(Mail $email, SendGrid $sendgrid) // <-追記
{
    // $sendgrid = new SendGrid(env('SENDGRID_API_KEY')); <-この記述がいらなくなる。
}

次に、メール構築部分の処理を分離していきます。
app/Mail/TestMail.phpを作成し、そのコンストラクターでメールを構築するようにします。

app/Mail/TestMail.php
<?php

namespace App\Mail;

use SendGrid\Mail\Mail;

class TestMail extends Mail // SendGrid\Mail\Mailを継承
{
    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($args)
    {
        $this->setFrom("test@<登録したドメイン>", "Example User");
        $this->setSubject($args->message);
        $this->addTo($args->to, "Example User");
        $this->addContent("text/plain", "and easy to do anywhere, even with PHP");
        $this->addContent(
            "text/html", "<strong>and easy to do anywhere, even with PHP</strong>"
        );

        return $this;
    }
}

TestMailControllerを以下の通り修正

TestMailController.php
(省略)

use SendGrid;
use SendGrid\Mail\Mail;
use App\Mail\TestMail; // 追記

(省略)

public function send(Mail $email, SendGrid $sendgrid)
{
    try {
        $response = $sendgrid->send(new TestMail($this->args));

        $message = 'メールを送信しました。'); // ついでに修正
    } catch (Exception $e) {
        report($e); // ついでに修正
        $message = 'メール送信に失敗しました。'); // ついでに修正
    }

    return redirect()->back()->with('flash_message', $message); // ついでに修正
}

テンプレートを用意する。

次にBladeテンプレートを用意して、それを利用するようにします。
(以下は、プレーンテキスト用のテンプレートです。)

views/emails/test_mail.blade.php
テストメールテンプレート
変数{{ $hoge }}{{ $fuga }}も渡せます。

テンプレートを利用するには、viewインスタンスを文字列にキャストしたものを、
addContentに渡せばOKです。

app/Mail/TestMail.php
<?php

namespace App\Mail;

use SendGrid\Mail\Mail;

class TestMail extends Mail // SendGrid\Mail\Mailを継承
{
    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($args)
    {
        $hoge = 'hoge';
        $fuga = 'fuga';

        $this->setFrom("test@<登録したドメイン>", "Example User");
        $this->setSubject($args->message);
        $this->addTo($args->to, "Example User");
        $this->addContent(
            "text/plain",
            strval(view('emails.test_mail', compact('hoge', 'fuga'))) // viewインスタンスを文字列にキャスト
        );

        // $this->addContent(
        //     "text/html", "<strong>and easy to do anywhere, even with PHP</strong>"
        // );

        return $this;
    }
}

複数のメールアドレスに対して送信する場合は、addTosメソッドを利用すればいいようです。
Send an Email to Multiple Recipients

$tos = [ 
    "test+test1@example.com" => "Example User1",
    "test+test2@example.com" => "Example User2",
    "test+test3@example.com" => "Example User3"
];
$email->addTos($tos);

この場合、toに複数のアドレスを書き込んでいる状態なので、受信者は全てのメールアドレスを見れてしまいますので、気をつけてください。
マーケティングメールなどを送るときは、メールアドレス分ループさせるのが良さそうです。

以上です。

参考

https://github.com/sendgrid/sendgrid-php#usage

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】SendGrid Web APIを利用してメールを送信する

実装手順

SendGridでの設定は省略します。

  1. .envにトークンを設定
  2. ライブラリをインストール
  3. githubのサンプルコードで仮実装
  4. 処理を分ける
  5. テンプレートを用意する。

.envにトークンを設定

.env
SENDGRID_API_KEY=<SndGridで取得したトークン>

ライブラリをインストール

composer require sendgrid/sendgrid

githubのサンプルコードで仮実装

とりあえず、サンプルコードを動かしてみます。
必要なものをuseして、適当なメソッドに貼り付けます。
ルーティングの設定を忘れずに。

TestMailController.php
(省略)

use SendGrid;
use SendGrid\Mail\Mail;

(省略)

public function send(Mail $email)
{
    $email->setFrom("test@<登録したドメイン>", "Example User"); // 送信元
    $email->setSubject("Sending with Twilio SendGrid is Fun"); // タイトル
    $email->addTo("<受け取れるメールアドレス>", "Example User"); // 送信先
    $email->addContent("text/plain", "and easy to do anywhere, even with PHP"); // プレーンテキストメール
    $email->addContent(
        "text/html", "<strong>and easy to do anywhere, even with PHP</strong>"  // HTMLメール
    );

    $sendgrid = new SendGrid(env('SENDGRID_API_KEY'));

    try {
        $response = $sendgrid->send($email);
        print $response->statusCode() . "\n";
        print_r($response->headers());
        print $response->body() . "\n";
    } catch (Exception $e) {
        echo 'Caught exception: '. $e->getMessage() ."\n";
    }
}

送信が完了したら、202から始まるテキストが表示されます。

処理を分ける

SendGrid以外のサービスを利用することになった場合でも、少ない修正で済むようにする!
ということまではしていません。あしからず。

まずは、$sendgrid = new SendGrid(env('SENDGRID_API_KEY'));の部分をDIできるように、バインディングします。
以下のように登録することで、引数にトークンが渡された状態でDIされます。

AppServiceProvider.php
use SendGrid;

(省略)

public function register()
{
    $this->app->bind('SendGrid', function ($app) {
        return new SendGrid(env('SENDGRID_API_KEY'));
    });
}

というわけで、TestMailControllerを以下の通り修正

TestMailController.php
public function send(Mail $email, SendGrid $sendgrid) // <-追記
{
    // $sendgrid = new SendGrid(env('SENDGRID_API_KEY')); <-この記述がいらなくなる。
}

次に、メール構築部分の処理を分離していきます。
app/Mail/TestMail.phpを作成し、そのコンストラクターでメールを構築するようにします。

app/Mail/TestMail.php
<?php

namespace App\Mail;

use SendGrid\Mail\Mail;

class TestMail extends Mail // SendGrid\Mail\Mailを継承
{
    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($args)
    {
        $this->setFrom("test@<登録したドメイン>", "Example User");
        $this->setSubject($args->message);
        $this->addTo($args->to, "Example User");
        $this->addContent("text/plain", "and easy to do anywhere, even with PHP");
        $this->addContent(
            "text/html", "<strong>and easy to do anywhere, even with PHP</strong>"
        );

        return $this;
    }
}

TestMailControllerを以下の通り修正

TestMailController.php
(省略)

use SendGrid;
use SendGrid\Mail\Mail;
use App\Mail\TestMail; // 追記

(省略)

public function send(Mail $email, SendGrid $sendgrid)
{
    try {
        $response = $sendgrid->send(new TestMail($this->args));

        $message = 'メールを送信しました。'); // ついでに修正
    } catch (Exception $e) {
        report($e); // ついでに修正
        $message = 'メール送信に失敗しました。'); // ついでに修正
    }

    return redirect()->back()->with('flash_message', $message); // ついでに修正
}

テンプレートを用意する。

次にBladeテンプレートを用意して、それを利用するようにします。
(以下は、プレーンテキスト用のテンプレートです。)

views/emails/test_mail.blade.php
テストメールテンプレート
変数{{ $hoge }}{{ $fuga }}も渡せます。

テンプレートを利用するには、viewインスタンスを文字列にキャストしたものを、
addContentに渡せばOKです。

app/Mail/TestMail.php
<?php

namespace App\Mail;

use SendGrid\Mail\Mail;

class TestMail extends Mail // SendGrid\Mail\Mailを継承
{
    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($args)
    {
        $hoge = 'hoge';
        $fuga = 'fuga';

        $this->setFrom("test@<登録したドメイン>", "Example User");
        $this->setSubject($args->message);
        $this->addTo($args->to, "Example User");
        $this->addContent(
            "text/plain",
            strval(view('emails.test_mail', compact('hoge', 'fuga'))) // viewインスタンスを文字列にキャスト
        );

        // $this->addContent(
        //     "text/html", "<strong>and easy to do anywhere, even with PHP</strong>"
        // );

        return $this;
    }
}

複数のメールアドレスに対して送信する場合は、addTosメソッドを利用すればいいようで。
Send an Email to Multiple Recipients

$tos = [ 
    "test+test1@example.com" => "Example User1",
    "test+test2@example.com" => "Example User2",
    "test+test3@example.com" => "Example User3"
];
$email->addTos($tos);

以上です。

参考

https://github.com/sendgrid/sendgrid-php#usage

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelでCSVダウンロード機能を実装する。

CSVダウンロード機能を実装するにあたり、少しはまった部分があったので備忘録です。

流れ

  1. 出力データを用意
  2. 出力データをカンマ区切りで配列にセット
  3. 改行区切りの文字列に変換
  4. 一時的にCSVファイルを作成
  5. CSVファイルに書き込み
  6. ダウンロードレスポンスを返す。

実装

はまったポイント
- 金額など、値にカンマが含まれる文字の扱い -> 値をクオートで囲むことで1つの値として評価される。
- 出力結果が改行されnai -> 改行コードをダブルコートで囲むことで改行コードとして評価される。
- Excelで開いたときに文字化けする -> SJISにエンコーディングする。

public function downloadCsv()
{
    // 1. 出力データをを用意
    $csvHeader = ["No,", 師匠名, ふりがな];
    $csvData = [
        [0001, 春風亭助羊, しゅんぷうてい すけよう],
        [0002, 桂左志郎, かつら さしろう],
        [0003, 三遊亭遊智, さんゆうてい ゆうち],
        [0004, 月亭がた枝, つきてい がたし],
        [0005, 春雨や雷扇, はるさめや らいおう],
        [0006, 桂喜八宝, かつら きゃぽう],
        [0007, 翁家八ゑ千代, おきなや やえちよ],
        [0008, 春雨や雷海, はるさめや らいかい],
    ];

    // 2. 出力データをカンマ区切りで配列にセット
    $downloadData = [];
    $downloadData[] = implode(',', $csvHeader);

    foreach ($csvData as $record) {
        // 念の為ダブルクオートで囲む
        foreach ($record as $i => $v) {
            $record[$i] = '"' . $v . '"';
        }

        $downloadData[] = implode(',', $record);
    }

    // 3. 改行区切りの文字列に変換
    $downloadData = implode("\r", $downloadData); // 改行コードはダブルクオートで囲む

    // Excel対応
    $downloadData = mb_convert_encoding($downloadData, "SJIS", "UTF-8");

    // 4. 一時的にcsvファイルを作成
    if (! file_exists(storage_path('csv'))) {
        $bool = mkdir(storage_path('csv'));

        if (! $bool) {
            throw new Exception("ディレクトリを作成できませんでした。", 500);
        }
    }
    $name = 'test.csv';
    $pathToFile = storage_path('csv/' . $name);

    // 5. CSVファイルを作成
    if (! file_put_contents($pathToFile, $csvData)) {
        throw new Exception("ファイルの書き込みに失敗しました。", 500);
    }

    // 6. ダウンロードレスポンスを返却
    return response()->download($pathToFile, $name)->deleteFileAfterSend(true);
}

参考

https://gray-code.com/php/download-for-csv-file/
https://teratail.com/questions/2199
https://bayashita.com/p/entry/show/49
https://qiita.com/ikemonn/items/f2bc4f9f834c989084ff
https://www.megasoft.co.jp/support/mifes/faq/miw8faq/faq017.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

システムからメール送信するときのメール配信サービスを列挙

システムからメール送信をするため、メール配信サービスを調査したので列挙します。

当初は、Amazon SESの利用を検討していましたが、
バウンスメールの処理を独自実装しないといけないため、
他のサービスを検討することとなりました。

AWSのSESでバウンスメール(bouncemail)対策。3つの方法とメリット・デメリット
AWS SESでバウンスメールをハンドリングしてみた

ちなみにLaravelドキュメントで触れられているサービスは、
バージョンによって地味に変わっています。

5.7

MailgunとSparkPostなどAPIベースドライバはシンプルでSMTPサーバよりも高速です。

5.8

MailgunとSparkPost、Postmarkなど、APIベースドライバはシンプルでSMTPサーバよりも高速です。

6.x

MailgunとPostmarkなど、APIベースドライバはシンプルでSMTPサーバよりも高速です。

Mailgun

いますぐ使う Mailgun

以下の理由で却下

  • RFC準拠していないメドに容赦ない
  • 単純にAmazon SESの4倍くらい高価

Postmark

このサービスは、トランザクションメールにのみ利用できるというポリシーのようで、今回のメール配信内容としてはマーケティングメールに当たるため、却下

トランザクションメールとマーケティングメールの違いとは?

SendGrid

今回はSendGridで要望を満たせたため、こちらを採用しました。

  • マーケティングメールでも利用可能
  • バウンス処理をしてくれる
  • 無料枠が大きい(12,000通/月)

https://sendgrid.kke.co.jp/plan/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む