Memo

メモ > 技術 > フレームワーク: Laravel > 実装メモ

■実装メモ
■APP_KEYの設定 他環境で実行する場合、GitからCLONEやPULLしたあとに以下の操作で APP_KEY の生成が必要 もしくは、キーを .env.example に含めるという手段もありそう
$ cp .env.example .env $ composer install --no-dev $ php artisan key:generate
複数台環境の場合、Web1で上記手順を実行して、 Web2では、上記作業によって .env に記録された APP_KEY の値を手動で設定 …とすると良さそう (データの暗号化などに使われるようなので、すべてのサーバで同じ値に統一しておく) Laravelについてのメモ - Qiita https://qiita.com/reflet/items/76ce4d7743c7d9a8a963 [Laravel5.5] APP_KEY の行方を追う - Qiita https://qiita.com/yk2220s/items/dcbf54c6d1f33a0cb06f [Laravel] アプリケーションキー(APP_KEY)を設定する - 端くれプログラマの備忘録 http://www.84kure.com/blog/2015/11/17/laravel-%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7... 初めてのフレームワーク-Laravel5-4エラー時の対策メモ - Qiita https://qiita.com/k-okada/items/0fa94f076d08584ee314 ■クラスの省略呼び出し use App\Article; と宣言しておくと、以下のように省略して呼び出せる
$article = new App\Article; ↓ $article = new Article;
■enumを扱う Laravel-enumをインストールすれば使える Laravel-enumの使い方 - Qiita https://qiita.com/sayama0402/items/4e8a885fed367090de12 ただし定番の方法は言いづらい 以下などを参考に自作する方が無難かも PHPで列挙型(enum)を作る - Qiita https://qiita.com/Hiraku/items/71e385b56dcaa37629fe Laravelでつくる、深くて表現豊かなモデル - Qiita https://qiita.com/nunulk/items/0820fd19690066d092d5 ■セッション
// セッション Route::get('/session', function () { $count = session('count', 0) + 1; session(['count' => $count]); return 'count=' . $count; }); // 以下のような書き方もできる $request->session()->get('key');
複数台構成でセッションをデータベースに保存する場合、以下が参考になる HTTPセッション 5.5 Laravel https://readouble.com/laravel/5.5/ja/session.html セッションをRedisに保存する場合、以下が参考になる Laravel 5.3でセッション管理にredisを使用する方法 - Qiita https://qiita.com/LowSE01/items/5f8a9c9b09948a6403dc AWS EC2にredisをインストールする - Qiita https://qiita.com/stoshiya/items/b8c1d2eb41770f92ffcf 404ページなどでセッションが使えない場合、以下が参考になる ($middleware に StartSession::class を追加する) Laravel5 例外ハンドラで指定した遷移先ページでセッションを使う方法 - Qiita https://qiita.com/papyrus9/items/c7394346ca509d016e70 ■メールアドレスとパスワードではなく、ユーザ名とパスワードで認証する 未検証 LoginController で username() を定義する
public function username() { return 'username'; }
認証 5.4 Laravel https://readouble.com/laravel/5.4/ja/authentication.html 「ユーザー名のカスタマイズ」を参照 Laravelでユーザー名またはメールアドレスでログインする - むらさきラボ http://y6rasaki.hatenablog.com/entry/2016/11/17/222713 ■キャッシュ 例えば以下のようにすると、Laravelでキャッシュを扱える
<?php namespace App\Http\Controllers\Cache; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Cache; use Illuminate\Http\Request; use App\Http\Controllers\Controller; class TestController extends Controller { /** * テストページ * * @param Request $request * @return \Illuminate\Http\Response */ public function test(Request $request) { if (Cache::has('test')) { $value = Cache::get('test') + 1; } else { $value = 1; } Cache::put('test', $value, 1); return 'cache_test test=[' . $value . ']'; } }
標準ではキャッシュはファイルに保存される Redisを使用する場合、
$ composer require predis/predis
を実行する .env
CACHE_DRIVER=file REDIS_HOST=xxxxx.cache.amazonaws.com REDIS_PASSWORD=null REDIS_PORT=6379
キャッシュ 5.5 Laravel https://readouble.com/laravel/5.5/ja/cache.html Laravel Recipes日本語版 | クエリー結果をキャッシュする http://recipes.laravel.jp/recipe/748 Laravel5.5でAWSのElastiCacheでRedisを使用する場合は以下が参考になりそう Laravelのセッション管理にRedisを指定し、AWSのElastiCacheを利用する - 商売力開発ブログ https://www.prj-alpha.biz/entry/2018/05/06/230232 【Elasticache】ELB配下の複数インスタンス間でのセッション管理【Laravel例】 - 備忘録の裏のチラシ https://norikone.hatenablog.com/entry/2016/02/08/%E3%80%90Elasticache%E3%80%91ELB%E9%85%8D%E4%B8%8B%... ■Laravel+Redis の putCache と putManyCache キャッシュへの保存は putCache を使うが、大量の情報を保存する場合は putManyCache を使うと速度が劇的に向上する可能性がある 以下、速度が向上する理由のメモ putManyCache は vendor/laravel/framework/src/Illuminate/Cache/RedisStore.php の100行目あたりに処理がある 基本的には配列の内容を put しているだけだが、前後で multi と exec が呼ばれている
/** * Store multiple items in the cache for a given number of minutes. * * @param array $values * @param float|int $minutes * @return void */ public function putMany(array $values, $minutes) { $this->connection()->multi(); foreach ($values as $key => $value) { $this->put($key, $value, $minutes); } $this->connection()->exec(); }
multi は vendor/predis/predis/src/Transaction/MultiExec.php の250行目あたりに処理がある
/** * Finalizes the transaction by executing MULTI on the server. * * @return MultiExec */ public function multi() { if ($this->state->check(MultiExecState::INITIALIZED | MultiExecState::CAS)) { $this->state->unflag(MultiExecState::CAS); $this->call('MULTI'); } else { $this->initialize(); } return $this; }
キャッシュへの保存前に MULTI という文字を送っていることが判る MULTI はRedisに用意されたトランザクション機能で、速度を向上させるために実装されているもの。これによって速度が向上する ただしRedisのトランザクションは整合性を保つためのものではなく、あくまでもパフォーマンスを向上させるための機能なので注意 詳細は以下を参照 トランザクション - Redis Documentation (Japanese Translation) https://redis-documentasion-japanese.readthedocs.io/ja/latest/topics/transactions.html Redisのトランザクションとパフォーマンス | よしやのブログ https://ameblo.jp/myon53/entry-11797609797.html ■Queue 未検証 キューが正しく動作しなくなったら、以下で再起動すると正常になる…ことが多いらしい キューを削除しても動き出さない…という場合、SQSの処理中メッセージが無くなってから再起動すれば大丈夫のことがあったらしい 要検証
php artisan queue:restart
Laravel の Queue で非同期処理を実装する(beanstalkd / IronMQ / SQS) - Shin x blog http://www.1x1.jp/blog/2014/08/laravel-queue-guide.html Laravel5でAWSのSQSを使う 複数のキューを処理する方法 - ECサイト運営開発記 http://nohohox.hateblo.jp/entry/2016/02/26/030616 キュー 5.4 Laravel https://readouble.com/laravel/5.4/ja/queues.html キュー - ララ帳 https://laravel10.wordpress.com/2015/05/07/%E3%82%AD%E3%83%A5%E3%83%BC/ ■APIの作成 APIアクセスの例 /api/example routes\api.php にAPI用のルーティングを設定し、 app\Http\Controllers\Api\ExampleController.php で処理を行う ■コマンドの作成 Artisanコンソール 5.5 Laravel https://readouble.com/laravel/5.5/ja/artisan.html タスクスケジュール 5.5 Laravel https://readouble.com/laravel/5.5/ja/scheduling.html タスクスケジュール 6.x Laravel https://readouble.com/laravel/6.x/ja/scheduling.html laravelでバッチ作ってcronで動かしてみた - Qiita https://qiita.com/ritukiii/items/a70d89fa988b2d9afbc4 Laravelで定期実行(スケジューラー)を設定する方法 - ポッポプログラミング https://poppotennis.com/posts/laravel-scheduler 【Laravel】 Cron タスクスケジューラの onOneServer() と withoutOverlapping() の違い - Qiita https://qiita.com/mpyw/items/15d14d920250a3b9eb5a
php artisan make:command Example
を実行すると
app\Console\Commands\Example.php
が作成されるので、これを編集する
php artisan list
コマンドの登録を確認
php artisan example
コマンドを実行 なお /etc/crontab にCronを記載する場合、
* * * * * php /var/www/vhosts/test/artisan schedule:run >> /dev/null 2>&1
ではなく、以下のように実行ユーザとパスも指定する必要があるので注意 (実行ユーザを指定していない場合、日時ログファイルが root 権限で作られて nginx から書き込めずエラーになる可能性がある)
* * * * * nginx /usr/bin/php /var/www/vhosts/test/artisan schedule:run >> /dev/null 2>&1
Laravel6の場合、以下のように「プロジェクトの場所へ移動してから実行」という書き方に変わっている Laravel6を使うなら、こちらに合わせておく方が無難かも
* * * * * nginx cd /var/www/vhosts/test && php artisan schedule:run >> /dev/null 2>&1
重複起動はwithoutOverlappingで防止できるが、複数台サーバだと防止にならないので注意 Laravel Scheduler のコードリーディング - Qiita https://qiita.com/mikakane/items/e9d2a70174e8af584db0 Laravelでタスクをスケジュール実行する | scratchpad https://takayukii.me/20160824836 また、onOneServerで複数台サーバでの重複起動を防止できるが、 デフォルトキャッシュドライバとして、memcached か redis を使用する必要がある タスクスケジュール 6.x Laravel https://readouble.com/laravel/6.x/ja/scheduling.html ■関数やクラスのパスを取得
exit(ArticlesTableSeeder::class); exit(event::class);
■動作環境の確認
php artisan env Current application environment: local
.envの以下の部分で設定される
APP_ENV=local
production(実働環境)とtesting(ユニットテスト環境)は標準で予約されている それ以外、local(開発環境)やstaging(デプロイ候補環境)など自由に設定できる production に設定されている場合、 マイグレーションやシーディングの実行時に確認が求められる ■バージョンの確認
php artisan --version Laravel Framework 5.4.34
Artisanコマンドライン 5.dev Laravel https://readouble.com/laravel/5.dev/ja/artisan.html \vendor\laravel\framework\src\Illuminate\Foundation\Application.php コマンドで確認できるが、このファイルにある
const VERSION = '5.4.34';
この部分の数値が表示されている ■SSLの強制 /routes/web.php の最後に以下を追加する
// 本番環境ではSSL用のURLを生成 if (app()->environment('production')) { URL::forceScheme('https'); }
productionでhttpsにしたい - ド忘れ防止雑記帳 http://dolphin.hatenablog.jp/entry/2015/04/27/010635 ただしこれは「LaravelにSSL用のURLを生成させる」処理なので、SSLにリダイレクトさせたいなら別途処理が必要 ロードバランサーが無い場合、以下で対応できそう(未検証) Laravel5で.htaccessを使用せず常時SSL化対応する方法 - Qiita https://qiita.com/qwe001/items/7cd0bcb149b5b5cc0fd7 ロードバランサーがある場合、以下のようにnginxで「$http_x_forwarded_proto」の条件を追加する
# vi /etc/nginx/nginx.conf
server { listen 80 default_server; listen [::]:80 default_server; server_name laravel.example.com; root /var/www/vhosts/laravel/public; if ($http_x_forwarded_proto = 'http') { return 301 https://$server_name$request_uri; }
# service nginx configtest # service nginx restart
Laravel 5 - laravel5.5 httpからhttpsへリダイレクトさせたい|teratail https://teratail.com/questions/98537 【Nginx】HTTPSへのリダイレクト設定〜rewriteではなくreturnでいこう〜 | ぴぐろぐ https://pig-log.com/nginx-redirect-return/ ■万年カレンダーを表示する Laravel+Carbonでカレンダーの作り方 - Crieit https://crieit.net/posts/Laravel-Carbon /routes/web.php
use Carbon\Carbon; Route::get('/calendar', function () { $year = date('Y'); $month = date('m'); $dateStr = sprintf('%04d-%02d-01', $year, $month); $date = new Carbon($dateStr); // カレンダーを四角形にするため、前月となる左上の隙間用のデータを入れるためずらす $date->subDay($date->dayOfWeek); // 同上。右下の隙間のための計算 $count = 31 + $date->dayOfWeek; $count = ceil($count / 7) * 7; $dates = []; for ($i = 0; $i < $count; $i++, $date->addDay()) { // copyしないと全部同じオブジェクトを入れてしまうことになる $dates[] = $date->copy(); } return view('calendar', [ 'dates' => $dates, 'year' => $year, 'month' => $month, ]); });
/resources/views/calendar.blade.php
<!doctype html> <html lang="{{ app()->getLocale() }}"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>カレンダー</title> <style> table tr th, table tr td { border: 1px solid #666; } table tr td.secondary { color: #aaa; } </style> </head> <body> <h1>カレンダー</h1> <table class="table table-bordered"> <thead> <tr> @foreach (['日', '月', '火', '水', '木', '金', '土'] as $dayOfWeek) <th>{{ $dayOfWeek }}</th> @endforeach </tr> </thead> <tbody> @foreach ($dates as $date) @if ($date->dayOfWeek == 0) <tr> @endif <td @if ($date->month != $month) class="secondary" @endif > {{ $date->day }} </td> @if ($date->dayOfWeek == 6) </tr> @endif @endforeach </tbody> </table> </body> </html>
■確認画面のある問い合わせフォームを作る マイグレーションを作成
php artisan make:migration create_contacts_table --create=contacts
マイグレーション内容を修正
Schema::create('contacts', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('email'); $table->string('subject'); $table->text('body'); $table->timestamps(); $table->softDeletes(); });
マイグレーションを実行
php artisan migrate
モデルを作成
php artisan make:model Contact
モデルを修正
<?php namespace App; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class Contact extends Model { use SoftDeletes; /** * 日付へキャストする属性 * * @var array */ protected $dates = ['created_at', 'updated_at', 'deleted_at']; /** * 複数代入する属性 * * @var array */ protected $fillable = ['name', 'email', 'subject', 'body']; }
フォームリクエストを作成
php artisan make:request StoreContactPost
フォームリクエストを修正
<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class StoreContactPost 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|max:255', 'email' => 'required|max:255', 'subject' => 'required|max:255', 'body' => 'required|max:255', ]; } }
ルーティングを追加
Route::prefix('/contact')->group(function () { Route::get('/', 'ContactController@index'); Route::post('/confirm', 'ContactController@confirm'); Route::post('/send', 'ContactController@store'); Route::get('/complete', 'ContactController@complete'); });
コントローラを作成
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Requests; use App\Http\Requests\StoreContactPost; use App\Http\Controllers\Controller; use App\Contact; class ContactController extends Controller { /** * Display a input form. * * @param Request $request * @return Response */ public function index(Request $request) { return view('contact.index'); } /** * Confirm a new contact. * * @param Request $request * @return Response */ public function confirm(StoreContactPost $request) { $data = $request->all(); $request->session()->put($data); return view('contact.confirm', compact('data')); } /** * Create a new contact. * * @param Request $request * @return Response */ public function store(Request $request) { if ($request->get('action') === 'back') { return redirect('/contact')->withInput($request->session()->all()); } Contact::create($request->session()->all()); $request->session()->flush(); return redirect('/contact/complete'); } /** * Display a complete. * * @return Response */ public function complete() { return view('contact.complete'); } }
ビューを作成: contact/index.blade.php
@extends('layouts.app') @section('content') <div class="container"> <div class="col-sm-offset-2 col-sm-8"> <div class="panel panel-default"> <div class="panel-heading"> Contact </div> <div class="panel-body"> <!-- Display Validation Errors --> @if (count($errors) > 0) <!-- Form Error List --> <div class="alert alert-danger"> <strong>Whoops! Something went wrong!</strong> <br><br> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <!-- Contact Form --> <form action="{{ url('contact/confirm')}}" method="POST" class="form-horizontal"> {{ csrf_field() }} <!-- Contact Name --> <div class="form-group"> <label for="contact-name" class="col-sm-3 control-label">Name</label> <div class="col-sm-6"> <input type="text" name="name" id="contact-name" class="form-control" value="{{ old('name') }}"> </div> </div> <!-- Contact Email --> <div class="form-group"> <label for="contact-email" class="col-sm-3 control-label">Email</label> <div class="col-sm-6"> <input type="text" name="email" id="contact-email" class="form-control" value="{{ old('email') }}"> </div> </div> <!-- Contact Subject --> <div class="form-group"> <label for="contact-subject" class="col-sm-3 control-label">Subject</label> <div class="col-sm-6"> <input type="text" name="subject" id="contact-subject" class="form-control" value="{{ old('subject') }}"> </div> </div> <!-- Contact Body --> <div class="form-group"> <label for="contact-body" class="col-sm-3 control-label">Body</label> <div class="col-sm-6"> <textarea name="body" cols="50" rows="10" class="form-control">{{ old('body') }}</textarea> </div> </div> <!-- Confirm Button --> <div class="form-group"> <div class="col-sm-offset-3 col-sm-6"> <button type="submit" class="btn btn-default"> <i class="fa fa-btn fa-plus"></i>Confirm </button> </div> </div> </form> </div> </div> </div> </div> @endsection
ビューを作成: contact/confirm.blade.php
@extends('layouts.app') @section('content') <div class="container"> <div class="col-sm-offset-2 col-sm-8"> <div class="panel panel-default"> <div class="panel-heading"> Contact </div> <div class="panel-body"> <!-- Contact Form --> <form action="{{ url('contact/send')}}" method="POST" class="form-horizontal"> {{ csrf_field() }} <!-- Contact Name --> <div class="form-group"> <label for="contact-name" class="col-sm-3 control-label">Name</label> <div class="col-sm-6"> {{ $data['name'] }} </div> </div> <!-- Contact Email --> <div class="form-group"> <label for="contact-email" class="col-sm-3 control-label">Email</label> <div class="col-sm-6"> {{ $data['email'] }} </div> </div> <!-- Contact Subject --> <div class="form-group"> <label for="contact-subject" class="col-sm-3 control-label">Subject</label> <div class="col-sm-6"> {{ $data['subject'] }} </div> </div> <!-- Contact Body --> <div class="form-group"> <label for="contact-body" class="col-sm-3 control-label">Body</label> <div class="col-sm-6"> {!! nl2br(e($data['body'])) !!} </div> </div> <!-- Send Button --> <div class="form-group"> <div class="col-sm-offset-3 col-sm-6"> <button type="submit" name="action" value="back" class="btn btn-default"> Back </button> <button type="submit" class="btn btn-default"> <i class="fa fa-btn fa-plus"></i>Send </button> </div> </div> </form> </div> </div> </div> </div> @endsection
ビューを作成: contact/complete.blade.php
@extends('layouts.app') @section('content') <div class="container"> <div class="col-sm-offset-2 col-sm-8"> <div class="panel panel-default"> <div class="panel-heading"> Contact </div> <div class="panel-body"> Complete </div> </div> </div> </div> @endsection
Laravel5で確認画面を経由したDB登録を実装する | Laravel | Ayumi Folio http://aym.sakura.ne.jp/system/20160521/ Laravel 5で確認画面付き問い合わせフォームを作る - Qiita http://qiita.com/ponko2/items/fd7ac38b964e10f16f52

Advertisement