メモ > 技術 > フレームワーク: Laravel6 > Laravelでプログラム作成
Laravelでプログラム作成
■言語ファイルを配置
$ cd /var/www/main
$ php -r "copy('https://readouble.com/laravel/6.x/ja/install-ja-lang-files.php', 'install-ja-lang.php');"
$ php -f install-ja-lang.php
$ php -r "unlink('install-ja-lang.php');"
validation.php言語ファイル 6.x Laravel
https://readouble.com/laravel/6.x/ja/validation-php.html
■タイムゾーンとロケールを変更
config/app.php でタイムゾーンとロケールを変更
'timezone' => 'Asia/Tokyo',
'locale' => 'ja',
設定 6.x Laravel
https://readouble.com/laravel/6.x/ja/configuration.html
■デフォルトのマイグレーションを調整
※調整内容は一例。案件に合わせて調整する
不要なマイグレーションを削除
database/migrations/2019_08_19_000000_create_failed_jobs_table.php
デフォルトのマイグレーションを調整
database/migrations/2014_10_12_000000_create_users_table.php
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->bigIncrements('id');
$table->string('name')->comment('名前');
$table->string('email')->unique()->comment('メールアドレス');
$table->timestamp('email_verified_at')->nullable()->comment('メールアドレス確認日時');
$table->string('password')->comment('パスワード');
$table->rememberToken()->comment('トークン');
$table->timestamps();
});
DB::statement('ALTER TABLE users COMMENT \'ユーザ\'');
}
database/migrations/2014_10_12_100000_create_password_resets_table.php
public function up()
{
Schema::create('password_resets', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->string('email')->index()->comment('メールアドレス');
$table->string('token')->comment('トークン');
$table->timestamp('created_at')->nullable();
});
DB::statement('ALTER TABLE password_resets COMMENT \'パスワードリセット\'');
}
マイグレーションを実行
$ php artisan migrate
データベース:マイグレーション 6.x Laravel
https://readouble.com/laravel/6.x/ja/migrations.html
■認証機能を作成
ユーザ登録と認証機能を作成する
※「php artisan make:auth」はLaravel6では使えない
※「composer require laravel/ui --dev」もLaravel7が出たからかLaravel6ではエラーになるようになった
$ composer require laravel/ui 1.*
$ php artisan ui vue --auth
画面の右上に「LOGIN」「REGISTER」が表示されていて、ここからログインと登録ができる
この時点ではCSSとJavaScriptがコンパイルされていないので、見た目は質素なものになるが動作はする
認証処理の流れはLaravel5から大きく変わっていないようなので、「Laravel.txt」の「認証」にある処理の流れを参考にする
認証 6.x Laravel
https://readouble.com/laravel/6.x/ja/authentication.html
更新! Laravel6/7「make:Auth」が無くなった 〜Laravel6/7でのLogin機能の実装方法〜MyMemo - Qiita
https://qiita.com/daisu_yamazaki/items/a914a16ca1640334d7a5
Laravel6 ログイン機能を実装する - Qiita
https://qiita.com/ucan-lab/items/bd0d6f6449602072cb87
[PHP]Laravel6でmake:authするには - Qiita
https://qiita.com/kusumoto-t/items/fc6ef3f5bf1dbe5dc579
Laravel 6でユーザー登録機能・ログイン機能を実装する
https://www.no-title.com/programming/laravel/authentication
■CSSとJavaScriptをコンパイルしない代わりにBootstrapを導入
※npmでコンパイルするのが本来の手順だと思われるが、動作しないのでBootstrapで対応する
以下にBootstrapがある。今回はこれを使用する
https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js
https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css
resources/views/layouts/app.blade.php
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Scripts -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" defer></script>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<!-- Styles -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet">
■Userモデルの配置場所を変更
app直下にモデルを大量に作ると管理しづらいので、フォルダにまとめるようにする
Laravelは「モデルの役割と置き場所は自分で決めてくれ」という思想
app/User.php を app/Models/User.php へ移動
namespace App;
↓
namespace App\Models;
それに伴い、以下も調整
config/auth.php
'model' => App\User::class,
↓
'model' => App\Models\User::class,
app/Http/Controllers/Auth/RegisterController.php
use App\User;
↓
use App\Models\User;
■メールの送信
「MAIL_DRIVER=sendmail」での対応だと、ローカルではメール送信にかなりタイムラグがあるみたい
いったんGmailのSMTPで送信してみる
.env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=465
MAIL_USERNAME=xxxxx@gmail.com
MAIL_PASSWORD=xxxxx
MAIL_ENCRYPTION=ssl
パスワードリセット機能でメール送信を試す
メールで以下のようなリンクが送られてきて、ここからリセットできる
http://laravel6.local/password/reset/dc56b315b5cd842e1ae6b888897bf62e8739902d35186fd02d542f942dd6fc0...
■パスワードリセットメールのカスタマイズ
通知クラスを作成
$ php artisan make:notification ResetPasswordNotification
以下にパスワードリセットの実際のクラスがあるので、これを参考に上記クラスを調整する
vendor/laravel/framework/src/Illuminate/Auth/Notifications/ResetPassword.php
完成した ResetPassword.php は以下のとおり。ここではメールの件名のみカスタマイズしている(実際は変数化してconfigなどで管理するといい)
なお、「['text' => 'emails.password_reset']」部分を「'emails.password_reset'」にするとHTMLメールとして送信される
<?php
namespace App\Notifications;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Lang;
class ResetPasswordNotification extends ResetPassword
{
use Queueable;
/**
* Build the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
if (static::$toMailCallback) {
return call_user_func(static::$toMailCallback, $notifiable, $this->token);
}
return (new MailMessage)
/*
->subject(Lang::get('Reset Password Notification'))
->line(Lang::get('You are receiving this email because we received a password reset request for your account.'))
->action(Lang::get('Reset Password'), url(config('app.url').route('password.reset', ['token' => $this->token, 'email' => $notifiable->getEmailForPasswordReset()], false)))
->line(Lang::get('This password reset link will expire in :count minutes.', ['count' => config('auth.passwords.'.config('auth.defaults.passwords').'.expire')]))
->line(Lang::get('If you did not request a password reset, no further action is required.'));
*/
->subject('パスワードリセット通知')
->view(['text' => 'emails.password_reset'], [
'reset_url' => url(config('app.url').route('password.reset', ['token' => $this->token, 'email' => $notifiable->getEmailForPasswordReset()], false))
]);
}
}
メール本文は resources/views/emails/password_reset.blade.php に作成する
文字列に「&」が入るとエスケープされるため、URLをテキストで表示する場合は「!!」を使っておくと無難(この機能に限れば「&」は入らないので問題無いが)
パスワードリセット通知
{!! $reset_url !!}
app/Models/User.php に sendPasswordResetNotification メソッドを追加する
このメソッドの実態は vendor/laravel/framework/src/Illuminate/Auth/Passwords/CanResetPassword.php にある
CanResetPassword クラスは vendor/laravel/framework/src/Illuminate/Foundation/Auth/User.php 経由で呼ばれている
使用するクラスは、上で作成した ResetPasswordNotification にする
use App\Notifications\ResetPasswordNotification;
/**
* Send the password reset notification.
*
* @param string $token
* @return void
*/
public function sendPasswordResetNotification($token)
{
$this->notify(new ResetPasswordNotification($token));
}
パスワードリセットを行い、「パスワードリセット通知」という件名で通知が来ることを確認する
本文も上で指定したものになっていることを確認する
Laravel6.xでパスワードリセットメールをカスタマイズする - Qiita
https://qiita.com/daijin/items/8bc658c9b14cdd15260c
■マイページと編集機能を実装
http://laravel6.local/mypage/ から、マイページにログインできるようにする
app/Http/Controllers/Auth/LoginController.php
app/Http/Controllers/Auth/RegisterController.php
app/Http/Controllers/Auth/ResetPasswordController.php
app/Http/Controllers/Auth/VerificationController.php を編集
protected $redirectTo = '/home';
↓
protected $redirectTo = '/mypage';
app/Http/Middleware/RedirectIfAuthenticated.php を編集
return redirect('/home');
↓
return redirect('/mypage');
app/Http/Controllers/MypageController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Hash;
use App\Http\Controllers\Controller;
use App\Models\User;
class MypageController extends Controller
{
/**
* インスタンス作成
*
* @return void
*/
public function __construct()
{
}
/**
* マイページ
*
* @param Request $request
* @return \Illuminate\Contracts\Support\Renderable
*/
public function index(Request $request)
{
return view('mypage/index');
}
/**
* 基本情報編集画面
*
* @param Request $request
* @return \Illuminate\Contracts\Support\Renderable
*/
public function basis(Request $request)
{
// ユーザー情報取得
$user = Auth::guard()->user();
return view('mypage/basis', [
'user' => $user,
]);
}
/**
* 基本情報編集
*
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function basisUpdate(Request $request)
{
// 入力内容をチェック
$validator = Validator::make($request->all(), [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255'],
'password' => ['nullable', 'string', 'min:8', 'confirmed'],
]);
if ($validator->fails()) {
return redirect('mypage/basis')->withErrors($validator)->withInput();
}
// 編集
$userId = Auth::guard()->user()->id;
$user = User::find($userId);
$user->name = $request->name;
$user->email = $request->email;
if (!empty($request->password)) {
$user->password = Hash::make($request->password);
}
$user->save();
return redirect('mypage/basis')->with('message', '基本情報を編集しました。');
}
}
resources/views/mypage/index.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">マイページ</div>
<div class="card-body">
<ul>
<li><a href="{{ route('mypage.basis') }}">基本情報編集</a></li>
<li><a href="{{ route('logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">ログアウト</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
@endsection
resources/views/mypage/basis.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">基本情報編集</div>
<div class="card-body">
<form method="POST" action="{{ route('mypage.basis.update') }}">
@csrf
@if (session('message'))
<div class="box">
<div class="alert alert-success">
{{ session('message') }}
</div>
</div>
@endif
<div class="form-group row">
<label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>
<div class="col-md-6">
<input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name', $user->name ?? '') }}" required autocomplete="name" autofocus>
@error('name')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email', $user->email ?? '') }}" required autocomplete="email">
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" autocomplete="new-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" autocomplete="new-password">
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Register') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
routes/web.php にルーティングを追加
// 認証後のコンテンツ
Route::group(['middleware' => 'auth'], function () {
// マイページ
Route::group(['as' => 'mypage'], function () {
// マイページ
Route::get('/mypage', 'MypageController@index')->name('.index');
// 基本情報編集画面
Route::get('/mypage/basis', 'MypageController@basis')->name('.basis');
// 基本情報編集
Route::post('/mypage/basis_update', 'MypageController@basisUpdate')->name('.basis.update');
});
});
バリデーション 6.x Laravel
https://readouble.com/laravel/6.x/ja/validation.html
Laravel|【保存版】バリデーションルールのまとめ - わくわくBank
https://www.wakuwakubank.com/posts/376-laravel-validation/
Laravel ログイン中、ログイン画面にアクセスした際のリダイレクト先変更 - Qiita
https://qiita.com/Ioan/items/551d379fe99ffcbd06b4
■マルチ認証
http://laravel6.local/mypage/ のマイページは残しつつ
http://laravel6.local/admin/login から、管理画面にログインできるようにする
database/migrations/2020_04_08_000000_create_admins_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateAdminsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('admins', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->bigIncrements('id');
$table->string('name')->comment('名前');
$table->string('email')->unique()->comment('メールアドレス');
$table->timestamp('email_verified_at')->nullable()->comment('メールアドレス確認日時');
$table->string('password')->comment('パスワード');
$table->rememberToken()->comment('トークン');
$table->timestamps();
});
DB::statement('ALTER TABLE admins COMMENT \'管理者\'');
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('admins');
}
}
database/seeds/AdminsTableSeeder.php
<?php
use Illuminate\Database\Seeder;
class AdminsTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
if (DB::table('admins')->count() > 0) {
return;
}
DB::table('admins')->insert([
'name' => 'admin',
'email' => 'admin@example.com',
'password' => Hash::make('abcd1234'),
'remember_token' => Str::random(10),
]);
}
}
database/seeds/DatabaseSeeder.php
// $this->call(UsersTableSeeder::class);
↓
$this->call(AdminsTableSeeder::class);
マイグレーションとシーダーを実行
Seederを追加した直後に「php artisan db:seed」を実行すると、AdminsTableSeederクラスが見つからないとなった
「composer dump-autoload」を実行すれば解決した
$ composer dump-autoload
$ php artisan migrate
$ php artisan db:seed
main/app/Models/Admin.php
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class Admin extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
config/auth.php にある guards の設定に以下を追加
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
同ファイルにある providers の設定に以下を追加
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
同ファイルにある passwords の設定に以下を追加(テーブルは password_resets 以外にすべきか?要検証)
'admins' => [
'provider' => 'admins',
'table' => 'password_resets',
'expire' => 60,
],
app/Http/Middleware/Authenticate.php に admin 用の分岐を追加
use Illuminate\Support\Facades\Route;
if (! $request->expectsJson()) {
if (Route::is('admin.*')) {
return route('admin.login');
} else {
return route('login');
}
}
app/Http/Middleware/RedirectIfAuthenticated.php に admin 用の分岐を追加
if (Auth::guard($guard)->check() && $guard === 'user') {
return redirect('/mypage');
} elseif (Auth::guard($guard)->check() && $guard === 'admin') {
return redirect('/admin/home');
}
app/Http/Controllers/Admin/HomeController.php
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class HomeController extends Controller
{
public function __construct()
{
$this->middleware('auth:admin');
}
public function index()
{
return view('admin.home');
}
}
app/Http/Controllers/Admin/Auth/LoginController.php
<?php
namespace App\Http\Controllers\Admin\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = '/admin/home';
public function __construct()
{
$this->middleware('guest:admin')->except('logout');
}
protected function guard()
{
return Auth::guard('admin');
}
public function showLoginForm()
{
return view('admin.auth.login');
}
public function logout(Request $request)
{
Auth::guard('admin')->logout();
return $this->loggedOut($request);
}
public function loggedOut(Request $request)
{
return redirect(route('admin.login'));
}
}
resources/views/layouts/admin.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Scripts -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" defer></script>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<!-- Styles -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
{{ config('app.name', 'Laravel') }}
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav mr-auto">
</ul>
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Authentication Links -->
@guest
<li class="nav-item">
<a class="nav-link" href="{{ route('admin.login') }}">{{ __('Login') }}</a>
</li>
@else
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
{{ Auth::user()->name }} <span class="caret"></span>
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ route('admin.logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
{{ __('Logout') }}
</a>
<form id="logout-form" action="{{ route('admin.logout') }}" method="POST" style="display: none;">
@csrf
</form>
</div>
</li>
@endguest
</ul>
</div>
</div>
</nav>
<main class="py-4">
@yield('content')
</main>
</div>
</body>
</html>
resources/views/admin/auth/login.blade.php
@extends('layouts.admin')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Login') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('admin.login') }}">
@csrf
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<div class="col-md-6 offset-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
<label class="form-check-label" for="remember">
{{ __('Remember Me') }}
</label>
</div>
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Login') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
resources/views/admin/home.blade.php
@extends('layouts.admin')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">管理者用ページ</div>
<div class="card-body">
<ul>
<li><a href="{{ route('admin.logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">ログアウト</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
@endsection
routes/web.php に admin 用のルーティングを追加
// 管理者
Route::namespace('Admin')->prefix('admin')->group(function () {
Route::name('admin.')->group(function () {
// ログイン認証関連
Auth::routes([
'register' => false,
'reset' => false,
'verify' => false
]);
});
// 認証後のコンテンツ
Route::middleware('auth:admin')->group(function () {
Route::group(['as' => 'admin'], function () {
// ダッシュボード
Route::get('/home', 'HomeController@index')->name('.home');
});
});
});
Laravel6でマルチ認証を実装する(UserとAdminの階層を分ける) - Qiita
https://qiita.com/namizatop/items/5d56d96d4c255a0e3a87
Laravelマルチ認証でセッション用テーブル、設定を分ける(Laravel6で確認済み) - Qiita
https://qiita.com/lixwork/items/11f7463d6cf35cb46553
Laravel6.7でマルチログインをできる限り自分好みに実装したはなし - Qiita
https://qiita.com/wasipo/items/b06be610bb7ba95954df
Laravel6x マルチ認証(userとadmin)の実装でハマった事|Makoto|note
https://note.com/makoto0419/n/n9d0e1c1dc90d
■バリデーションをリクエストに移行
デフォルトのコードではコントローラ内でバリデーションを行っているが、リクエストクラスにまとめることが推奨されている
ユーザ情報のバリデーションをリクエストクラスにまとめてみる
もともとのユーザ新規登録処理は vendor/laravel/framework/src/Illuminate/Foundation/Auth/RegistersUsers.php にある
一部このファイルの処理を参考にしている
$ php artisan make:request StoreUserRequest
$ php artisan make:request UpdateUserRequest
app/Http/Requests/StoreUserRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
];
}
/**
* バリデーションエラーのカスタム属性の取得
*
* @return array
*/
public function attributes()
{
return [
'name' => '名前',
'email' => 'メールアドレス',
'password' => 'パスワード',
];
}
}
main/app/Http/Requests/UpdateUserRequest.php
<?php
namespace App\Http\Requests;
class UpdateUserRequest extends StoreUserRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
$rules = parent::rules();
$rules['email'] = ['required', 'string', 'email', 'max:255'];
$rules['password'] = ['nullable', 'string', 'min:8', 'confirmed'];
return $rules;
}
}
main/app/Http/Controllers/MypageController.php
use App\Http\Requests\UpdateUserRequest;
/**
* 基本情報編集
*
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function basisUpdate(UpdateUserRequest $request)
{
// 編集
$userId = Auth::guard()->user()->id;
app/Http/Controllers/Auth/RegisterController.php
use App\Http\Requests\StoreUserRequest;
use Illuminate\Auth\Events\Registered;
// validatorメソッドは削除
/**
* Handle a registration request for the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function register(StoreUserRequest $request)
{
event(new Registered($user = $this->create($request->all())));
$this->guard()->login($user);
return $this->registered($request, $user)
?: redirect($this->redirectPath());
}
バリデーション 6.x Laravel
https://readouble.com/laravel/6.x/ja/validation.html
なお、バリデーション時にエラーがあると自動でリダイレクト処理が走るが、場合によってはその処理が邪魔になることがある
これは、StoreUserRequest 内で以下のようにカラの failedValidation を定義することで抑制できるみたい
(未検証)
protected function failedValidation(Validator $validator)
{
}
この場合、コントローラー側で以下のようにしてエラー判定できるみたい
(未検証)
protected function register(StoreUserRequest $request)
{
if ($request->getValidator()->fails()) {
$validator = $request->getValidator();
必要に応じて、この書き方を使用するといいかもしれない
【Laravel】フォームリクエストを使いつつ勝手にリダイレクトさせない - Qiita
https://qiita.com/rana_kualu/items/77134af5477d27bf2cc2
■CRUDを作成
管理画面でユーザ情報の登録編集削除をできるようにする
app/Http/Controllers/Admin/UserController.php
<?php
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Requests\StoreUserRequest;
use App\Http\Requests\UpdateUserRequest;
use App\Models\User;
class UserController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Display a list of all users.
*
* @param Request $request
* @return Response
*/
public function index(Request $request)
{
return view('admin.user.index', [
'users' => User::orderBy('created_at', 'asc')->get()
]);
}
/**
* Display a form of new user.
*
* @param Request $request
* @return Response
*/
public function create(Request $request)
{
return view('admin.user.form');
}
/**
* Create a new user.
*
* @param Request $request
* @return Response
*/
public function store(StoreUserRequest $request)
{
$user = new User;
$user->name = $request->name;
$user->email = $request->email;
$user->password = Hash::make($request->password);
$user->save();
return redirect()->route('admin.user.index')->with('message', '登録しました。');
}
/**
* Display a form of edit user.
*
* @param Request $request
* @return Response
*/
public function edit(Request $request, $id)
{
$user = User::find($id);
return view('admin.user.form', [
'user' => $user,
]);
}
/**
* Update a user.
*
* @param Request $request
* @return Response
*/
public function update(UpdateUserRequest $request, $id)
{
$user = User::find($id);
$user->name = $request->name;
$user->email = $request->email;
if (!empty($request->password)) {
$user->password = Hash::make($request->password);
}
$user->save();
return redirect()->route('admin.user.index')->with('message', '編集しました。');
}
/**
* Destroy the given user.
*
* @param Request $request
* @param string $id
* @return Response
*/
public function destroy(Request $request, $id)
{
User::findOrFail($id)->delete();
return redirect()->route('admin.user.index')->with('message', '削除しました。');
}
}
resources/views/admin/home.blade.php
<div class="card-body">
<ul>
<li><a href="{{ route('admin.home') }}">ホーム</a></li>
<li><a href="{{ route('admin.user.index') }}">ユーザ管理</a></li>
<li><a href="{{ route('admin.logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">ログアウト</a></li>
</ul>
</div>
resources/views/admin/user/index.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">ユーザ一覧</div>
<div class="card-body">
@if (session('message'))
<div class="box">
<div class="alert alert-success">
{{ session('message') }}
</div>
</div>
@endif
<p><a href="{{ route('admin.user.create') }}" class="btn btn-primary">ユーザ登録</a></p>
<table class="table table-striped">
<thead>
<th>名前</th>
<th>メール</th>
<th>編集</th>
<th>削除</th>
</thead>
<tbody>
@foreach ($users as $user)
<tr>
<td class="table-text"><div>{{ $user->name }}</div></td>
<td class="table-text"><div>{{ $user->email }}</div></td>
<td class="table-text"><a href="{{ route('admin.user.edit', ['id' => $user->id]) }}" class="btn btn-primary">Edit</a></td>
<td>
<form action="{{ route('admin.user.delete', ['id' => $user->id]) }}" method="POST">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<button type="submit" class="btn btn-danger">
Delete
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
@endsection
resources/views/admin/user/form.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">ユーザ @if (!Request::is('*/create')) {{ '編集' }} @else {{ '登録' }} @endif</div>
<div class="card-body">
@if (count($errors) > 0)
<div class="alert alert-danger">
@foreach ($errors->all() as $error)
{{ $error }}<br>
@endforeach
</div>
@endif
<form action="{{ Request::is('*/create') ? route('admin.user.create') : route('admin.user.edit', ['id' => $user->id]) }}" method="POST" class="form-horizontal">
@if (!Request::is('*/create'))
{{ method_field('put') }}
@endif
{{ csrf_field() }}
<div class="form-group">
<label for="name" class="col-sm-3 control-label">Name</label>
<div class="col-sm-6">
<input type="text" name="name" id="name" class="form-control" value="{{ old('name', isset($user) ? $user->name : '') }}">
</div>
</div>
<div class="form-group">
<label for="email" class="col-sm-3 control-label">Email</label>
<div class="col-sm-6">
<input type="text" name="email" id="email" class="form-control" value="{{ old('email', isset($user) ? $user->email : '') }}">
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-3 control-label">Password</label>
<div class="col-sm-6">
<input type="password" name="password" id="password" class="form-control" value="{{ old('password') }}">
</div>
</div>
<div class="form-group">
<label for="password-confirm" class="col-sm-3 control-label">Password</label>
<div class="col-sm-6">
<input type="password" name="password_confirmation" id="password-confirm" class="form-control">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="submit" class="btn btn-primary">
<i class="fa fa-btn fa-plus"></i>@if (!Request::is('*/create')) {{ '編集' }} @else {{ '登録' }} @endif
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
routes/web.php
// 管理者
Route::namespace('Admin')->prefix('admin')->group(function () {
Route::name('admin.')->group(function () {
// ログイン認証関連
Auth::routes([
'register' => false,
'reset' => false,
'verify' => false
]);
});
// 認証後のコンテンツ
Route::middleware('auth:admin')->group(function () {
Route::group(['as' => 'admin'], function () {
// ダッシュボード
Route::get('/home', 'HomeController@index')->name('.home');
// ユーザ管理
Route::get('/user', 'UserController@index')->name('.user.index');
Route::get('/user/create', 'UserController@create')->name('.user.create');
Route::post('/user/create', 'UserController@store')->name('.user.store');
Route::get('/user/edit/{id}', 'UserController@edit')->name('.user.edit');
Route::put('/user/edit/{id}', 'UserController@update')->name('.user.update');
Route::delete('/user/delete/{id}', 'UserController@destroy')->name('.user.delete');
});
});
});
■サービスとリポジトリを作成
コントローラ内で直接モデルを呼び出さず、サービスとリポジトリを経由するように変更する
設計方針は人それぞれだが、ここでは
「コントローラからは常にサービスを呼び出し、リポジトリとモデルは呼び出さない」
「データベース操作はリポジトリに閉じ込め、テストのために差し替え可能な状態にする」
とする
※app/Http/Controllers/Auth/RegisterController.php ファイルの register メソッド内に
event(new Registered($user)); の処理があると、ユーザ登録時にnginxタイムアウトになってしまうことがあった
冒頭で use Illuminate\Auth\Events\Registered; をインポートするようにして解決したみたい
※似て非なる処理が増えて管理しづらくなってしまうので、
「interface Repository」を作って以下にあるような雛形を定義し、
それを継承して「abstract class UserRepository implements Repository」を作って具体的な処理を実装し、
それを「use App\Contracts\Repositories\UserRepository as UserRepositoryContract;」として読み込んで継承して「class UserRepository implements UserRepositoryContract」を作って必要な追加処理があれば実装する
…とする方がいいか
app/Contracts/Repositories/UserRepository.php
<?php
namespace App\Contracts\Repositories;
interface UserRepository
{
/**
* 取得
*
* @param int $id
* @return mixed
*/
public function find($id);
/**
* 検索
*
* @param array $conditions
* @param array $orders
* @param int|null $limit
* @return mixed
*/
public function search(array $conditions, array $orders, $limit);
/**
* 件数
*
* @return int
*/
public function count();
/**
* 保存
*
* @param array $data
* @param int|null $id
* @return mixed
*/
public function save(array $data, $id);
/**
* 削除
*
* @param int $id
* @return mixed
*/
public function delete($id);
}
app/Repositories/UserRepository.php
<?php
namespace App\Repositories;
use App\Contracts\Repositories\UserRepository as UserRepositoryContract;
use App\Models\User;
class UserRepository implements UserRepositoryContract
{
/** @var User */
protected $user;
/**
* コンストラクタ
*
* @param User $user
* @return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* 取得
*
* @param int $id
* @return mixed
*/
public function find($id)
{
return $this->user->find($id);
}
/**
* 検索
*
* @param array $conditions
* @param array $orders
* @param int|null $limit
* @return mixed
*/
public function search(array $conditions = array(), array $orders = array(), $limit = null)
{
$query = $this->user->query();
$query = $this->setConditions($query, $conditions);
foreach ($orders as $order) {
$query->orderBy($order[0], $order[1]);
}
if ($limit == null) {
return $query->get();
} else {
return $query->paginate($limit);
}
}
/**
* 件数
*
* @param array $conditions
* @return int
*/
public function count(array $conditions = array())
{
$query = $this->user->query();
$query = $this->setConditions($query, $conditions);
return $query->count();
}
/**
* 保存
*
* @param array $data
* @param int|null $id
* @return User
*/
public function save(array $data, $id = null)
{
return $this->user->updateOrCreate(['id' => $id], $data);
}
/**
* 削除
*
* @param int $id
* @return mixed
*/
public function delete($id)
{
return $this->user->findOrFail($id)->delete();
}
/**
* 検索条件を設定
*
* @param int $query
* @param array $conditions
* @return \Illuminate\Database\Query\Builder
*/
private function setConditions($query, array $conditions = array())
{
if (isset($conditions['id'])) {
$query->where('id', $conditions['id']);
}
if (isset($conditions['name'])) {
$query->where('name', $conditions['name']);
}
if (isset($conditions['name_like'])) {
$query->where('name', 'like', $conditions['name_like']);
}
return $query;
}
}
app/Services/UserService.php
<?php
namespace App\Services;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Contracts\Repositories\UserRepository;
use App\Http\Requests\StoreUserRequest;
use App\Http\Requests\UpdateUserRequest;
class UserService
{
/** @var UserRepository */
protected $userRepository;
/**
* コンストラクタ
*
* @param UserRepository $userRepository
* @return void
*/
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
/**
* 1件取得
*
* @param int $id
* @return mixed
*/
public function getUser($id)
{
return $this->userRepository->find($id);
}
/**
* 検索して取得
*
* @param array $conditions
* @param array $orders
* @param int $limit
* @return mixed
*/
public function getUsers(array $conditions = array(), array $orders = array(), $limit = null)
{
return $this->userRepository->search($conditions, $orders, $limit);
}
/**
* 件数を取得
*
* @param array $conditions
* @return int
*/
public function countUsers(array $conditions = array())
{
return $this->userRepository->count($conditions);
}
/**
* 登録
*
* @param StoreUserRequest $request
* @return \App\Models\User
*/
public function storeUser(StoreUserRequest $request)
{
$input = $request->only([
'name',
'email',
'password',
]);
// パスワードを暗号化
$input['password'] = Hash::make($input['password']);
// 保存
try {
return DB::transaction(function () use ($input) {
$result = $this->userRepository->save($input);
return $result;
});
} catch (\Exception $e) {
Log::error('UserService:storeUser', ['message' => $e->getMessage(), 'input' => $input]);
return null;
}
}
/**
* 編集
*
* @param UpdateUserRequest $request
* @param int $id
* @return \App\Models\User
*/
public function updateUser(UpdateUserRequest $request, $id)
{
$input = $request->only([
'name',
'email',
'password',
]);
// パスワードを暗号化
if (empty($input['password'])) {
unset($input['password']);
} else {
$input['password'] = Hash::make($input['password']);
}
// 保存
try {
return DB::transaction(function () use ($input, $id) {
$result = $this->userRepository->save($input, $id);
return $result;
});
} catch (\Exception $e) {
Log::error('UserService:updateUser', ['message' => $e->getMessage(), 'input' => $input, 'id' => $id]);
return null;
}
}
/**
* 削除
*
* @param int $id
* @return \App\Models\User
*/
public function deleteUser($id)
{
try {
return DB::transaction(function () use ($id) {
return $this->userRepository->delete($id);
});
} catch (\Exception $e) {
Log::error('UserService:deleteUser', ['message' => $e->getMessage(), 'id' => $id]);
return null;
}
}
}
app/Providers/AppServiceProvider.php
public function register()
{
$this->app->bind(
\App\Contracts\Repositories\UserRepository::class,
\App\Repositories\UserRepository::class
);
}
resources/views/admin/user/index.blade.php
@elseif (session('error'))
<div class="box">
<div class="alert alert-danger">
{{ session('error') }}
</div>
</div>
@endif
app/Http/Controllers/Auth/RegisterController.php
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Auth\Events\Registered;
use App\Http\Controllers\Controller;
use App\Http\Requests\StoreUserRequest;
use App\Models\User;
use App\Services\UserService;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = '/mypage';
/**
* Create a new controller instance.
*
* @param UserService $userService
* @return void
*/
public function __construct(UserService $userService)
{
$this->middleware('guest');
$this->userService = $userService;
}
/**
* Handle a registration request for the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function register(StoreUserRequest $request)
{
event(new Registered($user = $this->userService->storeUser($request)));
$this->guard()->login($user);
return $this->registered($request, $user)
?: redirect($this->redirectPath());
}
}
app/Http/Controllers/MypageController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Hash;
use App\Http\Controllers\Controller;
use App\Http\Requests\UpdateUserRequest;
use App\Models\User;
use App\Services\UserService;
class MypageController extends Controller
{
/**
* インスタンス作成
*
* @param UserService $userService
* @return void
*/
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
/**
* マイページ
*
* @param Request $request
* @return \Illuminate\Contracts\Support\Renderable
*/
public function index(Request $request)
{
return view('mypage/index');
}
/**
* 基本情報編集画面
*
* @param Request $request
* @return \Illuminate\Contracts\Support\Renderable
*/
public function basis(Request $request)
{
// ユーザー情報取得
$user = Auth::guard()->user();
return view('mypage/basis', [
'user' => $user,
]);
}
/**
* 基本情報編集
*
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function basisUpdate(UpdateUserRequest $request)
{
// 編集
$id = Auth::guard()->user()->id;
if ($this->userService->updateUser($request, $id)) {
return redirect()->route('mypage.basis')->with('message', '基本情報を編集しました。');
} else {
return redirect()->route('mypage.basis')->with('message', '基本情報を編集できませんでした。');
}
}
}
app/Http/Controllers/Admin/UserController.php
<?php
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Http\Requests\StoreUserRequest;
use App\Http\Requests\UpdateUserRequest;
use App\Models\User;
use App\Services\UserService;
class UserController extends Controller
{
/**
* Create a new controller instance.
*
* @param UserService $userService
* @return void
*/
public function __construct(UserService $userService)
{
$this->middleware('auth');
$this->userService = $userService;
}
/**
* Display a list of all users.
*
* @param Request $request
* @return Response
*/
public function index(Request $request)
{
return view('admin.user.index', [
'users' => $this->userService->getUsers([], [['id', 'desc']]),
]);
}
/**
* Display a form of new user.
*
* @param Request $request
* @return Response
*/
public function create(Request $request)
{
return view('admin.user.form');
}
/**
* Create a new user.
*
* @param Request $request
* @return Response
*/
public function store(StoreUserRequest $request)
{
if ($this->userService->storeUser($request)) {
return redirect()->route('admin.user.index')->with('message', 'ユーザを登録しました。');
} else {
return redirect()->route('admin.user.index')->with('error', 'ユーザを登録できませんでした。');
}
}
/**
* Display a form of edit user.
*
* @param Request $request
* @return Response
*/
public function edit(Request $request, $id)
{
return view('admin.user.form', [
'user' => $this->userService->getUser($id),
]);
}
/**
* Update a user.
*
* @param Request $request
* @return Response
*/
public function update(UpdateUserRequest $request, $id)
{
if ($this->userService->updateUser($request, $id)) {
return redirect()->route('admin.user.index')->with('message', 'ユーザを編集しました。');
} else {
return redirect()->route('admin.user.index')->with('error', 'ユーザを編集できませんでした。');
}
}
/**
* Destroy the given user.
*
* @param Request $request
* @param string $id
* @return Response
*/
public function destroy(Request $request, $id)
{
if ($this->userService->deleteUser($id)) {
return redirect()->route('admin.user.index')->with('message', 'ユーザを削除しました。');
} else {
return redirect()->route('admin.user.index')->with('error', 'ユーザを削除できませんでした。');
}
}
}
■新規ユーザ登録時に確認画面を表示
データ登録前に確認画面を表示する例として作成
データの一時的な保持にはフォームのhiddenではなく、セッションを使う
routes/web.php
Auth::routes();
Route::post('confirm', 'Auth\RegisterController@confirm')->name('confirm');
app/Http/Controllers/Auth/RegisterController.php
use Illuminate\Http\Request;
/**
* Show the application registration form.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function showRegistrationForm(Request $request)
{
if ($request->referer === 'confirm' && $request->session()->has('post.register')) {
$post = $request->session()->get('post.register');
} else {
$post = [];
}
return view('auth.register', [
'user' => $post,
]);
}
/**
* Confirm a registration request for the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\Support\Renderable
*/
protected function confirm(StoreUserRequest $request)
{
$post = $request->all();
$request->session()->put('post.register', $post);
return view('auth.confirm', [
'user' => $post,
]);
}
/**
* Handle a registration request for the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function register(Request $request)
{
if (!$request->session()->has('post.register')) {
return redirect()->route('register');
}
$post = $request->session()->get('post.register');
$postRequest = new StoreUserRequest();
$postRequest->merge($post);
$request->session()->forget('post.register');
event(new Registered($user = $this->userService->storeUser($postRequest)));
$this->guard()->login($user);
return $this->registered($request, $user)
?: redirect($this->redirectPath());
}
resources/views/auth/register.blade.php
<form method="POST" action="{{ route('confirm') }}">
<input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name', $user['name'] ?? '') }}" required autocomplete="name" autofocus>
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email', $user['email'] ?? '') }}" required autocomplete="email">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" value="{{ old('password', $user['password'] ?? '') }}" required autocomplete="new-password">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" value="{{ old('password_confirmation', $user['password_confirmation'] ?? '') }}" required autocomplete="new-password">
resources/views/auth/confirm.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Register') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('register') }}">
@csrf
<div class="form-group row">
<label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>
<div class="col-md-6">
{{ $user['name'] }}
</div>
</div>
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
{{ $user['email'] }}
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
**********
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<a href="{{ route('register') }}?referer=confirm">Back</a>
<button type="submit" class="btn btn-primary">
{{ __('Register') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
■論理削除に対応
データを物理削除から論理削除に変更する
まずはマイグレーションを作成
$ php artisan make:migration alter_tables
作成されたマイグレーションを以下のように修正
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->softDeletes();
});
Schema::table('admins', function (Blueprint $table) {
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('deleted_at');
});
Schema::table('admins', function (Blueprint $table) {
$table->dropColumn('deleted_at');
});
}
マイグレーションを実行
$ php artisan migrate
プログラムを修正
app\Models\User.php
use Illuminate\Database\Eloquent\SoftDeletes;
use Notifiable, SoftDeletes;
app\Models\Admin.php
use Illuminate\Database\Eloquent\SoftDeletes;
use Notifiable, SoftDeletes;
■CSSファイルやJSファイルのキャッシュ読み込み対策を行う
ファイル名の後ろに、自動的にタイムスタンプが付くようにする
app\Providers\BladeServiceProvider.php を作成
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Blade;
class BladeServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
/**
* CSSファイルやJSファイルのパスに、ファイルのタイムスタンプを追加
*
* @param string $file
* @return string
*/
Blade::directive('asset', function ($file) {
$file = str_replace(["'", '"'], '', $file);
$path = public_path() . '/' . $file;
try {
$timestamp = "?<?php echo \File::lastModified('{$path}') ?>";
} catch (\Exception $e) {
$timestamp = '';
}
return asset($file) . $timestamp;
/*
// ロードバランサーを考慮する場合(環境によってはURLを自動取得できないので、.envのAPP_URLを参照)
$app_url = env('APP_URL');
if (empty($app_url)) {
return asset($file) . $timestamp;
} else {
return $app_url . '/' . $file . $timestamp;
}
*/
});
}
}
config\app.php を編集
'providers' => [
〜略〜
App\Providers\BladeServiceProvider::class,
ビュー内で以下のように asset を使用すると、ファイル名の最後に「?1597309521」のような値が追加される
<script src="@asset('js/common.js')" defer></script>
<link href="@asset('css/common.css')" rel="stylesheet">