- 投稿日:2020-11-17T22:49:29+09:00
【Laravel基礎】フォームの入力内容を制限する方法【バリデーションとフォームリクエスト】
概要
Laravel学習で自分がつまずいた部分を備忘録としてまとめています。
今回はフォームの入力内容の制限に関する記事です。つまずいたポイント
指定条件以外のフォーム入力を弾いてくれる
バリデーション
。
そんなバリデーションですが、アクション事に毎回指定するのが面倒くさい。。
効率的な方法が無いか調べました。どうやら、
フォームリクエスト
なるものを使うと
一括でバリデーションを指定出来るとのこと。バリデーションの復習もかねて、下記の2つを記事にしました。
①バリデーション
②フォームリクエスト
以下、記事内容です!
バリデーション
まずはバリデーションの復習。
保存や編集などの、フォーム内容を受け取るアクション内で、
$this->validate($request,[条件]);
を入力。
第2引数の入力内容が、フォームの入力条件になります。■コントローラ
PostsControllerpublic function store(Request $request) { //バリデーションで条件を指定 $this->validate($request, [ 'title' => 'required|min:3', 'body' => 'required' ]); $post = new Post(); $post->title = $request->title; $post->body = $request->body; $post->save(); return redirect('/'); }上記の場合だと、
title => 3文字以上 , body => 入力必須
て感じですね。
この条件以外の内容がフォームから送信されると、バリデーションが弾いてくれます。フォームリクエスト
次は
フォームリクエスト
です。
バリデーションはアクション毎にフォームの入力内容を指定していましたが、
フォームリクエストではそれを一括で指定することが出来ます。
以下、手順です。ターミナルphp artisan make:request PostRequestフォームリクエストは
php artisan make:request 〜Request
で作成出来ます。
今回はPostRequestと名付けました。
作成したRequestはApp\Http\Requests
の中にあります。■フォームリクエスト
PostRequest.php//① public function rules() { return [ 'title' => 'required|min:3', 'body' => 'required' ]; } //② public function messages() { return [ 'title.required' => 'タイトルを入力して下さい。' ]; }フォームリクエスト上での主な指定内容は2つ。
1つは入力内容の条件、もう1つはバリデーションのメッセージです。まずは入力内容の条件から。
rulesメソッド
を使う事で条件指定できます。(①)
中身は先ほどのバリデーションと同じですね。そして
messagesメソッド
では、
バリデーション適用時のメッセージを指定する事ができます。(②)
デフォルトでは英文が指定されているので、わかり易くするには日本語に変えておいた方が良いかもですね。■コントローラー
PostsController//① use App\Http\Requests\PostRequest; //② public function store(PostRequest $request) { $post = new Post(); $post->title = $request->title; $post->body = $request->body; $post->save(); return redirect('/'); }コントローラでは、フォームリクエストをuseで使えるようにしましょう。(①)
そしてアクションの引数にフォームリクエストを入力。(②)
フォームリクエストで指定した内容が適用されるようになります。
バリデーションを書かないで良いので楽ですね。フォームリクエストは以上です!
1.ターミナルからフォームリクエストを作成
2.フォームリクエストの条件を指定
3.コントローラ+アクションでフォームリクエストを適用
という流れですね。ちなみに、何でアクションの引数にrequestを入れるだけでフォーム内容が受け取れるのか?
疑問に思って調べましたが、「サービスコンテナ」やら「メソッドインジェクション」やら「DI(Dependency Injection = 依存性注入)」なる単語まで出てきて、脳がフリーズしたので一旦忘れます。いつかちゃんと調べて記事にします。多分。。。まとめ
以上、Laravelでフォームの入力内容を制限する方法でした。
最後まで読んで頂きありがとうございました。
フォームリクエストの方がコードの量が少なくなるので楽ちんですね。
- 投稿日:2020-11-17T22:26:07+09:00
5分で作るDocker+Laravel PHP+Vue.js開発環境構築
開発環境 macOS Big Sur 下記の記事を参考に環境構築を行ったのですが、
やれwget
コマンドが無いだの、apt-get
コマンドが無いだの初心者の方への導入への障壁がいくつかあったため、
それを乗り越えるための記事にしたいと思います。(※注:下記の記事は決して悪くありません。)
タイトル リンク 5分で作るLaravel+Vue.js開発環境(docker-compose) https://qiita.com/yusukeito58/items/37bd551560e495dbd1b8
wget
コマンドインストール
タイトル リンク Mac - wgetコマンドをインストール(使えるようにする) https://qiita.com/th4inf/items/f85c1b91065d85af67b9
←apt-getコマンドが無いかと思い調べてが結果的にいらないのでやらんで良いapt-get
コマンドインストール
タイトル リンク install apt-get to Mac https://qiita.com/th4inf/items/f85c1b91065d85af67b9
docker-compose up -d --build
時にmysql-client
のエラーがでたらエラー内容
E: Package 'mysql-client' has no installation candidate ERROR: Service 'app' failed to build : The command '/bin/sh -c apt-get update && apt-get install -y zlib1g-dev mysql-client libpng-dev libjpeg-dev gnupg curl wget && docker-php-ext-configure gd --with-png-dir=/usr/include --with-jpeg-dir=/usr/include && docker-php-ext-install zip pdo_mysql gd' returned a non-zero code: 100
タイトル リンク docker-compose buildするときにbundle installやmysql-clientでコケた話 https://qiita.com/aseanchild1400/items/d3580366054fee3d2703
- 投稿日:2020-11-17T19:25:35+09:00
AWS BeanstalkでLaravelをデプロイするときにCloudwatch Logsにログを転送する
前提のBeanstalk環境
PHP 7.4 running on 64bit Amazon Linux 2/3.1.3
やること
- lavavel.logのパーミッション設定
- EC2にCloudwatch Logsのロググループ作成のためのサービスロールを追加
- 設定ファイル(.ebextensions)の作成
1. lavavel.logのパーミッション設定
$ chmod 0664 /var/www/html/storage/logs/laravel.log2. lavavel.logのパーミッション設定
- Beanstalk環境のIAM インスタンスプロフィールに設定されているIAMロールに、CloudWatchLogsFullAccessのポリシーを追加 (Codepipelineでデプロイしている場合は、そのロールにも同様にCloudWatchLogsFullAccessのポリシーを追加)
3. 設定ファイル(.ebextensions)の作成
- PHP Platformでデフォルトで追加されるログの設定
参考: https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/AWSHowTo.cloudwatchlogs.html
.ebextensions/4-eblog.configoption_settings: - namespace: aws:elasticbeanstalk:cloudwatch:logs option_name: StreamLogs value: true - namespace: aws:elasticbeanstalk:cloudwatch:logs option_name: DeleteOnTerminate value: false - namespace: aws:elasticbeanstalk:cloudwatch:logs option_name: RetentionInDays value: 7
- カスタムログでlaravel.logを設定する
.ebextensions/5-laravellog.configpackages: yum: awslogs: [] files: "/etc/awslogs/awscli.conf" : mode: "000600" owner: root group: root content: | [plugins] cwlogs = cwlogs [default] region = `{"Ref":"AWS::Region"}` "/etc/awslogs/awslogs.conf" : mode: "000600" owner: root group: root content: | [general] state_file = /var/lib/awslogs/agent-state "/etc/awslogs/config/logs.conf" : mode: "000600" owner: root group: root content: | [/var/www/html/storage/logs/laravel_log] log_group_name = `{"Fn::Join":["/", ["/aws/elasticbeanstalk", { "Ref":"AWSEBEnvironmentName" }, "var/www/html/storage/logs/laravel_log"]]}` log_stream_name = {instance_id} file = /var/www/html/storage/logs/laravel* commands: "01": command: systemctl enable awslogsd.service "02": command: systemctl restart awslogsd
- 投稿日:2020-11-17T16:38:54+09:00
Laravel passportのログイン失敗のエラーを飛ばさないようにする
Laravel passportを使うときデフォルトでは、ユーザーのログイン認証に失敗するだけでエラーを投げるようになっている。
エラートラッキングツール(Sentryなど)を使っていると、ユーザーがログイン失敗するだけで通知が来てしまうのが面倒。Handler.pnpに、下記のように追記するとエラーが飛ばないようにできる。
app/Exceptions/Handler.phpprotected $dontReport = [ \Laravel\Passport\Exceptions\OAuthServerException::class, ];
- 投稿日:2020-11-17T16:29:34+09:00
【Laravel基礎】データの受け渡し方 【①ルートパラメータ②Implicit Binding】
概要
Laravel学習で自分がつまずいた部分を備忘録としてまとめています。
今回はデータの受け渡しに関する記事です。つまずいたポイント
記事投稿型の簡易アプリ作成時につまずいた問題です。
記事一覧ページ→記事の詳細ページに移る際、
ビュー→コントローラに投稿のデータを渡すにはどうしたら良いのか?
下記2つの方法で解決出来たので記事にしてみました。①ルートパラメータ
②Implicit Binding
以下、記事内容です!
ルートパラメータ
まず渡し方の1つがルートパラメータを用いた方法です。
■ビュー
index.blade.php@foreach ($posts as $post) <li> <a href="/posts/{{ $post->id }}">{{ $post->title }}</a> </li> @endforeachまず、ビュー上でURLを用いて、ルーティングに投稿のIDを渡します。
■ルーティング
web.phpRoute::get('/posts/{id}','PostsController@show')ここからがルートパラメータを用いた方法です。URLの中に
{ }
を設定します。
この{ }
の中身がパラメータと言う扱いになり、アクション内でこのパラメータが使用可能になります。
仮で{ }
の中身を{id}
と設定していますが、中身にはビューで設定した$post->id
が入ってきます。
※{ }は変数扱いなので、中身の文字はわかりやすい単語でOK【例】
'/post/test'
でアクセスした場合 →「test」
がパラメータ扱い
'/post/1'
でアクセスした場合 →「1」
がパラメータ扱い■コントローラ
PostsController//アクションの引数にパラーメータを設定 public function show($id) { //パラメータをアクション内で使用出来る $post = Post::find($id); return view('posts.show')->with('post', $post); }アクションの引数の中に先ほどのパラメータを代入する事で、
アクション内でそのパラメータが使用可能になります。上記のshowアクションでは、
パラメータを元にfindメソッドで該当の記事データを再取得→
記事データを渡しつつ投稿の詳細画面を表示することが出来ました。Implicit Binding
次は
Implicit Binding
です。
ルートパラメータの場合、URLに書かれた文字列だけをコントローラに渡しました。
Implicit Bindingの場合は、投稿を丸ごと渡すことが出来ます。
下記、その手順です。■ビュー
index.blade.php@foreach ($posts as $post) <li> <a href="/posts/{{ $post }}">{{ $post->title }}</a> </li> @endforeachURLに
$post
を指定します。■ルーティング
web.phpRoute::get('/posts/{post}', 'PostsController@show')先述のルートパラメータで
{post}
を指定します。■コントローラー
PostsControllerpublic function show(Post $post) { return view('show')->with('post',$post); }アクションの引数を
(Post $post)
に指定→投稿の中身を$post
で使用できます。先ほどと違い、アクション内で投稿を再取得せずに
$post
をそのまま記事詳細画面に渡すことが出来ました。楽ちんですね。まとめ
以上、Laravelにおけるビュー→コントローラへデータの渡し方でした。
Implicit Bindingの方が書くコードの量が少なくなるので効率的ですね。最後まで読んで頂きありがとうございました!
- 投稿日:2020-11-17T16:08:01+09:00
InterventionImageで編集した画像ファイルをbase64変換してMySQLに保存する
やりたいこと
InterventionImageで編集した画像ファイルをバイナリーに変換してMySQLに保存したい
もちろん画像ファイルは/public配下やS3などのファイルシステムに保存するのが定石なのは承知の上で、今回は手軽さを優先してDBに画像ファイル自体をtextカラムに保存する環境
% sw_vers ProductName: Mac OS X ProductVersion: 10.15.7 BuildVersion: 19H2 % docker version Client: Docker Engine - Community Cloud integration: 1.0.1 Version: 19.03.13 API version: 1.40 # php -v PHP 7.4.7 (cli) (built: Jun 11 2020 18:41:17) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Xdebug v2.9.6, Copyright (c) 2002-2020, by Derick Rethans # php artisan -v Laravel Framework 7.26.1 # mysql --version mysql Ver 14.14 Distrib 5.7.30, for Linux (x86_64) using EditLine wrapperIntervention Image とは
ImageMagikの上位互換?のモダンな画像編集パッケージ
リサイズ、トリミング、フィルターとなんでも手軽にできるっぽい
詳しくは公式doc参照MySQLに画像バイナリを保存する
UserControllerpublic function update(Request $request, User $user) { // InterventionImageで加工&保存 $file = $request->file('profile_img'); $img = Image::make($file); $img->fit(400); //400px * 400px にトリム&リサイズ $bin = base64_encode($img->encode('png')); $user->profile_img = $bin; $user->save(); return redirect()->route('user.index'); }ポイントは
$bin = base64_encode($img->encode('png'));
の1行。
base64_encodeする前に一度InterventionImageインスタンスをエンコードしている。
この処理がないとbase64_encodeしても空文字が生成される。なぜかはよくわからない。
- 投稿日:2020-11-17T14:23:02+09:00
Google App Engine x Laravel でroute:cache config:cacheを使う
キャッシュしてサイト高速化がしたかった
php artisan config:cache php artisan route:cacheしかし、サイトにアクセスするとエラーになる
Read-onlyの場所に書き込みがあったぞ的な。
PHP message: PHP Fatal error: Uncaught ErrorException: file_put_contents(/workspace/storage/dxcea6x78780x7e92x554x5f6dxade76x0c0x0ce.php): failed to open stream: Read-only file system in /workspace/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php:135app.yamlに追記すれば解決
app.yamlAPP_SERVICES_CACHE: /tmp/services.php APP_PACKAGES_CACHE: /tmp/packages.php APP_CONFIG_CACHE: /tmp/config.php APP_ROUTES_CACHE: /tmp/routes.php無事、キャッシュ利用してサイト高速化ができました。
参考サイト:https://kido0617.github.io/php/2019-12-17-service-env/
- 投稿日:2020-11-17T00:52:30+09:00
Laravelのget()とfirst ()が曖昧だったので取得データを見てみた
LaravelのDB検索した後のデータの扱い時、getとfirstの扱いが曖昧だったため確認して見ました。
前提
例えばid、title、bodyを持つpostデータのテーブルがあったとします。
で、そのidを持つpostを検索し、そのpostのtitleを返すコントローラーを作りたいとします。最初の状態。get()でデータを取得した。
public function post($id){ $post = Post::where('id',$id)->get();//whereで引数の$idと同一のpostを検索。 Log::debug($post);//このログの出力:[{"id":5,"title":"hoge","body":"hoge"}] return $post->title; } //詳細は省略しておりますが、上記のように「$post->title」を返そうとするとそんなプロパティないよ!と怒られエラーとなりました。
local.ERROR: Property [title] does not exist on this collection instance.なぜだ?ちゃんと出力データの中には「title」あるのに!と思ってgetやfirstの取って来ているデータを調べました。
原因
で、get()ではなくfirst()にするとうまくいったので、
それぞれのwhere直後の$postを見てみると、こんな状態になってました。first()で取得した時のデータ
{"id":5,"title":"hoge","body":"hoge"}
get()で取得した時のデータ
[{"id":5,"title":"hoge","body":"hoge"}]
何が違う?
get()の方もfirstの方も、今回「id」でwhere検索しているので、1件しか取得してないのですが
getの方は[]で囲われています。
例えば
[
{"id":9,"title":"hoge","body":"hoge"},
{"id":1o,"title":"fuge","body":"fuge"},
]
のように数件取得して、foreachで一件ずつに「->title」で呼び出すなら問題ない、
複数件前提のデータということになります。今回のように1件だけ決めうちで取りたいならfirst()を使うべきでした。
こうするとうまく動きました!$post = Post::where('id',$id)->first();