Josh
Josh

Reputation: 8159

Eloquent ORM Code Hinting in PhpStorm

So I'm just starting off with Laravel (using v5) and Eloquent. I'm working on getting some basic APIs up and running and noticing that a lot of working methods don't show up in PhpStorm's code hinting

So I have this model:

namespace Project\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;

class User extends Model 
    implements AuthenticatableContract, CanResetPasswordContract {
}

And in one of my controllers I try to do

User::query()->orderBy('id', 'desc');

User::query() creates a Eloquent Builder object and orderBy() behave properly and without error. However, PhpStorm does not show orderBy() (or take(), skip(), and I'm sure others) when I type User::query()-> and gives warnings when I actually do use it.

I am using Laravel IDE Helper which has helped immensely with bringing code hints to the Facades, but not to the models/builders it would seem.

Does anyone have a solution to this?

Upvotes: 37

Views: 39915

Answers (9)

iifast2
iifast2

Reputation: 334

This really helped me (laravel-ide-helper):

composer require --dev barryvdh/laravel-ide-helper -W

then :

php artisan ide-helper:eloquent

This really helps :

    Using version ^2.13 for barryvdh/laravel-ide-helper
PS C:\Users\anonym\Documents\Github\laravel\elearny_app_web> php artisan ide-helper:eloquent                      
Unexpected no document on Illuminate\Database\Eloquent\Model
Wrote expected docblock to C:\Users\anonym\Documents\Github\laravel\elearny_app_web\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php
PS C:\Users\anonym\Documents\Github\laravel\elearny_app_web>

Upvotes: 0

Homer
Homer

Reputation: 467

Verified on Laravel 8, just added @mixin Builder to Illuminate\Database\Eloquent\Model.php annotation solved it.

// Illuminate\Database\Eloquent\Model.php
/**
  * @mixin Builder
*/
abstract class Model

Upvotes: 0

imprfekt
imprfekt

Reputation: 377

Just import Eloquent Builder in your Model class and add mixin:

use Illuminate\Database\Eloquent\Builder;
/** @mixin Builder */

To cover all the models at once — add the mixin to the src/Illuminate/Database/Eloquent/Model.php)

Upvotes: 8

Add in model PHPDoc@mixin

/**
 * Class News
 * @property int $id
 * @property string $created_at
 * @property string $updated_at
 * @mixin \Eloquent
 * @package App
 */
class News extends Model
{

}

In PHPStorm works

Upvotes: 22

GTCrais
GTCrais

Reputation: 2087

If you're using BarryVHD's Laravel IDE Helper package, run:

php artisan ide-helper:eloquent

This will write /** @mixin \Eloquent */ into the vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php file.

Upvotes: 7

Isometriq
Isometriq

Reputation: 381

I wanted to have some kind of explicit "casting" when interacting with the query builder. Example...

$user = User::query()->findOrFail($id);
$user->myUserSpecialMethod(); // <-- IDE syntax error

Since all my models are extending my custom base Model which in turn extends Eloquent, I've ended up creating this method in my custom base model:

/**
 * Explicit type-hinting
 *
 * @return static
 */
static public function hint(BaseModel $model)
{
    return $model;
}

This way, it solves the IDE invalid error and helps me:

$user = User::hint(User::query()->findOrFail($id));
$user->myUserSpecialMethod(); // <-- all OK !

Please note that this is not OOP type casting. It is only a hint to help the IDE. In my example, the returned Model was already a User. If I woud use this method on a derived class like SuperUser, only the IDE will be fooled...

An nice alternative also is to put meta information directly over the assignment statement:

/** @var User $user */
$user = User::query()->findOrFail($id);
$user->myUserSpecialMethod(); // <-- all OK !

Or next to it...

$user = User::query()->findOrFail($id); /** @var User $user */
$user->myUserSpecialMethod(); // <-- all OK !

Upvotes: 2

Evren Yurtesen
Evren Yurtesen

Reputation: 2349

A little late but I recently had the same problem so I thought I would put a note down:

This is because Database\Eloquent\Model.php has a query() function which returns \Illuminate\Database\Eloquent\Builder and the Eloquent\Builder has a line:

use Illuminate\Database\Query\Builder as QueryBuilder;

Then it uses 'magic' __call methods to call to functions in Query\Builder. (look for __call method in Eloquent\Builder)

See: http://php.net/manual/en/language.oop5.overloading.php#object.call

__call() is triggered when invoking inaccessible methods in an object context.

So, indeed the method you are calling is inaccessible :) There is not much that the IDE can do.

There are workarounds like using @method tags but it is unmaintainable. An alternative is to use @mixin (but this is not standards based). See: https://github.com/laravel/framework/issues/7558

I think this all be resolved when they get rid of all the magic calls in the Laravel code and use PHP 'traits' instead. See last message here. :)

Upvotes: 5

Erik Johansson
Erik Johansson

Reputation: 1656

For future Googlers, and perhaps OP as well if you are still sticking to Laravel.

The laravel-ide-helper package solves this issue for you quite elegantly, with what I believe is a relatively new feature; generated model PHPDocs.

You can generate a separate file for all PHPDocs with this command:

php artisan ide-helper:models

The generated metadata will look something like this for each class:

namespace App {
/**
 * App\Post
 *
 * @property integer $id
 * @property integer $author_id
 * @property string $title
 * @property string $text
 * @property \Carbon\Carbon $created_at
 * @property \Carbon\Carbon $updated_at
 * @property-read \User $author
 * @property-read \Illuminate\Database\Eloquent\Collection|\Comment[] $comments
 */
class Post {}
}

This caused issues for me in PHPStorm however, where the software was complaining about multiple class definitions. Luckily an option is readily available for writing directly to the model files:

php artisan ide-helper:models -W

There are a few more options and settings available if you need to tweak the behavior, but this is the gist of it.

Upvotes: 95

mirza
mirza

Reputation: 5793

You can try Laravel plug-in for PhpStorm and you need to specifically activate it in your project settings.

Upvotes: 5

Related Questions