Repository navigation
v1.22.0
What most Laravel applications reach for every day: forms that post _method, validation that redirects back, file downloads with Range, 22 more validation rules, route model binding with scoping, subdomains, JSON columns, and helpers on relations. daravel_pulse now shows N+1 queries and connection waits, and daravel_teobiefy reads the Zstandard frames real clients send.
Upgrading can change what an application sees:
- A failed validation in the
webgroup redirects back, unless the client expects JSON.Request.expectsJsonfollows Laravel: an XHR that asks for HTML is not JSON. _methodis on by default. A POST route that streams a form body needsmiddleware.methodOverride = false.- Since 1.21.1 a
tryaroundnextcatches nothing, in any middleware. Read the newresponse.exceptioninstead. whereJsonContainssends JSON on MySQL and PostgreSQL. Code that encoded the value itself now encodes it twice.UniqueRule.ignoreis a method; the field isignored.
Fixed
- PostgreSQL
inet,cidr,macaddrandmacaddr8columns came back as undecoded bytes, so comparing one withrequest.ipalways failed. They are text now, as PostgreSQL prints them, andmodel:synctypes them asString. - Validation errors in a JSON session use the bag format of Laravel 13 (
{default: {format, messages}}), which itsStore::marshalErrorsneeds. whereJsonContainssends a JSON document on MySQL and PostgreSQL, as Laravel: a plain number or string failed there.daravel_teobiefy: refusals (406, 409, 413, 401) follow the route's response profile, as upstream'sapi()->response().accepted_ifanddeclined_if: with abooleanrule on the other attribute,trueandfalsecompare as booleans, and:otheruses the custom attribute names.
Changed
Request.expectsJsonfollows Laravel: an XHR that asks for HTML, as an Inertia visit does, no longer counts as JSON.
Added
Response.exception, Laravel's$response->exception: since 1.21.1 an exception no longer passes throughnext, so atryaroundnextcatches nothing, not only in transaction middleware. A middleware reads it here instead.DB.transaction(attempts: n)waits a short random time between retries (decorrelated jitter, 2 to 250 ms), so isolates that collided do not collide again. Frozen test clocks retry at once.QueryExecuted.poolWait: the time a query waited for a connection, apart fromtime. PostgreSQL and MySQL measure it while a listener is registered.daravel_pulse: cards for N+1 queries and query storms (PULSE_N_PLUS_ONE_THRESHOLD,PULSE_QUERY_STORM_THRESHOLD) and for connection waits (PULSE_POOL_WAIT_THRESHOLD).dartisan route:diff --by-prefix: progress per module.Cache.touch(key, ttl),WithoutOverlapping(key, shared: true)andReadThroughDisk, Laravel's read-through filesystem for moving files to a new disk gradually.- Subdomain routing:
router.group(domain: '{tenant}.example.com')and.domain(), with routes of the same path on different hosts, host parameters before path ones, androuter.url()on that host.Request.fakenow takes its host from ahostheader, as the socket path does. - Route model binding:
router.bindModel('post', Post.definition),{post:slug},.scopeBindings()(implied by a custom column, as in Laravel) so another owner's row is a 404,.withoutScopedBindings(),.withTrashed()and.missing(). It is explicit: a Dart handler has no parameter types to tell a model from an id. - ORM helpers:
BelongsTo.withDefault,HasOne.latestOfMany,oldestOfManyandofMany(one query when eager loading),syncWithoutDetaching,toggleandupdateExistingPivot, onBelongsToManyand on the model,updateQuietly,deleteQuietly,namedGlobalScopeswithwithoutGlobalScope(name), andQueryBuilder.whereNone. - JSON columns:
where('meta->lang', 'id'),orderByandupdate({'meta->lang': 'en'})on SQLite, PostgreSQL and MySQL, as Laravel compiles them. Writing a nested path needs its parent on PostgreSQL and MySQL, as in Laravel; SQLite creates it. Tested live on SQLite, PostgreSQL, MySQL 8.4 and MariaDB 11. withoutMiddleware(['csrf'])takes aliases, groups, types and instances, also those from an outer group.- 22 validation rules:
gt,gte,lt,lte,decimal,multiple_of,min_digits,max_digits,date_equals,timezone,required_with_all,required_without_all,required_if_accepted,present_if,prohibited_if,prohibited_unless,prohibits, and theexcludefamily, which leaves attributes out ofvalidated(). Numbers compare as exact decimals.timezonealso accepts old IANA aliases, and notper_country. Rules.enum_, andRules.unique(...).ignore(id),.where(...)andRules.exists(...).where(...). Both rules acceptschema.table, which failed with anArgumentError.Response.download,Response.file,Storage.downloadandStorage.response, with RFC 6266 file names,ETag, andRange(206) when given the request.deleteFileAfterSendremoves a temporary file once it was sent. Several ranges in one request get the whole file._methodandX-HTTP-Method-Overrideturn a POST into PUT, PATCH or DELETE, on by default as in Laravel; only form bodies are read.Request.originalMethodkeeps the verb on the wire.- A failed validation in the
webgroup redirects browsers and Inertia back, with errors and old input flashed (session.errors,session.old); clients expecting JSON keep the 422.Response.backignores a foreignReferer. - Remember-me cookies in
SessionGuard:attempt(..., remember: true)andlogin(user, remember: true)write Laravel'sremember_web_<sha1>cookie, and either side can log in from the other's. - Payload profiles of teobiefy-laravel-api-response 0.3 in
daravel_teobiefy:withTeobiefyProfiles()and theteobiefy.profilemiddleware (route patterns, XChaCha20, ChaCha20 and AES-256-GCM with key ids, HMAC-SHA256, replay protection). Responses are raw frames; requests may use any frameext-zstdwrites, read by a pure Dart decoder. ModelQuery.orderByRaw,KeyType.manualInt(Laravel's$incrementing = falseon an integer key),Request.inputSyncfor model scopes, andClock.nowIn('Asia/Makassar').