Skip to content
OpenCloseEsc

Tips(21)

Short notes from real Laravel and PHP work: one idea, one snippet.

RSS feed
New
  • Laravel
  • rate-limiting
  • security
  • http

Count only the responses you choose in a rate limit

Limit::after() decides after the response which requests count: only 404s for someone guessing ids, and never 422s, so a user fixing a form does not spend their own limit.
Published on
1 min read
New
  • Laravel
  • cache
  • concurrency

Lock the rebuild, not the read

Wrap the expensive rebuild in Cache::lock() so one request fills the key while the others wait a moment and read the result.
Published on
1 min read
New
  • Laravel
  • enums
  • php

One details() match instead of label(), color() and hint()

Put everything the UI needs about a case in one array per case, and read label() and meta() from it; adding a case means one new arm, and match still throws when it is missing.
Published on
1 min read
New
  • Laravel
  • enums
  • php

Give every enum the same ten lines

A small trait adds values(), names() and options() to every backed enum, so whereIn clauses, validation lists and select inputs read the cases instead of a copied array.
Published on
1 min read
New
  • Laravel
  • database
  • enums
  • migrations

A plain string column, not a MySQL enum

Adding a case to a MySQL ENUM column is an ALTER TABLE that can lock a big table for minutes. A string column with an index stores the same values, and the PHP enum does the checking.
Published on
1 min read
New
  • Laravel
  • rate-limiting
  • http

Prefix the by() keys when one limiter returns several limits

Three limits with the same by() key share one counter: the hour limit fills up at the minute's pace. A prefix per window keeps the counters apart.
Published on
1 min read
New
  • Laravel
  • enums
  • architecture

Rules about a status live in the status

canBeCancelled() and isFinal() as methods on the enum turn a three-way string compare copied in four places into one method in one place.
Published on
1 min read
New
  • PHP
  • enums
  • validation

tryFrom() at the edges, from() inside

OrderStatus::from('xyz') throws a ValueError; tryFrom('xyz') returns null. Use tryFrom for query strings, webhooks and imports, and from where a wrong value is a bug.
Published on
1 min read
New
  • Laravel
  • eloquent
  • concurrency
  • database

lockForUpdate() only works inside a transaction

A SELECT … FOR UPDATE outside a transaction releases its lock at once, so the check-then-write gap stays open. Wrap the read and the write in DB::transaction().
Published on
1 min read
New
  • Laravel
  • cache
  • performance

Serve stale data with Cache::flexible()

flexible() returns a fresh value while it is young, serves the old one and rebuilds in the background during a grace window, and only blocks once that window has passed.
Published on
1 min read
New
  • Laravel
  • dates

Make Carbon immutable by default

One line in a service provider makes now() and every date attribute return CarbonImmutable, so addDay() stops changing the date you passed in.
Published on
1 min read
New
  • Laravel
  • eloquent
  • database

Use sole() when exactly one row must match

first() hides a duplicate and firstOrFail() hides nothing more; sole() throws when there is no row and also when there is more than one.
Published on
1 min read
New
  • Laravel
  • eloquent
  • performance
  • database

Use chunkById() when the loop changes the rows it reads

chunk() pages with OFFSET, so updating a row that leaves the WHERE clause shifts the next page and skips rows. chunkById() pages by the primary key and does not.
Published on
1 min read
New
  • Laravel
  • eloquent
  • performance

Turn lazy loading into an exception in development

Model::preventLazyLoading() makes every accidental N+1 throw while you develop, so missing with() calls are found before they reach production.
Published on
1 min read
New
  • Laravel
  • queue
  • concurrency

Keep one copy of a job in the queue with ShouldBeUnique

A job that implements ShouldBeUnique is not dispatched again while an identical one is waiting or running, so a burst of events produces one run instead of fifty.
Published on
1 min read
New
  • Laravel
  • queue
  • concurrency

Run jobs for the same record one at a time

The WithoutOverlapping middleware lets two workers process different orders in parallel but never the same order twice at once.
Published on
1 min read
New
  • Laravel
  • validation
  • enums

Validate and cast a status with one backed enum

Rule::enum() accepts only the enum's values, and an enum cast on the model gives you the case everywhere else, so the list of valid statuses lives in one place.
Published on
1 min read
New
  • Laravel
  • database
  • concurrency

Let DB::transaction() retry a deadlock

The second argument of DB::transaction() is the number of attempts: a deadlock is retried that many times before the exception reaches you.
Published on
1 min read
New
  • Laravel
  • queue
  • performance

Run small work after the response without a queue worker

dispatchAfterResponse() sends the HTTP response first and runs the job in the same process afterwards, which is enough for an email or a log line.
Published on
1 min read
New
  • PHP
  • syntax

Reach for match() instead of switch

match compares strictly, returns a value and throws on an unhandled case, which removes the three usual switch bugs in one move.
Published on
1 min read
New
  • PHP
  • syntax
  • collections

Pass methods with first-class callable syntax

strtoupper(...) and $this->toDto(...) create a Closure from a function or method, so callbacks stop being strings or arrow-function wrappers.
Published on
1 min read