Skip to content

Database & Eloquent (project conventions)

  • Casts via the casts() method + ide-helper annotations (see php-laravel.md).
  • Named scopes for domain queries (aggressive) — a scopeForDate so call sites read Plan::forDate($today), not ::where('plan_date', $today). For "the latest related row per parent" use a hasOne(...)->latestOfMany('col') relation and eager-load it — never a method that re-queries inside a loop, and never limit(1) on an eager-loaded hasMany (it limits total rows, not per parent):
    php
    public function latestRun(): HasOne { return $this->hasOne(Run::class)->latestOfMany('started_at'); }
    // usage: Job::with('latestRun')->get();  // one query, not N+1
  • N+1s are bugs to fix aggressively — not a Tier-3 nicety. Any loop touching a relation is suspect. Eager-load with with(), and add a query-count regression test so it can't creep back:
    php
    DB::enableQueryLog();
    // ...exercise the code...
    expect(DB::getQueryLog())->toHaveCount(2); // bounded, not N+1
  • Migrations: one logical change each; foreignId()->constrained(); precise types (decimal for money, never float); index what you filter/sort/join on; real down(). Add credential/secret columns with an encrypted cast (and $hidden — see security.md).
  • Wrap multi-step writes in DB::transaction(...).