- 投稿日:2019-05-07T20:38:53+09:00
Laravel セッション切れ「The page has expired due to inactivity」の回避策
app/Exceptions/Handler.php
public function render($request, Exception $e) { if ($e instanceof \Illuminate\Session\TokenMismatchException) { return redirect() ->back() ->withInput($request->except('password')) ->with([ 'message' => 'Validation Token was expired. Please try again', 'message-type' => 'danger']); } return parent::render($request, $e); }
- 投稿日:2019-05-07T16:41:14+09:00
mysql laravel で ユーザー別にランキング順位を求める
例えば 3位/1000人中
とかやりたい。ただ、これは関連テーブルをSUMして・・・とやるのは無理みたい。
ということで、裏でパッチ処理させておいて、メインテーブルに格納。
それをソートする。
socials テーブル
id sum_social_day7pageviewsがあって
指定ユーザーIDが
sum_social_day7pageviews 順に何位か?を求める。参考
https://qiita.com/hmuronaka/items/1afc132ddf400363efc2DB::statement(DB::raw('set @c:=0'));//こうやって set を分けておくのが味噌 $res = DB::select("SELECT tmp.id, tmp.sum_social_day7pageviews, tmp.rank rank FROM (SELECT id, sum_social_day7pageviews, @c:=@c+1 rank FROM uranaibako.socials ORDER BY sum_social_day7pageviews DESC) tmp WHERE id=296640879");これで結果が
Array ( [0] => stdClass Object ( [id] => 296640879 [sum_social_day7pageviews] => 97 [rank] => 2 )やったね!
- 投稿日:2019-05-07T16:29:15+09:00
Laravelでよく使うバリデーションルール
Laravelでよく使うバリデーションルールをメモしました。
めっちゃ使う
required
必須チェックnumeric
数値であるかinteger
整数であるかmax:値
文字列の場合は、文字数になるし、数値の場合は数値になるという賢いやつ!!min:値
文字列の場合は、文字数になるし、数値の場合は数値になるという賢いやつ!!between:min,max
フィールドが指定された最小値と最大値の間のサイズであることをバリデートします。
めっちゃ使うとかいいながら、存在を忘れていた。
メールアドレスの形式であるかconfirmed
パスワード(確認用)、メールアドレス(確認用)でよく使うフィールドがそのフィールド名+_confirmationフィールドと同じ値であることをバリデートします。
ということなので、htmlのname属性に注意!
日付関連
date
日付の形式であるかafter:日付
対象日より後の日付であるか日付はPHPの
strtotime関数で処理されます。
strtotimeにより評価される日付文字列を渡す代わりに、その日付と比較する他のフィールドを指定することもできます。after_or_equal:日付
対象日以降の日付であるかbefore:日付
対象日より前の日付であるかbefore_or_equal:日付
対象日以前の日付であるかdate_equals:日付
バリデーションされる値が、指定した日付と同じことをバリデートします。
いまさら気づいた
今後、使おう。
nullable
nullも許可するよ。
よくある場面は、メールアドレスが任意入力だけど、確認用メールアドレスと一致しているかチェックするときとかalpha
フィールドが全部アルファベット文字であることをバリデートします。
alpha_dash
フィールドが全部アルファベット文字と数字、ダッシュ(-)、下線(_)であることをバリデートします。
alpha_num
フィールドが全部アルファベット文字と数字であることをバリデートします。
メールアドレスのバリデーションサンプル
confirmed、nullableを使ってみる。
- メールアドレスは任意入力
- メールアドレスが入力されている場合は、確認用メールアドレスと一致している必要がある
public function rules() { return [ 'email' => 'confirmed|email|nullable', ]; }
- 投稿日:2019-05-07T15:47:05+09:00
Laravelで前回の入力値を表示する方法
Laravelで前回の入力値を表示する方法を紹介します。
サンプルblade
この状態だと、入力エラーになっても、前回の入力値は表示されません。
<div class="wrapper"> @if(count($errors) > 0) <ul class="bg-danger"> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> @endif <form action="{{ route('sample.store') }}" method="post"> @csrf <div class="form-group"> <label>名称<span class="required">※必須</span></label> <input type="text" name="name" class="form-control"> </div> <button type="submit" class="btn btn-success">登録</button> </form> </div>oldメソッド
ここで活躍するのが、
oldメソッドです!<input type="text" name="name" class="form-control" value="{{ old('name') }}">
oldの引数に、対象のhtmlのname属性を指定すると、前回の入力値を表示してくれます。
でも編集のときとか、すでに保存されている値がある場合は、どうしたらいいんや?実は
oldメソッドは第二引数にデフォルトの値を受け取ることができます。<input type="text" name="name" class="form-control" value="{{ old('name', 'デフォルトの値') }}">では、実践向きに記述しますね。
新規登録画面と編集画面は同じbladeファイルを使い回すと思いますので、それに対応したいと思います。まずは、bladeのinputのvalueを以下のようにします。
<input type="text" name="name" class="form-control" value="{{ old('name', isset($defaultName) ? $defaultName : '') }}">Controllerのcreateメソッド
public function create() { return view('sample'); }createメソッドのrouteにアクセスすると、入力欄は空欄です。
Controllerのeditメソッド
public function edit($id) { return view('sample')->with([ 'defaultName' => 'デフォルトの名称', ]); }editメソッドのrouteにアクセスすると、入力欄には「デフォルトの名称」が表示されます。
ちょいと解説
value="{{ old('name', isset($defaultName) ? $defaultName : '') }}"第一引数には、htmlのname属性を入れます。こちらは、入力エラーがあった場合に表示されます。
第二引数は、初期表示の場合に表示されます。
新規登録時は$defaultNameの変数が設定されていないので、三項演算子の後半に行って、空になります。
編集時は、$defaultNameの変数が設定されているので、参考演算子の前半に行って、その値が表示されます。まとめ
素phpユーザーから、Laravelを始めて、最初につまづいたのがここだった。。
そのうちチェックボックス・ラジオボタンのoldの値の表示の仕方もまとめたい。
- 投稿日:2019-05-07T15:20:35+09:00
laravelにVue.jsを入れる前の、5分間の事前学習
◆コンパイル
ソースコードを機械語に変換する
◆ビルド
バグがないことを確かめて(静的解析)、問題がなければ実行できる形のファイルに組み立てること
(プリプロセッサ:定数置き換え・コメント削除などコンパイル前の準備) このあとコンパイル。
コンパイルはビルドの中に含まれる◆sass
cssの機能を拡張した言語(効率よくかける)
scssも同様
sassはインデントで分けて、scssはcssと書き方は同じだがこちらもインデントで分ける◆node.js参考記事
サーバーサイドで使えるJavaScriptの代表的なものの一つ
クライアントもサーバーサイドもJavaScriptで書ければ楽ということが利用される最大の理由◆npm参考記事
node.jsのパッケージ管理ツール
node.jsのパッケージは用意された便利機能の集まり◆webpack
複数javaScriptのファイルがあり、またそのファイルごとに依存関係がある(なくてももちろんいい)場合でも、それを解決し、
一つのファイルにまとめてくれる機能(ビルド)
laravelのwebpack.mix.jsファイルを見てみると、let mix = require('laravel-mix'); mix.js('resources/assets/js/app.js', 'public/js') .sass('resources/assets/sass/app.scss', 'public/css');resources/assets/js/app.jsがビルドしたいファイル
public/jsが出力先
ほかにも指定したいものがあれば、どんどん指定できる。◆npm run dev
laravelにvue.jsを導入するときに使うと、思うのですが、これで先ほどwebpack.mix.jsで指定した内容をビルドして、出力してくれる。
◆laravel mix関数参考記事
バージョン付けしたファイルの最新の名前を自動的に解決
mix.js('resources/assets/js/app.js', 'public/js') .version();npm run devで出力されているため、asset('js/app.js')でも参照できる。バージョン管理がない場合はassetでいいと思います
参考記事◆導入
参考記事をもとに進めました。
laravel-vue.js-docker-comose
- 投稿日:2019-05-07T15:15:05+09:00
Laravelでのバリデーション(値チェック)の方法
Laravelでのバリデーション(値チェック)の方法を紹介します。
サンプルblade
<div class="wrapper"> @if(count($errors) > 0) <ul class="bg-danger"> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> @endif <form action="{{ route('sample.store') }}" method="post"> @csrf <div class="form-group"> <label>名称<span class="required">※必須</span></label> <input type="text" name="name" class="form-control"> </div> <div class="form-group"> <label>チェックボックス<span class="required">※必須</span></label> <div class="checkbox"> <label class="checkbox-inline"> <input type="checkbox" name="checkbox" value="1">A </label> <label class="checkbox-inline"> <input type="checkbox" name="checkbox" value="2">B </label> <label class="checkbox-inline"> <input type="checkbox" name="checkbox" value="3">C </label> </div> </div> <div class="form-group"> <label>ラジオボタン<span class="required">※必須</span></label> <div class="radio"> <label class="radio-inline"> <input type="radio" name="radio" value="1">A </label> <label class="radio-inline"> <input type="radio" name="radio" value="2">B </label> <label class="radio-inline"> <input type="radio" name="radio" value="3">C </label> </div> </div> <button type="submit" class="btn btn-success">登録</button> </form> </div>バリデーションルール作成
以下のコマンドを実行します
$ php artisan make:request ValidateSampleすると、以下のファイルが作成されます。
app/Http/Requests/ValidateSample.php<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class ValidateSample extends FormRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return false; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ // ]; } }まず、
authorizeメソッドのreturn falseをreturn trueに修正します。
(本来は権限チェックが必要な場合は、ここでチェックすることもできます。でも他の箇所ですることが多いです。)では、
rulesメソッドの中を書いていきます。public function rules() { return [ 'name' => 'required|max:30', 'checkbox' => 'required', 'radio' => 'required', ]; }連想配列のキーが、html側のnameと一致させるように書きます。
連想配列の値に適用したいルールを書きます。
ルールはこちらの「使用可能なバリデーションルール」を参照。
(使うものはだいたい限られますが)続いて、作成したルールが適用されるようにControllerを修正します。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Requests\ValidateSample; //★追加★ class SampleController extends Controller { ...public function store(ValidateSample $request) //★もともとRequestだった箇所をValidateSampleに置き換え★ { ...では、画面から登録ボタンを押してみましょう。
あ!エラーメッセージが英語だったぞ...
エラーメッセージを日本語化する場合は、こちらから日本語ファイルを持ってくると便利です。
(今回、関係あるのはvalidation.phpだけですが...)
配置する場所はresources/lang/jaの中です。いや、ちょっと英語残ってるやんけ。
というわけで、先程作成したバリデーションファイルにattributesメソッドを追加します。app/Http/Requests/ValidateSample.phppublic function attributes() { return [ 'name' => '名称', 'checkbox' => 'チェックボックス', 'radio' => 'ラジオボタン', ]; }連想配列のキーにhtmlのname属性、値に日本語訳をつっこみます。で、登録!
よし!日本語なった!
あー、でも、もうちょっと親切なメッセージにしたいぜ。というそこのアナタ!
messagesメソッドを追加しましょう。app/Http/Requests/ValidateSample.phppublic function messages() { return [ 'checkbox.required' => 'チェックボックスは最低1つはチェックを入れてください。', ]; }連想配列のキーに、htmlのname属性と、さらに
.でつなげて、バリデーションの値を書きます。
連想配列の値はフルメッセージです。おわりに
基本的にwebシステムなどを作成するときは、JavaScriptとphp両方でバリデーションすると思いますので、あまりphpのエラーメッセージは重要視されないかもしれませんが...
JavaScriptでやれば、エラーメッセージを対象の項目の下に出すのも楽ですからね。(私はVue.jsを使用しています)
マスター関連とかは、めんどくさくなってphpだけにしちゃったりしますので、そういうときに結構役立つかも。そういえば、エラーになったときに、前回の入力値はどうやって表示するの?という疑問を持った方のための記事も作成する予定です。
- 投稿日:2019-05-07T14:10:32+09:00
Laravelのフラッシュメッセージ表示のメモ
Laravelのフラッシュメッセージ表示のメモです。
以下のように、保存後などにメッセージを表示したい場合blade側
メッセージを表示したい場所に、以下の通り記載
@if (Session::has('flash_message')) <p class="bg-success">{!! Session::get('flash_message') !!}</p> @endif @if (Session::has('error_message')) <p class="bg-danger">{!! Session::get('error_message') !!}</p> @endifController側
public function store(Request $request) { //DBへの登録処理など... \Session::flash('flash_message', '保存しました。'); return redirect(route(('sample.create'))); }
Session::flashの第一引数と、blade側の変数名が対応しています。
サンプルの場合は、flash_messageだけ表示しています。DBの登録処理を失敗した場合などは、
error_messageを使ってエラーを表示させます。
flash_message,error_messageは好きな名前を使えます。
- 投稿日:2019-05-07T13:24:25+09:00
Laravel のテストであるクラスのプロパティをテストから書き換えて初期化するには
この記事について
半分個人メモです。
ある特殊なテストを行いたくて、private なプロパティをテストメソッドから書き換えて実行する方法を探っていたところ、以下のやり方を思いついたので書き残しておきます。
はじめに
概要
あるクラスが config から読み取った値を private なプロパティにセットして初期化していて、その値を、あるテストメソッドでのみ、特殊な環境変数で上書きして実行したい、というケースに遭遇した際、リフレクションと無名クラスで対応できそうだったのでやってみました。
環境
- PHP: 7.3.2
- Laravel: 5.8.13
- PHPUnit: 7.5.8
詳細
とあるクラス
<?php namespace App\Services; class SomeService { private $config; public function __construct() { $this->config = config('services.some.config'); } public function doSomething() { return $this->config; } }テストクラス
<?php namespace Tests\Feature\Services; use App\Services\SomeService; use Tests\TestCase; class SomeServiceTest extends TestCase { public function testDoSomethingInGeneralEnvironment() { $service = app(SomeService::class); $this->assertEquals('hoge', $service->doSomething()); } public function testDoSomethingInSpecialEnvironment() { $service = new class extends SomeService { public function __construct() { $class = new \ReflectionClass(SomeService::class); $property = $class->getProperty('config'); $property->setAccessible(true); $property->setValue($this, env('SOME_SERVICE_CONFIG_OVERWRITTEN')); } }; $this->assertEquals('fuga', $service->doSomething()); } }config/services.php
'some' => [ 'config' => env('SOME_SERVICE_CONFIG'), ],.env
SOME_SERVICE_CONFIG=hoge SOME_SERVICE_CONFIG_OVERWRITTEN=fuga
SOME_SERVICE_CONFIG_OVERWRITTENは、.env.testing とか phpunit.xml とかに書いてもいいかもしれないです(テストでしか使わないやつなので)。
- 投稿日:2019-05-07T10:05:07+09:00
Laravel5のRequestクラス覚え書き
Webアプリケーションフレームワーク Laravel の
Illuminate\Http\Requestの書き方メモ。リファレンス的なもの。Controllernamespace App\Http\Controllers; use Illuminate\Http\Request; class UserController extends Controller { public function store(Request $request) { $name = $request->input('name'); // } }View@extends('layouts.app') @section('body') <form method="POST" action="{{ route('XXXX') }}"> @csrf <input type="text" name="name" value=""> // </form> @stop入力の取得
動的プロパティで入力を取得
$name = $request->name;全入力を連想配列で取得
$input = $request->all();アップロードファイルを除いて、全入力を連想配列で取得
$input = $request->input();すべてのクエリストリングを連想配列で取得(上記のallやinputにもクエリストリングは含まれる)
$input = $request->query();アップロードファイルの取得
$file = $request->file('csv');"name" の入力を取得
$name = $request->input('name');デフォルト値を指定して取得
$request->input('name', 'Tom');"name" と "password" のみ取得
$input = $request->only('name', 'password');"password" 以外を取得
$input = $request->except('password');リクエストに値が存在するか
$request->has('name')すべて存在するか
$request->has(['name', 'email'])リクエストに値が存在し、かつ空でないか
$request->filled('name')フラッシュデータ(次のリクエストの間だけ利用できるデータ)の保存
すべてをフラッシュデータに保存
$request->flash();"name" と "email" のみフラッシュデータに保存
$request->flashOnly(['name', 'email']);"password" を除いてフラッシュデータに保存
$request->flashExcept('password');セッション
"key" をセッションから取得
$request->session()->get('key');デフォルト値を指定してセッションから取得
$request->session()->get('key', 'default');その他
リクエストURIを返す
$uri = $request->path();HTTPメソッド名(GET、POST等)を返す
$method = $request->method();POSTメソッドか
$request->isMethod('POST')リクエストURIがパターンに合致するか
$request->is('admin/*')User-Agentを返す
$request->header('User-Agent');
- 投稿日:2019-05-07T08:36:23+09:00
Laravel5.8で簡単画像アップロード機能の実装
Laravelを使い初めて、画像アップロード公開がものすごく簡単に実装できて感動したので、投稿します。
1、画像を保存。
(1) 下準備
/config/filesystem.phpの設定を変更。
'default' => env('FILESYSTEM_DRIVER', 'local'),localのままだと不都合があるため(これから説明)、.envファイルに下記を追記しpublicに設定変更してあげる。
/.env
FILESYSTEM_DRIVER=public(2) 画像をアップロード
$image = $request->image->store('posts');この1行で画像自体のアップロードは完了。
後は必要に応じて返り値の画像パスをDBに保存するだけ。formから送られてきた画像データに対し、storeメソッドを呼ぶと、storage/app/public配下にデータが保存される。例のようにstoreメソッドでディレクトリを指定することもできる。今回の場合は、storage/app/public/posts配下に保存される。
※localのままだと、storage/app直下に保存されるので、これから説明するシンボリックリンクがはれない。
2、画像を表示
(1) viewで表示できるように、laravelの公開用publicフォルダにシンボリックリンクをはる。
php artisan storage:link;上記コマンドをターミナルで実行すると、
public配下にstorageリンクが作成される。/public/storage/画像パス
(2) viewで表示
<img src="{ asset('storage/画像のパス') }}">で保存した画像をviewで表示できる。
※asset()を使うとフルパスになる。
3、アップロードした画像の削除
DBから画像のパスを削除した際に、Storageフォルダにアップロードした画像を同時に削除する方法。
Storageファサードのdeleteメソッドで保存していた画像を削除できる。
use Illuminate\Support\Facades\Storage;Storage::delete('画像パス');データ削除した際に、上記メソッドを行えば、画像データも同時に削除できる。
以上、で簡単に画像のCRUDが実装できます。
参考:(公式ドキュメント)
https://readouble.com/laravel/5.8/ja/filesystem.html
- 投稿日:2019-05-07T03:36:43+09:00
LaravelでLeague/Csvを使ってアップロードされたcsvを読み込みDBに保存する
環境
Laravel 5.6
League/Csv 9.2前提
- Qiita初投稿です、お手柔らかにお願いします。
- 今回はバリデーションについては実装、言及しません。
導入
League/Csvをインストールする。
composer dump-autoloadは多分必要。composer require league/csv composer dump-autoload今回ぶち込みたいCSV
company_name name hoge株式会社 佐藤 exapmle1@example.com foo株式会社 山田 exapmle2@example.com 実装
UserController.php<?php namespace App\Http\Controllers; use App\Eloquent\User; use Illuminate\Http\Request; use League\Csv\Reader; use League\Csv\Statement; class UserController extends Controller { // 省略 public function importCSV(Request $request, Statement $stmt, User $user) { $file_path = $request->file('file')->getPathname(); // ReaderはDIできないらしい。 $csv = Reader::createFromPath($file_path, 'r')->setHeaderOffset(0); $records = $stmt->process($csv); $data = []; // 後ほど解説。 foreach ($records as $record) { $record['created_at'] = now(); $record['updated_at'] = now(); $data[] = $record; } $user->insert($data); return redirect()->route('user.index'); } }解説
ここでリクエストされたfileの一時保管パス?的なのを取得する。
$file_path = $request->file('file')->getPathname();そしてここ、
foreach ($records as $record) { $record['created_at'] = now(); $record['updated_at'] = now(); $data[] = $record; } $user->insert($data);$recordsには
ResultSet {#375 ▼ #records: LimitIterator {#372 ▶} #header: array:4 [▶] }というオブジェクトが入っているのでforeachで取得していくとなんと、各recordには
[ "company_name" => "hoge株式会社" "name" => "佐藤", "email" => "example1@example.com" ]などの配列が入っているというわけ。
Laravelだとinsertの引数に各レコードを値にもつ多次元配列を渡すことで複数レコードまとめて挿入できる。
しかし、insertは「created_at」「updated_at」が更新されないので、foreachで回しながら入れている。おまけ
今回のroute
web.phpRoute::post('/users/csv', "UserController@importCSV")->name('user.importCSV');今回のview
users.blade.php{{ Form::open(['url' => route('user.importCSV'), 'method' => 'POST', 'class' => '', 'files' => true]) }} <div class='form-group'> <input type="file" name="file" value=""> </div> <button type="submit">csv読み込み</button> {{ Form::close() }}応用編
大切なことはすべて公式ドキュメントが教えてくれた。
9.0のドキュメント↓
https://github.com/thephpleague/csv/blob/master/docs/9.0/index.md<?php use League\Csv\Reader; use League\Csv\Statement; $csv = Reader::createFromPath('/path/to/your/csv/file.csv', 'r'); // headerは何行目か。 $csv->setHeaderOffset(0); $header = $csv->getHeader(); //return [0 => "企業" // 1 => "名前" // 2 => "メールアドレス"] // 10行飛ばして25行とる $stmt = (new Statement()) ->offset(10) ->limit(25); $stmt->process($csv);まとめ
2019年でPHPでcsvをいじりたいってなると、goodbyか、このLeague/Csvの二強な感じがしていて、今回書きやすそうだしGitHubのスターもダントツでLeague/Csvの方が高かったのでこちらを採用しました。
今回は使わなかったのですが、goodbyは省メモリを売りにしているそうなのでメモリを気にする量のcsvを裁くときは視野に入れたいですね。
結局、Laravelが好きです。引用
https://github.com/thephpleague/csv/blob/master/docs/9.0/index.md




