闇鍋

趣味も勉強も全部ごった煮。質より量より継続重視

Laravel 個人的知見まとめ ※随時更新

実務を通して知ったことなどをメモ書きしていく。

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\AuthServiceProviderbootメソッド内に定義していく。

「管理者」のみユーザーの編集権限を与えたい、みたいな場面

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;
    });
}

コントローラーなどから呼び出す時はallowsdeniesメソッドを使用

class UserController extends Controller
{
    public function updateUser(Request $request)
    {
        if (! Gate::allows('edit-user')) {
            abort(403);
        }
    }
}

認証ユーザーは勝手に渡されるので、特に指定する必要はない。 第二引数以降を渡したい場合は、allowsdeniesの第二引数に渡してあげればOK

 if (! Gate::allows('update-post', $post)) {
     abort(403);
}

またはauthorizeを使用すれば、許可されていない場合は自動的に403を返してくれる。

Gate::authorize('edit-user');

他にもポリシーというものもあるので、それはまた今度調べてみる。

参考:

readouble.com

コレクションの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')
        ];
}

qiita.com

これ日本語の公式ドキュメントのどこに書いてあるんだろう…???

モデルの属性のキャスト

1/0で保存している値をbool型に変換して取得したい、みたいな時に使う モデルの$castsプロパティにカラム名と変換したい型を指定すれば良い

protected $casts = [
     'is_admin' => 'boolean',
]

PHPEnumにキャストすることも可能

use App\Enums\ServerStatus;

/**
 * キャストする属性
 *
 * @var array
 */
protected $casts = [
    'status' => ServerStatus::class,
]

余談

Enumのことよく知らないんだけど、 「Laravelのパッケージ(ライブラリ?)のEnum」と、「PHP8.1から使えるようになったEnum」があるのか??

laravel-enum

github.com qiita.com

PHPEnum

www.php.net qiita.com