はじめに 最近 Laravel を使うことが増えました。 だんだん使い方が分かってきたのですが、おそらく数年後には忘れてしまっていると思います。。 その時のために使い方を簡単にメモしておきます
目次
テンプレート 表示するビューの外側を共通化 表示するビューの外側を共通化したい場合です 例えば<head>
タグとかですね。 正確には共通化というより継承ですね
ファイル名の例:resources/views/layout/base.blade.php
基本的にはそのままコードを記載し、下のコードを呼び出す部分に@yield('content')
を書く
1 2 3 4 5 6 7 @extends('layout.base' ) @section('content' ) aaa @endsection
表示するビューの内側(一部分)を共通化 表示するビューの内側(一部分)を共通化したい場合です 例えばフォーム部品とかですね。 正確には共通化というよりコンポーネント化ですね
そのままコードを記載するだけ
1 2 3 @component('hoge.test' , ['user' => $user]) @endcomponent
ソートしたい時 以下のライブラリを利用するhttps://github.com/Kyslik/column-sortable
デフォルトのソート順を変更したい時は以下ファイルを変更する
config/columnsortable.php
1 2 3 4 5 - 'default_direction' => 'asc' , + 'default_direction' => 'desc' , - 'default_direction_unsorted' => 'asc' , + 'default_direction_unsorted' => 'desc' ,
モデル テーブル 作成(マイグレーション) Laravel はマイグレーション機能があります つまりコードから DB を自動作成できます
参考https://readouble.com/laravel/5.5/ja/migrations.html
1 2 3 4 5 6 7 php artisan make:migration create_users_table php artisan migrate php artisan migrate:rollback
データベース から Model ファイルを作成したい時 1 php artisan code:models --table=users
初回は設定が必要 以下の手順に従う
Laravel + Eloquent で reliese/laravel を用いてモデルクラスを Scaffolding する
INSERT・UPDATE 1 2 3 4 5 6 7 8 if (User::where("hoge_id" , $hoge["id" ])->exists()) { $user = User::where("hoge_id" , $hoge["id" ])->first(); $user->fill($request->except(['_token' ]))->save(); } else { User::create($request->except(['_token' ])); }
複雑な WHERE 条件 1 2 3 4 5 6 $hoge = 1 ; $users = User::where("status" , 'new' ) ->where(function ($query) use ($hoge) { $query->where('user_id' , '=' , $hoge)->orwhere('user_id2' , '=' , $hoge); }) ->get();
コントローラー URL とコントローラーの紐付けを設定したい時 参考https://readouble.com/laravel/5.5/ja/controllers.html
routes/web.php
を以下のように記載する
1 2 3 4 Route::get('/user/edit' , 'User\HomeController@edit' ); Route::post('/user/edit' , 'User\HomeController@postEdit' );
ログを出力したい時
1 tail -f storage/logs/laravel.log
その他
ページネーションを利用したいとき
1 $users = DB::table('users' )->paginate(15 );
1 2 3 4 5 6 7 <div class="container"> @foreach ($users as $user) {{ $user->name }} @endforeach </div> {{ $users->links() }}
参考https://laravel.com/docs/7.x/pagination
全文検索したい時 基本的には以下の記事の通りにすれば OKLaravel + MySQL5.7 で日本語全文検索をする方法とちょっとした注意点
上の記事はテーブル生成と同時にインデックスを作成してますが、後からインデックスを貼りたい場合は以下のようにすれば可能です。 対象の複数カラムを結合した新しいカラム(fulltext_column)を作成してます。
1 2 DB::statement("ALTER TABLE videos ADD fulltext_column TEXT AS (CONCAT(video_name, ' ', overview, ' ', product_name)) STORED" ); DB::statement('ALTER TABLE videos ADD FULLTEXT index fulltext_index (`fulltext_column`) with parser ngram' );
ページネーションを利用している場合 記事にあるようにクラスのスコープを利用すると取得データが 0 件になる不具合があるので以下のように記載すると良いです
1 2 - $videos = Video::freeword($request->search_word)->sortable()->paginate(2 ); + $videos = Video::whereRaw("match(`fulltext_column`) against (? IN NATURAL LANGUAGE MODE)" , [$request->search_word])->sortable()->paginate(2 );
ページネーション部分には以下のようにwithQueryString()
を付けると2ページ目以降に検索ワードが引き継がれます
1 {!! $videos->withQueryString()->appends(\Request::except('page' ))->render() !!}
変更が画面反映されない時 おそらくキャッシュが残ってしまっているのでキャッシュを削除する
1 2 3 4 php artisan cache:clear php artisan config:clear php artisan route:clear php artisan view:clear
コメントアウトしてるのにエラーになる コメントアウトしている箇所も読み込まれます ので内容が不正であればエラーになります
join したカラムが利用できない join するテーブルに同じカラム名がある場合は以下のように select を使って別名にする必要があります。
1 2 3 $user = User::leftJoin("ranks" , "ranks.id" , "=" , "users.rank_id" ) ->select("ranks.name as rank_name" , "users.*" ) ->first();
link タグが読み込まれない パスの最初に/
がないとトップページ以外の画面で読み込まれませんでした
1 2 3 4 <link rel ="stylesheet" type ="text/css" href ="fontawesome/css/all.css" /> <link rel ="stylesheet" type ="text/css" href ="/fontawesome/css/all.css" />
Class ‘App\Http\Controllers\Hoge’ not found コントローラーファイルの位置に合わせて namespace も変更する必要がある 修正箇所はHoge.php
の以下の行
1 namespace App \Http \Controllers \Hoge ;
ログイン機能 以下の記事に従うLaravel のログイン認証の基本(Authentication)を完全理解する
Laravel のバージョンによってはphp artisan make:auth
がエラーになる その場合は以下で同じコマンドになる
1 2 3 4 5 composer require laravel/ui --dev php artisan ui vue --auth php artisan clear-compiled php artisan optimize php artisan view:clear
画像をアップロードする blade
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 <div > <form method ="POST" enctype ="multipart/form-data" > @csrf <div class ="row file_upload" > <div class ="col-2 col-form-label text-center" > <label > 関連ファイル</label > </div > <div class ="col-10" > <?php foreach (range(1 , 5 ) as $value) { echo '<div class="custom-file mb-3">' ; echo '<input type="file" class="custom-file-input" name="file' . $value . '" id="file' . $value . '">' ; echo '<label class="custom-file-label" for="file' . $value . '" id="file' . $value . '_label">選択されていません</label>' ; echo '</div>' ; echo '<img id="file' . $value . '_preview" class="preview">' ; } ?> </div > </div > <div class ="form-group text-center mt-5" > <input type ="submit" name ="submit" class ="btn btn-primary" value ="送信" > </div > </form > </div > <script type ="text/javascript" > function show_preview (id) { if ($(id).val() == '' ) return const file = $(id).prop('files' )[0 ]; $(id + '_label' ).text(file.name) $(id + '_preview' ).attr('src' , null ); if (file.type.slice(0 , 5 ) != 'image' ) { $(id + '_preview' ).attr('src' , '/assets/images/file.png' ); return } load(file, function (canvas) { console .log('読み込み完了' ) canvas.toBlob(function (blob) { var blobUrl = window .URL.createObjectURL(blob); $(id + '_preview' ).attr('src' , blobUrl); $(id).attr('src' , canvas.toDataURL()); }); }); function load (file, callback) { var options = { canvas: true , }; loadImage.parseMetaData(file, function (data) { if (data.exif) { options.orientation = data.exif.get('Orientation' ); } loadImage(file, callback, options); }); } } for (let i = 1 ; i <= 5 ; i++) { $('#file' + i).on('change' , function ( ) { show_preview('#file' + i) }); } </script >
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 for ($i = 1 ; $i <= 5 ; $i++) { $file = $request->file('file' . $i); if ($request->hasFile('file' . $i) && $request->file('file' . $i)->isValid()) { $file = $request->file('file' . $i); $extension = $request->file('file' . $i)->extension(); $file_name = md5(uniqid(mt_rand(), true )) . '.' . $extension; $path = Storage::putFileAs("public/hoge/" . $hoge["id" ], $file, $file_name, 'public' ); $input = []; $input["hoge_id" ] = $hoge["id" ]; $input["file_name" ] = $file->getClientOriginalName(); $input["file_path" ] = "/storage/hoge/" . $hoge["id" ] . "/" . $file_name; $this ->correct_image_rotation($input["file_path" ]); PatientFile::create($input); } }
iPhone で撮った写真は縦向き・横向きが逆になる場合があるので、correct_image_rotation 関数で回転補正してます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public function correct_image_rotation ($img_path) { \Log::info('回転補正開始' ); $imagick = new \Imagick(); $url = env("APP_URL" ) . $img_path; $image = file_get_contents($url); $imagick->readImageBlob($image); $format = strtolower($imagick->getImageFormat()); if ($format === 'jpeg' ) { $orientation = $imagick->getImageOrientation(); $isRotated = false ; if ($orientation === \Imagick::ORIENTATION_RIGHTTOP) { $imagick->rotateImage('none' , 90 ); $isRotated = true ; } elseif ($orientation === \Imagick::ORIENTATION_BOTTOMRIGHT) { $imagick->rotateImage('none' , 180 ); $isRotated = true ; } elseif ($orientation === \Imagick::ORIENTATION_LEFTBOTTOM) { $imagick->rotateImage('none' , 270 ); $isRotated = true ; } if ($isRotated) { $imagick->setImageOrientation(\Imagick::ORIENTATION_TOPLEFT); } } $imagick->writeImage(ltrim($img_path, "/" )); }
アップロードした画像を表示する Controller
1 2 $hoge_files = HogeFile::where("id" , $id)->get();
blade
1 2 3 4 5 @foreach ( $hoge_files as $hoge_file) <a href="<?= $hoge_file->file_path ?>" target="_blank" > <img src=' <?= $hoge_file->file_path ?>' style="width:100px" > </a> @endforeach
view の変数を JavaScript 側で利用したい時 View
1 2 3 4 5 <script type="text/javascript" > const users = @json($users); users.forEach (user => { }) </script>
ローカルのファイルを読み込みたい時 1 <script src ="{{url('assets/js/plugins/quagga.min.js')}}" > </script >
ベストプラクティス