もくじ
ORMさんとのお付き合い
- 利用するメソッドの戻り値をすべて把握して処理
- パラメータ配列の添字が空やNULLを考慮
- get()やfind()でオブジェクトが存在しない時の考慮
first()やget()でオブジェクトが存在しない時の考慮
大事なことです🐱
first()の場合
よくないパターン
$user_instance = new User(); $user = $user_instance->find($user_id)->first(); $user_name = $user->name;
$userのオブジェクトがnullの場合にエラーになる
職人
$user_instance = new User(); $user = $user_instance->find($user_id)->first(); if (!is_null($user)) { $user_name = $user->name; }
もしくは三項演算子で判定する $user_name = (is_null($user)) ? "" : $user->name;
get()の場合
toArray()で配列に変換にしてからコレクションが空かを判定してからプロパティを参照しよう
職人
$user_instance = new User(); $users = $user_instance->where('year', =, 20)->get(); if (!$users->isEmpty()) { $user_names = []; foreach ($users as $user) { $user_names[] = $user->name; } }
// 例で示す為にくどくなっています。Collectionが空の場合はforeach()の中が実行されないので本来はif (!$users->isEmpty()) は省略できる…🐱
または
$user_instance = new User(); $users = $user_instance->where('year', =, 20)->get(); if (!empty($users->toArray())) { $user_names = []; foreach ($users as $user) { $user_names[] = $user->name; } }
ここです🐱
if (!empty($users->toArray())) {
Collectionクラスはforeachで取得できるよ
コレクションを集計処理で使う場合は注意
- コレクションで集計などで計算する場合もtoArray()で配列化してから、集計処理をすると良い。
- コレクションのデータ量は大きいのです。配列化すると軽量になります🐱
よく使うやつまとめていく
value()
カラムを指定して値だけ取り出したい場合 value()
$user_score = self::where('user_id', $user_id) ->where('year', $setYear) ->where('period', $setPeriod) ->value('score'); return $user_score;
scoreの点数だけ取り出す
first()
先頭の1件をCollectionで取得
$user_score = self::where('user_id', $user_id) ->where('year', $setYear) ->where('period', $setPeriod) ->first(); return $user_score;
- first()やget()では値やレコードがないとエラー吐くので注意
where()
$section_kpi = new SectionKpi(); $section_kpi = $section_kpi->where('section_kpi_id', $id)->first(); if (is_null($section_kpi)) { abort(404, "部署の目標id:{$id}のデータが存在しません"); }
- find()を使わず、where() +主キーを指定する形でこっちをよく使う。
find()は空ぶった時の処理を考慮する必要があるので、findOrFail()かwhere() + 主キーが良い - nullだった場合の処理を忘れずに行うこと。
- is_nullでオブジェクトがあるか判定できる
whereIn()
SQLだとこういう形で利用するあれです。
SELECT * FROM テーブルA WHERE tableA.id IN ( SELECT tableA.id FROM テーブル名B WHERE tableB.cost > 1000 )
whereIn()を使う
$company_ids = [1, 3, 4, 6]; $staff_instance = new Staff(); $staffs = $staff_instance->whereIn('company_id', $company_ids)->where('type', 'engineer');
例) $sectionNames配列でのwhereIn()
return $query->select( 'tb_member.member_id', 'tb_member.fullname', 'tb_member.skill', 'tb_section.section_name' ) ->leftjoin('tb_section', function ($join) { $join->on('tb_section.section_id', '=', 'ud.section_id') ->where('tb_section.deleted', '=', '0'); }) ->when(isset($sectionNames), function($query) use ($sectionNames) { return $query->whereIn('section_name', $sectionNames); // ←●ここ }) ->get();
when()と組み合わせ。whenの場合はreturnが必要になるので忘れずに🐱
whereHas()
リレーション先のテーブルに条件をつけて抽出したい時に利用します。
例) departments.department_id = 99に所属するusersテーブルのデータを取得する
$users = \App\Models\User::whereHas('Department', function($query){ $query->where('department_id', 99); })->get();
is_nullでのオブジェクト判定
$sectionKpi = new SectionKpi(); // 予算を取得 $date = Carbon::now(); $now_year = $date->year; $now_period = ($date->month < 7) ? 'first' : 'second'; $my_section = $user->find($user_id)->departs()->first(); $my_sectionId = $my_section->section_id; $my_section_now_kpi = $section_kpi->where('section_id', $my_section_id) ->where('year', $now_year) ->where('period', $now_period) ->first(); $my_section_now_kpi_buffer = is_null($my_section_now_kpi) ? 0 : $my_section_now_kpi->budget; ←●
$mySectionNowKpi->budget
のようなプロパティを表示するものは、is_null()などでオブジェクトの有無を判定してから利用します。
戻り値
- オブジェクトが存在する場合
Builderクラスを返却する - オブジェクトが存在しない場合
null
複数指定もできる
$sectionKpi->where('section_id', "=", $requestParams['section_id']) ->where('user_id', "=", $requestParams['user_id']) ->where('year', "=", $requestParams['year']) ->get();
WHEREで一気に更新をかける場合の考慮
- 西暦2000年生まれのグループのユーザにかける場合
->where(‘year’, “=”, $requestParams[‘year’]) - 西暦2000年生まれのグループのユーザの名前をそれぞれを一気に更新をかける場合
ループをかけて
->where(‘user_id’, “=”, $requestParams[‘user_id’])
->where(‘year’, “=”, $requestParams[‘year’])
誤った更新が起きないように更新先テーブルのidを指定する
find() idで抽出
$depart = new Depart(); $department = $depart->find($request_params['department_id']);
- 最後に->first()や->get()はいらない
- SELECTする場合は使いやすい
- UPDATEやDELETEでは使いにくい
・where()を使うのがベター
戻り値
- ある場合
Modelオブジェクト - ない場合
null
nullの場合のケア
$mySection = $user->find($userId)->sections() ->where('year', $nowYear) ->where('period', $nowPeriod) ->where('tb_section.deleted', '=', 0) ->whereNotNull('section_parent_id') ->orderBy('created', 'desc') ->first(); if (isset($mySection)) { $mySectionId = $myDepart->section_id; $mySectionNowKpi = $sectionKpi->where('section_id', $mySectionId) ->where('year', $nowYear) ->where('period', $nowPeriod) ->first(); }
ポイント
if (isset($mySection)) { $mySectionId = $myDepart->section_id;
$mySectionがnullではないことを確認してから、プロパティを参照すること
findOrFail() idで抽出、見つからない場合は例外を投げる
idを指定することで抽出し、idが見つからない場合は例外を投げる
class UserScoreController extends Controller { public function deleteUserkpiById(Request $request) { $user_score_id = $request->user_score_id; $userScore = new UserScore(); try { $result = $userScore->findOrFail($user_score_id)->delete(); } catch (ModelNotFoundException $e) { $result = 'user_score.id not found'; return response()->json( $result, 404,[], JSON_UNESCAPED_UNICODE ); } } }
例)
try { if (!isset($request['userId'])) { return 'ユーザIDが見つかりません。<br/> <a href="/">ホームに戻る</a>'; } $userId = (int) $request['userId']; $user = Users::findOrFail($userId); } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) { return 'ユーザIDが見つかりません。<br/> <a href="/home">ホームに戻る</a>'; }
- Request $requestにuserIdがあるかチェックする(バリデーションで対応がベター)
- findOrFailで例外判定する
戻り値
- findOrFail()で該当するレコードが見つからない場合、ModelNotFoundExceptionに例外を投げてくれる。
get()
- 戻り値はCollectionクラス。foreachでそれぞれのModelオブジェクトを取得できる
- オブジェクトがあるかの判定は$collection->isEmpty()
empty($collection->toArray())
toArray()からempty()でも判定できる
戻り値
- Collectionクラス
all()
すべて取得する
戻り値
- Collectionクラス
論理削除の扱い
with()
リレーション先のデータを取得する時はこれ!
<?php namespace App\Http\Models; use Illuminate\Database\Eloquent\Model; use App\Http\Models\Users; use Carbon\Carbon; class UserScore extends Model { ・・・ public function users() { return $this->belongsTo(Users::class, 'user_id', 'user_id'); } }
users()メソッドを定義しておいて
$user = new User(); $userSections = $user::with('userSections') ←●これ ->where('section_id', '=', $user->section_id) ->get();
- UserScoreモデルのリレーション先のUserモデルのデータを取得していく!
- リレーション先から取得する場合はこれでOK!
ビューでリレーション先を出力する例
<?php isset($user->userSections) ? print $user->userSections->section_name : null ?>
- リレーションが取れているオブジェクトかどうか確認してから、プロパティを参照する。
- オブジェクトがなければnullを返す配慮が必要
with()で複数のリレーションやネスと先も取得できるぞ
@see
save() 保存や更新を行う
レコードのInsertやupdateを行います。そのままリクエストを入れていくのでセキュリティリスクがあります。
$fillable, $guardedを指定しましょう。
- $fillable … ホワイトリスト。指定したカラムのみにCreateによって代入を許可する
- $guarded … ブラックリスト。指定したカラムにはCreateによって代入させない。
これを指定しましょう
フォームで受け取ったリクエストに値を追加する場合
$request_params = $request->all(); if (isset($request->day[0]) && is_array($request->day)) { $manDay = array_map('intval', $request->day); // int型に配列を変換 $request_params['child_day'] = array_sum($childDay); } $project->fill($request_params); $project->save();
一旦$request->all()で変数に受け取ってから->fill()を経由して->save()を行います🐱
新規登録する
$section = new Section(); $section->fill($request_params); $section->save();
更新する
更新はidをfindOrFail()で指定してModelを取ってきて、こちらもsave()で更新する
$section = Section::findOrFail($request_params['section_id']); $section->fill($request_params)->save();
delete() 削除する
$userScore = new UserScore(); $deleteUserScoreCount = $userScore->where('id', $request->user_score_id)->delete(); if ($deleteUserScoreCount > 0) { $result = 'true'; return response()->json( $result, 200,[], JSON_UNESCAPED_UNICODE ); } $result = 'false'; return response()->json( $result, 404,[], JSON_UNESCAPED_UNICODE );
戻り値
- 削除したレコード数を返す
orderBy()
- orderBy(‘カラム名’, ‘desc’)
降順で取得…値が大きい順に取得 - orderBy(‘カラム名’, ‘asc’)
昇順で取得…値が小さい順に取得
例) 部署の作成日が新しい順に取得
$mySection = $user->find($userId)->sections()->orderBy('created', 'desc')->get();
- ->get()で複数取得
- ->first()で1つ取得
コレクション Collection
pluck() 特定のカラムのみ抽出する
$section_id = (int) $request['section_id']; $section = new Section(); $section_staffs = $section->find($section_id)->users()->pluck('full_name', 'tb_user.user_id');
map()による加工
filter()による抽出
テスト
- その関数が取得する値が存在しない場合のチェック
→nullや0を返しているか?
テストすること
少しずつ追加していくのだ🐹