larastan: Method calls on custom query builder to public parent methods are wrongly reported as private

  • Larastan Version: 2.1.11
  • --level used: 7
  • Pull request with failing test: <none>

Description

If one creates a trait to equip a model with a custom query builder, then methods calls on the custom query builder which are defined in Illuminate\Database\Query\Builder are wrongly reported as private.

Laravel code where the issue was found

I prepared the following GITHub repository with a minimal Laravel application: https://github.com/nagmat84/larastan-example. Step to reproduce the problem:

  1. Checkout the repository
  2. Install all dependencies via composer install
  3. Run PHPStan via composer phpstan

You will get the following output

 ------ ---------------------------------------------------------------------------------------------------------- 
  Line   Http/Controllers/Controller.php                                                                           
 ------ ---------------------------------------------------------------------------------------------------------- 
  18     Call to private method whereBetween() of parent class Illuminate\Database\Eloquent\Builder<TNodeModel of  
         App\Models\Contracts\Node&Illuminate\Database\Eloquent\Model>.                                            
 ------ ----------------------------------------------------------------------------------------------------------

However the method is not private.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 2
  • Comments: 18

Most upvoted comments

Yes, this is the only error which also remains for the branch full_example. It would be nice to get a fix for that.

Fixed in #1299

I updated my example at https://github.com/nagmat84/larastan-example. It is now even more trivial and does not use any interface or any intersection type. But the errors are still there. IMHO this needs to be fixed, because it is a very typical pattern that models are augmented via traits.

That is not going to happen. Rather we migrate the whole project away from Laravel to Symfony.

Not only due to this problem at hand, but because we had a long history of fuck-ups due to Laravel’s stupid architecture. (Yes, I am aware that Laravel and Larastan are two different projects.) In the past I used Symfony for other project which had a much more complex DB model than the current Laravel project and I never ever encountered any of the many problem we already had with Laravel despite the fact that the current project is much simpler. (I don’t want to know what would have happened, if we had tried to realize the other projects in Laravel.)

So before I start duplicating code and create a maintainability hell for the future, I rather take the effort to migrate the whole project.

Unfortunately, the problem is back again in https://github.com/nunomaduro/larastan/pull/1285 after I have added a test class for custom relations.

I can confirm that #1299 fixed it, see here https://github.com/nagmat84/larastan-example/runs/7161581815?check_suite_focus=true.

I will now use what I have learned (i.e. that you must not rename the template parameter!) and apply it to our actual code. May be there are still other problems, but that another issue then.

Is there any chance that #1299 gets back-ported to Larastan 1.x. Our project is still stuck at Laravel 8 due to various reasons.

I cannot reproduce Call to private method whereBetween() of parent class ... error on the example repo.

Sorry, for that. I pushed an even smaller MWE after @szepeviktor suggested in his post that the intersection types might be the problem (even though he wrongly called them union types). In doing the original error changed from “call to private method” into “call to undefined method”.

I followed your advices (see below) and also reverted the example repo to the full example (note that the default branch has changed).

* If you rename generic types `TNodeModel` to `TModelClass` it gets rid of the other error. I know this could be improved, but for now this is a workaround.

Great. This did not only solve the problem “call to undefined method” for the branch trivial_example, but also solved the problem “call to private method” for the branch full_example and any other error. Now, PhpStan is even happy with the intersection types.

I don’t understand why one must not rename the template parameter, but I can live with that restriction. IMHO, there should be a bold, eye-catching warning in the documentation that one must not rename inherited template parameters.

* Last remaining error is because `newModelQuery` does not have correct stubs in Larastan. But for example if you change it to `Node::query()` you'll see it works. I'll try to update the stubs later.

Yes, this is the only error which also remains for the branch full_example. It would be nice to get a fix for that.