You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
10
10
### Added
11
11
12
+
-**Array value type tracking from variable-key assignments.** When an array is built incrementally with variable keys inside a loop (`$arr[$key] = $value`), the element type is now tracked. Subsequent `foreach` iteration, bracket access, and null-coalescing (`$arr[$key] ?? null`) all resolve the correct element type instead of falling back to bare `array`.
12
13
-**`Conditionable::when()` / `unless()` chain resolution.** Chained calls after `when()` or `unless()` on Eloquent Builder, Collection, and any class using the `Conditionable` trait now resolve correctly. Previously the unresolved `TWhenReturnType` template parameter in the return type broke chain continuation, so `Builder::where(...)->when(...)->get()` lost type information after `when()`.
13
14
-**`whereHas` / `whereDoesntHave` closure parameter from relation traversal.** The closure parameter in `whereHas`, `orWhereHas`, `whereDoesntHave`, `orWhereDoesntHave`, `withWhereHas`, and related methods is now typed as `Builder<RelatedModel>` instead of `Builder<CallingModel>`. The relation name string (first argument) is resolved by walking the model's relationship methods. Dot-notation chains like `whereHas('category.articles', fn($q) => ...)` follow each segment to the final related model. Works for static calls (`Brand::whereHas(...)`), builder instance calls (`$query->whereHas(...)`), and body-inferred relationships (no `@return` annotation). Falls back to the calling model's builder when the relation cannot be resolved.
14
15
-**Eloquent `where{PropertyName}()` dynamic methods.** Calls like `User::whereBrandId(42)` and `$query->whereLangCode('en')` now resolve instead of producing `unknown_member` diagnostics. For each known column on an Eloquent model (from `$casts`, `$attributes`, `$fillable`/`$guarded`/`$hidden`/`$appends`, `$dates`, timestamps, and `@property` annotations), a virtual `where{StudlyCase}()` method is synthesized on both the model (as a static method) and the Builder (as an instance method). Each method accepts a `mixed` value parameter and returns `Builder<ConcreteModel>`, so chains like `Bakery::whereFlour('rye')->whereApricot(true)->get()` resolve end-to-end.
| T22 |[Array value type tracking from loop assignments](todo/type-inference.md#t22-array-value-type-tracking-from-loop-assignments)| Medium | Medium |
27
26
| T23 |[`class-string<T>` static method dispatch](todo/type-inference.md#t23-class-stringt-static-method-dispatch)| Medium | Medium |
28
27
| T21 |[Bidirectional template inference](todo/type-inference.md#t21-bidirectional-template-inference-upperlower-bounds) (closure return type → generic) | Medium | Medium-High |
29
28
| H10 |[`return.unusedType` — remove unused type from return union](todo/phpstan-actions.md#h10-returnunusedtype--remove-unused-type-from-return-union)| Medium | Medium |
0 commit comments