laravel-ide-helper icon indicating copy to clipboard operation
laravel-ide-helper copied to clipboard

Issues after Laravel 11.15

Open Sergiobop opened this issue 1 year ago • 3 comments

Versions:

  • ide-helper Version: 3.1
  • Laravel Version: 11.15
  • PHP Version: 8.3

Description:

Additionally to issues like https://github.com/barryvdh/laravel-ide-helper/issues/1571, Laravel 11.15 also ruined some other _ide_helper.php methods (find, findOrFail, etc)

I think is related to https://github.com/laravel/framework/pull/51851 and https://github.com/laravel/framework/pull/52037

Before 11.15:

/**
             * Find a model by its primary key or throw an exception.
             *
             * @param mixed $id
             * @param array|string $columns
             * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|static|static[] 
             * @throws \Illuminate\Database\Eloquent\ModelNotFoundException<\Illuminate\Database\Eloquent\Model>
             * @static 
             */            public static function findOrFail($id, $columns = [])
            {
                                /** @var \Illuminate\Database\Eloquent\Builder $instance */
                                return $instance->findOrFail($id, $columns);
            }

After 11.15:

/**
             * Find a model by its primary key or throw an exception.
             *
             * @param mixed $id
             * @param array|string $columns
             * @return \Illuminate\Database\Eloquent\($id is (\Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<mixed>) ? \Illuminate\Database\Eloquent\Collection<int, TModel> : TModel)
             * @throws \Illuminate\Database\Eloquent\ModelNotFoundException<TModel>
             * @static 
             */            public static function findOrFail($id, $columns = [])
            {
                                /** @var \Illuminate\Database\Eloquent\Builder $instance */
                                return $instance->findOrFail($id, $columns);
            }

Now for example this is wrong: $pack = Pack::query()->findOrFail($packId);

Previous to 11.15: $pack: Pack|Pack[]|Builder|Builder[]|Collection|Model|null After 11.15: $pack: |Collection|Model|null

I don't know if we have to do something to make it work again in our end.

Thanks

Sergiobop avatar Jul 17 '24 07:07 Sergiobop

Same here.

For example, User::first() returns a User object. However, after Laravel 11.15, I get an intelephense error if I try to typehint it.

Expected type 'App\Models\User'. Found 'Illuminate\Database\Eloquent\TValue|null'.

From _ide_helper.php:

/**
 * Execute the query and get the first result.
 *
 * @param array|string $columns
 * @return \Illuminate\Database\Eloquent\TValue|null 
 * @static 
 */
public static function first($columns = [])
{
    /** @var \Illuminate\Database\Eloquent\Builder $instance */
    return $instance->first($columns);
}

joelstein avatar Jul 18 '24 01:07 joelstein

Hello,

Same for me, all models are viewed as Illuminate\Database\Eloquent\Builder instead of an instance of App\Models\MODELNAME.

Thanks in advance, Max

max13fr avatar Jul 25 '24 09:07 max13fr

Same issue here. It seems that Laravel changed the DocBlocks for the Eloquent Builder class in Laravel 11.

It now has a template tag on the class itself @template TModel of \Illuminate\Database\Eloquent\Model, and it references this template on some of the methods @return TModel.

mengidd avatar Jul 30 '24 09:07 mengidd

What worked for me is that i disabled inteliphense and i only had this php intelisense enabled. Then i added this phpdoc to MyModel: @mixin \Illuminate\Database\Eloquent\Model<\App\Models\MyModel> then regenerate _ide_helper_models.php.

tlevi101 avatar Sep 16 '24 17:09 tlevi101

I have the same problem

wattnpapa avatar Oct 03 '24 09:10 wattnpapa

Same problem here

alexandre-tobia avatar Oct 04 '24 08:10 alexandre-tobia

I created a draft pull request #1591 to fix this issue. The tests don't pass, but the fix is ​​done.

A simple fix would require Laravel to only support versions 11.15 and later, which is a breaking change.

For compatibility, we could change the behavior depending on the running Laravel version, but because the Laravel Framework allows type changes even in minor versions, we might need to continue implementing similar version detection in the future. In my opinion, I don't recommend it.

After hearing your opinions on the versioning approach, I will complete the pull request.

KentarouTakeda avatar Oct 09 '24 14:10 KentarouTakeda

After further trial and error, it seemed like maintaining compatibility with versions below Laravel 11.15 would be a tough road to overcome, so I completed a pull request narrowing the supported version.

KentarouTakeda avatar Oct 10 '24 10:10 KentarouTakeda

great job, thank you :)

feng-yifan avatar Oct 15 '24 09:10 feng-yifan

While the changes are really good, one thing is still working incorrectly.

Model::create(), Model::find(), Model::make() are still returning the wrong type. This is due the \Eloquent mixin which is not working with generics. My suggestion would still be to replace the default @mixin \Eloquent with @mixin Builder<static> which would improve the autocompletion.

Eloquent mixin: image

Builder mixin: Screenshot 2024-10-18 at 14 26 13

@KentarouTakeda What do you think?

pataar avatar Oct 18 '24 12:10 pataar

Yes, I think it would be useful if it were fixed. On the other hand, I prefer to explicitly call the Eloquent Builder with query().

$user = User::query()->create();
// Identified as `\App\Models\User`

$user = User::create();
// Identified as `mixed`

