実務を通して知ったことなどをメモ書きしていく。
upsert()でバルクアップデート出来る
バルクアップデートというか、実行されるのはINSERT ... ON DUPLICATE KEY UPDATE
なので、
「更新対象が存在すれば更新、なければ挿入」というやつ。
updateOrCreate
は1レコードに対して行うが、upsert
は複数レコードに対して行うことが出来る。
こちらの例を引用させていただいて…
User::upsert( [ ['id' => 1, 'name' => 'かっちゃん', 'age' => 30, 'address' => '北海道'], ['id' => 2, 'name' => 'さわやん', 'age' => 28, 'address' => '大阪'], ['id' => null, 'name' => 'もりりん', 'age' => 34, 'address' => '愛知'] ], ['id'], ['age', 'address'] );
- 第一引数: 挿入/更新を行いたい値を配列で渡す
- 第二引数: レコードの特定に使用するカラムを指定
- 第三引数: UPDATEを行う際に更新したいカラムを配列で渡す。未指定の場合、全カラムが対象となる
この第三引数でちょっと躓いたので太字に。 第一引数で値渡しているのに、なんか更新されないぞ?となったら第三引数を確認してみよう。
ちなみに、第一引数ではINSERTするのに必要なデータをすべて渡す必要がある。
どういうことかと言うと、
例えばuserテーブルにpost_id
という外部キーがある時、post_id
は更新対象ではないからと第一引数の配列から省くとエラーになる。
Field 'post_id' doesn't have a default value
バルクアップデートとは言うものの行うのはあくまでもINSERTなので、INSERTで必要になるカラム(null許可していない、デフォルト値がないなど)の情報はすべて渡してあげないといけないらしい。
参考: nextat.co.jp
Gateを使用した権限チェック
認可の機能のGateを使うことで、ユーザーが特定のアクションを実行することを許可されているかどうかの判断ができる。 例えば、「管理者」と「一般ユーザー」のようにいくつかロールがあり、行える操作が異なるようなシステムの場合に活躍する。
通常、App\Providers\AuthServiceProvider
のboot
メソッド内に定義していく。
「管理者」のみユーザーの編集権限を与えたい、みたいな場面
AuthServiceProvider
内に以下のように定義
public function boot(): void
{
Gate::define('edit-user', function (User $user) {
return $user->is_master;
});
}
※is_masterはテーブルのカラムやアクセサで定義されている想定
第一引数には必ずユーザーインスタンスが渡され、他に渡したい引数があれば第二引数以降に指定していく。
public function boot(): void { Gate::define('update-post', function (User $user, Post $post) { return $user->id === $post->user_id; }); }
コントローラーなどから呼び出す時はallows
かdenies
メソッドを使用
class UserController extends Controller { public function updateUser(Request $request) { if (! Gate::allows('edit-user')) { abort(403); } } }
認証ユーザーは勝手に渡されるので、特に指定する必要はない。
第二引数以降を渡したい場合は、allows
・denies
の第二引数に渡してあげればOK
if (! Gate::allows('update-post', $post)) { abort(403); }
またはauthorizeを使用すれば、許可されていない場合は自動的に403を返してくれる。
Gate::authorize('edit-user');
他にもポリシーというものもあるので、それはまた今度調べてみる。
参考:
コレクションのpluck()
コレクションの機能ではあるけど、主な使い所はModel経由でDBのデータを取得した時に使う印象。
例えば、userテーブルからidだけの取得してそれを配列に格納したい場面
$users_collection = User::all(); $user_ids = $users_collection->pluck('id')->toArray();
と書くことでidだけの配列を作ることが出来る。
また、idをキーとするnameの配列を作りたい場面
$user_names_by_id = User::all()->pluck('name', 'id')->toArray();
pluck(value, key)
の順で渡すことで作ることが出来る。第一引数がvalueなのが注意。
paginate()で取ってきたデータを変換できるthrough()
paginate()->through()
のようにメソッドチェーンで繋げて、データを加工したりなんなりして返すことが出来るものっぽい
Contact::paginate()->through(function ($contact) { return [ 'id' => $contact->id, 'name' => $contact->name, 'phone' => $contact->phone, 'city' => $contact->city, 'organization' => optional($contact->organization)->only('name') ]; }
これ日本語の公式ドキュメントのどこに書いてあるんだろう…???
モデルの属性のキャスト
1/0で保存している値をbool型に変換して取得したい、みたいな時に使う
モデルの$casts
プロパティにカラム名と変換したい型を指定すれば良い
protected $casts = [
'is_admin' => 'boolean',
]
use App\Enums\ServerStatus; /** * キャストする属性 * * @var array */ protected $casts = [ 'status' => ServerStatus::class, ]
余談
Enumのことよく知らないんだけど、 「Laravelのパッケージ(ライブラリ?)のEnum」と、「PHP8.1から使えるようになったEnum」があるのか??