Vscode-intelephense: Undefined method when scope is an interface but implementation class is expected or configured

Created on 9 Mar 2020  路  17Comments  路  Source: bmewburn/vscode-intelephense

Describe the bug
There is missing autocompletion when a trait is applied to the class.

To Reproduce
First I've been added Laravel/Passport package. Then added use HasApiTokens trait to User model. Then I tried to call createToken method and Undefined method 'createToken'.intelephense(1013) occurs.

Expected behavior
createToken method should appear in the list of autocompletion.

Screenshots
image
image

Platform and version
Windows 10, WSL(Ubuntu-18.04), Intelephense 1.3.11

Most helpful comment

Using 1.5.4 this still doesn't seem to work.

image

All 17 comments

This line below is probably setting the type of $user to an interface that does not have the method defined.

$user = auth()->user();

When you hover on $user of the above code what type does it show?

I have got the same error. Help Please!

This line below is probably setting the type of $user to an interface that does not have the method defined.

$user = auth()->user();

When you hover on $user of the above code what type does it show?

I also have the same problem
when I hover on $user it shows :

```
Illuminate\Contracts\Auth\Guard::user
Get the currently authenticated user.
public function user() { }
@return \Illuminate\Contracts\Auth\Authenticatable|null

Yes, this is the source of many issues in my projects as well. Because if you use Auth::user() the extension does not know it's actually a user model. So my workaround for these issues is:

        /** @var \App\Models\User */
        $currentUser = Auth::user();

That really clutters the code tho, that's a downside. I wish intelephense would automatically know it's an instance of a user model.

@bmewburn - is that enough information?

Laravel's docblock for Auth::user() is that it returns a contract:

<?php

namespace Illuminate\Contracts\Auth;

interface Guard
{
    /**
     * Determine if the current user is authenticated.
     *
     * @return bool
     */
    public function check();

    /**
     * Determine if the current user is a guest.
     *
     * @return bool
     */
    public function guest();

    /**
     * Get the currently authenticated user.
     *
     * @return \Illuminate\Contracts\Auth\Authenticatable|null
     */
    public function user();

.... the User model/class in your application uses this interface.

Technically intelphense doesn't know that so it says that methods don't exist when in fact they most likely do. So you have to type hint to intelephense what's returned is a version of your user model:

<?php
/** @var \App\User|null $user */
$user = $this->auth->user();

As someone else mentioned, this does clutter your code a fair bit. I'm not sure what the alternative would be though, Laravel does this pretty much everywhere - it returns a "Contract" interface in the docblock.

Another issue with Laravel support for intelephense is with facades. It often complains:

<?php

Route::get('some-url');
?>

This will be marked as not knowing what Route is, it's a facade added by Laravel. I guess the workaround for that is to use https://github.com/barryvdh/laravel-ide-helper ?

@garygreen is correct. Intelephense is working as expected here. Using @var is kind of equivalent to a cast to the User model but it is verbose. Other option is to create a helper function annotated to return the expected type and call it instead. Will leave this one open to see if this can be improved somehow.

This line below is probably setting the type of $user to an interface that does not have the method defined.

$user = auth()->user();

When you hover on $user of the above code what type does it show?

Illuminate\Support\Facades\Auth::user

<?php
public static function user() { }
@return \Illuminate\Contracts\Auth\Authenticatable|null

In 1.5 intelephense will prefer definitions not found in vendor. This enables you to override vendor definitions by providing a helper stub somewhere in the workspace. It also means that _ide_helper.php will be preferred.

For the specific case of auth()->user() I don't think _ide_helper.php has a stub for this so it will probably still return an interface rather than a concrete class. It is up to the user to add stub methods/functions where desired.

Using 1.5.2 this still doesn't seem to work.

Screenshot 2020-07-14 at 11 03 34

Auth::user() seems to return \App\Models\User, but when assigning it to a variable Intelephense still thinks the variable is the contract instead of the concrete User class as defined by _ide_helper.php:

Screenshot 2020-07-14 at 11 06 08

You're right @NEGits . Fixed in 1.5.3

Using 1.5.4 this still doesn't seem to work.

image

Using 1.5.4 and I also still have this issue.

image

Same here, still seeing the issue in 1.5.4 when using Auth::user().

It's detecting the definition in _ide_helper.php, but it's choosing the definition from vendor over it.

image

image

image

this still seems to be an issue (I have the same problem as described above, running 1.5.4)...is there another Issue tracking this or shit it be reopened?

+1

+1 ... Those underlines makes me feel uncomfortable

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zlianon picture zlianon  路  3Comments

swashata picture swashata  路  3Comments

muuvmuuv picture muuvmuuv  路  4Comments

ottopic picture ottopic  路  3Comments

ghnp5 picture ghnp5  路  3Comments