In my opinion, Model and Builder are different classes even in terms of their inheritance, so I think it's better not to mix them.

By the way, the Eloquent mixin example you showed did not produce the same results in my environment. I don't know if it's Laravel or IDE Helper, but it may be written in a way that is interpreted differently depending on the editor. I use VSCode and PHP Intellephense.

vscode-intelephense-result

KentarouTakeda avatar Oct 18 '24 13:10 KentarouTakeda

Yes, I think it would be useful if it were fixed. On the other hand, I prefer to explicitly call the Eloquent Builder with query().

$user = User::query()->create();
// Identified as `\App\Models\User`

$user = User::create();
// Identified as `mixed`

In my opinion, Model and Builder are different classes even in terms of their inheritance, so I think it's better not to mix them.

By the way, the Eloquent mixin example you showed did not produce the same results in my environment. I don't know if it's Laravel or IDE Helper, but it may be written in a way that is interpreted differently depending on the editor. I use VSCode and PHP Intellephense.

vscode-intelephense-result

That might be caused due the @mixin \Eloquent entry. What happens if you remove that one? Does it still indicate 'mixed'?

I agree that a Model should be a different class than Builder. Although the docs state that ::create, ::where and ::find are valid methods.

pataar avatar Oct 21 '24 07:10 pataar

I removed @mixin \Eloquent as you suggested, but it didn't change anything.

builder-mixin

By the way, I noticed a strange output in the DocBlock generated to _ide_helper.php in recent versions.

helpers-eloquent-create

/**
 * @return \Illuminate\Database\Eloquent\TModel
 */
public static function create($attributes = [])

As you can see, a class that doesn't actually exist is being output as the return type. This is probably a bug.

A reasonable solution would be to make ide-helper:generate generic-compatible, and modify the Eloquent class itself to accept type parameters, just like I did with ide-helper:models. I think this will get you the results you want.

KentarouTakeda avatar Oct 21 '24 10:10 KentarouTakeda

I removed @mixin \Eloquent as you suggested, but it didn't change anything.

builder-mixin

By the way, I noticed a strange output in the DocBlock generated to _ide_helper.php in recent versions.

helpers-eloquent-create

/**
 * @return \Illuminate\Database\Eloquent\TModel
 */
public static function create($attributes = [])

As you can see, a class that doesn't actually exist is being output as the return type. This is probably a bug.

A reasonable solution would be to make ide-helper:generate generic-compatible, and modify the Eloquent class itself to accept type parameters, just like I did with ide-helper:models. I think this will get you the results you want.

Thanks, perhaps the interpretation of generics is different between PhpStorm and VSCode. I'll try to fix this in a PR soonish.

pataar avatar Oct 21 '24 12:10 pataar

@pataar Would it make sense to reopen this ticket unit "create returns Tmodel" problem is fixed? I've just run into the same issue.

gyulavoros avatar Nov 22 '24 13:11 gyulavoros

@pataar I second @gyulavoros, and would like to add that it also affects Model::find() and similar. Calling explicitly with query() every time is in conflict with the succinctness that Eloquent offers IMO.

hauthorn avatar Nov 26 '24 12:11 hauthorn

@pataar @hauthorn I'm not sure if this is the correct way of fix this, but adding this docbloc for TModel of Eloquent class in ide-helper fix the return type in vscode:

image

single: image

multiple: image

chack1172 avatar Dec 18 '24 14:12 chack1172

Is it really fixed in version 3.4.0? I see TModel was added in https://github.com/barryvdh/laravel-ide-helper/pull/1631 However, after this change TModel is not there anymore. Now it has double TValue

/**
     * 
     *
     * @template TCollection of static
     * @template TValue of static
     * @template TValue of static
     */
    class Eloquent extends \Illuminate\Database\Eloquent\Model {        /**

It was fine with:

"barryvdh/laravel-ide-helper": "dev-master#a25b9478514ef50e12a6f241d0bd93bc3c610910"

ekateiva avatar Dec 30 '24 11:12 ekateiva

Ah yes. Can you try with latest dev-master? https://github.com/barryvdh/laravel-ide-helper/pull/1645

barryvdh avatar Dec 30 '24 11:12 barryvdh

@barryvdh it still needs some tweaks, to make it work templates should be passed to the method's PHPDoc implementing this change https://github.com/barryvdh/ReflectionDocBlock/pull/22 or we will get this:

immagine

chack1172 avatar Dec 30 '24 12:12 chack1172

Do you have a minimal example of what you’re trying to do? Where does chaining give incorrect results?

barryvdh avatar Dec 30 '24 12:12 barryvdh

With me it links correctly, just using the @mixin \Eloquent tag. Screenshot 2024-12-30 at 13 42 20

Using the Builder class can work but that gives warnings about static calls when using Model::where() instead of Model::query()->where Screenshot 2024-12-30 at 13 45 30

barryvdh avatar Dec 30 '24 12:12 barryvdh

@barryvdh what I was saying is that if you take a look at the _ide_helper.php file there are still some types that adds the namespace to the types of templates. For example check firstOrNew or updateOrCreate methods.

chack1172 avatar Dec 30 '24 14:12 chack1172

Hmm yeah, but phpstorm still accepts this for me:

Screenshot 2024-12-30 at 15 42 30

But I'll see what I can do.

barryvdh avatar Dec 30 '24 14:12 barryvdh