moonshine-software / moonshine

Laravel Admin panel and more. Simple for beginners and powerful for experts. Using Blade, Alpine.js and Tailwind CSS.

Home Page:https://moonshine-laravel.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Fields inherited from ModelRelationField do not work with either the specified resource query or the scope of the related model

savosik opened this issue · comments

Description

PHP version: PHP 8.2.18
DB version: MySQL: 8.2
Laravel version: 10.48.16
Moonshine version: 2.18.1

Steps to reproduce:

  1. Create Model 'Company':
class Company extends Model
{
    use SoftDeletes;  // Model uses SoftDeletes!


    protected $fillable = ['name', 'inn', 'moonshine_user_id'];

    protected $searchableFields = ['*'];

    public function orders(): `HasMany`
    {
        return $this->hasMany(Order::class);
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'moonshine_user_id');  // User was inherited from MoonshineUser model
    }

    protected static function booted()
    {
        static::addGlobalScope('filterByUser', function (Builder $builder) {  // scope was temporary added from trait (wherehas etc..)
            if (!App::runningInConsole() && Auth::check()) {
                $builder->whereHas('user', function (Builder $query) {
                    $query->where('moonshine_users.id', Auth::id());
                });
            }
        });
    }
}
  1. Create Moonshine Resource 'CompanyResource':
class CompanyResource extends ModelResource
{
    protected string $model = Company::class;

    protected string $title = 'Компании';

    protected string $column = 'name';


 /*    todo:: uncomment it for test resource without model's global scope  
    public  function query() : \Illuminate\Contracts\Database\Eloquent\Builder
    {
        return parent::query()->where('moonshine_user_id', auth()->id());
    }
*/

   
    protected function beforeCreating(Model $item): Model
    {
        $item->moonshine_user_id ??= auth()->id();
        return $item;
    }

...

}
  1. Create Order Model:
class Order extends Model
{
    use \Znck\Eloquent\Traits\BelongsToThrough;
    use SoftDeletes;

    use FilterByUser; //  global scope by user for order

    protected $fillable = [ '*',];

    public function company(): BelongsTo
    {
        return $this->belongsTo(Company::class);
    }

    public function user(): BelongsToThrough
    {
        return $this->belongsToThrough(User::class, Company::class);
    }
}
  1. Create Moonshine Resource : 'OrderResource':
class OrderResource extends ModelResource
{
    protected string $model = Order::class;

    protected string $title = 'Заказы поставщику';


    public function fields(): array
    {
        return [
            Block::make([
                ID::make()->sortable(),
                BelongsTo::make('Компания', 'company', resource: new CompanyResource())
            ]),
        ];
    }

}

belongs-to-field

The filtering methods on the field itself are very cumbersome and often force code duplication or the creation of a custom class for the field:

  BelongsTo::make('Компания', 'company', resource: new CompanyResource())
                            ->valuesQuery(function (Builder $builder) {
                                return $builder->whereHas('user', function (Builder $builder) {
                                    $builder->where('moonshine_users.id', Auth::id())->whereNull('deleted_at');
                                });
                            })->asyncSearch(asyncSearchQuery: function (Builder $builder) {
                                return $builder->whereHas('user', function (Builder $builder) {
                                    $builder->where('moonshine_users.id', Auth::id())->whereNull('deleted_at');;
                                });
                            })