What’s Changed
This release brings names scope support into a brand new level!
-
#1032— Instance scope calls onBuilderresolve toBuilder<Model>instead ofmixed
Customer::query()->active()now returnsBuilder<Customer>; arguments are type-checked against the scope's declared params (minus the leading$query). Covers both legacyscopeXxx()and#[Scope]-attributed methods on the base builder. -
#1033— Scopeself/staticparameters pin to the correct class
Scope params typedselfresolve to the trait's composing class (not the queried subclass), andstatic/$thisresolve to the queried model. Eliminates false-positiveInvalidArgumentwhen a sibling child is passed to a trait-hosted scope. -
#1034/#1036— Direct scope calls use the real method signature
Calling a#[Scope]method directly ($this->otherScope($query, ...)or any accessible bare-name call) no longer shifts arguments left or fabricatesBuilder<Model>as the return type. TheisDirectScopeCallclassifier decides by PHP dispatch semantics, not argument shape — nullable?Builder, variadic scopes, non-variable expressions all classify correctly. -
#1039— Variadic and named-arg scope calls work on forwarded path
A scope with a variadic tail keeps its variadic flag after$queryis stripped; zero-arg calls are valid and extra args don't drawTooManyArguments. -
#1039— Scope names that collide with realEloquent\Buildermethods no longer mask the real return type
Model::query()->find(1)now correctly returnsModel|nulleven whenscopeFind()exists on the model. Names that route through__call(likecount/sumpassthru aggregates) remain scope-eligible. -
#1031/#1043— Trait-hosted scopeselfresolves to the composing class, not the subclass (behavior change:InvalidArgumentmessage shifts from the queried child to the abstract parent when the trait is composed on a parent)
QueryingContract::query()->rankedAbove($receipt)— whereContractinheritsComparesRankfrom its abstract parent — now accepts sibling children instead of rejecting them with a false positive. -
Consume-once hand-off for scope params (#1042)
A scope call on one model no longer leaks its zero-arg signature into a subsequent same-namedSoftDeletesmacro call on a different model. -
SuppressHandlercorrectly treats private#[Scope]methods as unused (not silenced as scope entry points).
Full Changelog: v4.12.4...v4.13.0