barryvdh/laravel-ide-helper

Nova Resources

Muetze42 opened this issue · 8 comments

Is it a lot of effort to create a helper file for Nova Resources? _ide_helper_nova-resources.php

These should only contains the @property comments and not the @method or @property-read commands for each Nova resource based on static::$model in the resources.

mfn commented

Can you give an example of a Nova resource and the related eloquent model how you imagine this looks like?

Fresh created Laravel app with Nova. The default namespace for Nova resources is App\Nova, but I change it always
to App\Nova\Resources. (Similar to how it was with the models in the older Laravel versions)

The Nova resource for the User Model:

class User extends Resource
{
    /**
     * The model the resource corresponds to.
     */
    public static string $model = \App\Models\User::class;

The extended Resource class an abstract class and extends another abstract class \Laravel\Nova\Resource.

Method model() from the extended Resource:

    /**
     * Get the underlying model instance for the resource.
     *
     * @return TModel|null
     */
    public function model()
    {
        return $this->resource;
    }

The helper file would then look something like this:

<?php

// _ide_helper_nova.php

// @formatter:off
// phpcs:ignoreFile


namespace App\Nova\Resources {
    /**
     * App\Nova\Resources\User
     *
     * @property int $id
     * @property string $name
     * @property string $email
     * @property \Illuminate\Support\Carbon|null $email_verified_at
     * @property mixed $password
     * @property string|null $remember_token
     * @property \Illuminate\Support\Carbon|null $created_at
     * @property \Illuminate\Support\Carbon|null $updated_at
     */
    class User extends \App\Nova\Resources\Resource
    {
        /**
         * @return \App\Models\User|null
         */
        public function model()
        {
            return \App\Models\User::first();
        }
    }
}

If nothing speaks against it, can I write the Nova Command myself?

mfn commented
namespace App\Nova\Resources {
    /**
     * App\Nova\Resources\User
     *
     * @property int $id
     * @property string $name
     * @property string $email

Does this mean you are supposed to be able to access $novaUser->email and it routes it to $eloquentUser->email?

Yes, a Nova resource is "based" on a model and is initialized with it, so a resource also has the model attributes and then also it's possible to use them in a resource for example. (Nova it self use this for the field values etc).

Like here:
https://nova.laravel.com/docs/resources/fields.html#field-help-text
In the docs they use $this->name in a Nova resource and this return Model $userModel->name

Edit. Here a dd from the User resource:
image

mfn commented

I see.

Try adding this to your nova resource:

 * @mixin \App\Models\User

PhpStorm now correctly resolve property access to your underlying model.

Personally I prefer documenting the return value of the model() method and exclusively use it; for small project it doesn't matter, but once projects grow, the explicitness makes the difference.

 * @method \App\Models\User model()
…
  // later in code
  $this->model()->name

I think any reasonable editor should be able to work with either of these and personally I wouldn't want to introduce more complexity to ide-helper, believing the workarounds are adequate.

WDYT, does this work for you?

/**
 * @mixin \App\Models\User
 * @method \App\Models\User|null model()
 */

work

OK. It is certainly better not to include Nova in the ide-helper. Otherwise you would have to include a lot more.

I just create a simple little command that creates a Nova helper file.

For the next Nova user, my solution:

Copy the /vendor/laravel/nova/src/Console/stubs/resource.stub to /stubs/nova/resource.stub, if not already done.
And add the mixin and method as comment:

<?php

namespace {{ namespace }};

use Illuminate\Http\Request;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Http\Requests\NovaRequest;

/**
 * @mixin \{{ namespacedModel }}
 * @method \{{ namespacedModel }}|null model()
 */
class {{ class }} extends Resource
{
    //...