You're correct that this is a static analysis limitation: PHPStan (and Larastan) can't "see" dynamically added methods like withTrashed() on Eloquent relationships, because they're added at runtime via macros.
The cleanest solution is to use PHPStan's extension mechanism to teach it about these dynamic methods. Larastan already provides some support for Eloquent magic, but for custom macros or traits (like MongoDB's SoftDeletes), you may need to help it further.
Solution 1: Use Larastan's Helper Docblocks
Larastan reads PHPDoc @method annotations. For your case, you can add a docblock to your trait or model to inform PHPStan about withTrashed():
/**
* @method static \Illuminate\Database\Eloquent\Builder|static withTrashed(bool $withTrashed = true)
*/
class PipelineModel extends Model
{
use \MongoDB\Laravel\Eloquent\SoftDeletes;
// ...
}
Or, if you want to annotate the relationship method:
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo|\Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\PipelineModel>
* @method \Illuminate\Database\Eloquent\Relations\BelongsTo withTrashed(bool $withTrashed = true)
*/
public function pipeline(): BelongsTo
{
return $this->belongsTo(PipelineModel::class, Constants::PIPELINE_REL_DB_FIELD)->withTrashed();
}
But this can get verbose and repetitive.
Solution 2: Use PHPStan's phpstan.neon to Ignore the Error
If the above doesn't work or is too cumbersome, you can tell PHPStan to ignore this specific error pattern:
# phpstan.neon or phpstan.neon.dist
parameters:
ignoreErrors:
- '#Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\BelongsTo::withTrashed#'
This is pragmatic and safe, since you know the method exists at runtime.
Solution 3: Write a PHPStan Extension (Advanced)
If you want a robust, project-wide fix, you can write a PHPStan dynamic return type extension for Eloquent relationships, but this is more involved and usually overkill unless you have many such macros.
Summary
- Recommended: Use
@methodPHPDoc on your models or relationships to inform static analysis. - Pragmatic: Use
ignoreErrorsin yourphpstan.neonfor this specific error. - Advanced: Write a PHPStan extension if you need full static analysis support for macros.
For most teams, the ignoreErrors approach is the most maintainable and least intrusive.
Let me know if you want a sample PHPStan extension for this!