适用于Laravel Nova中同一模型上两个资源字段的relatableQuery()

时间:2019-07-03 23:52:04

标签: php laravel laravel-nova

我在“工作日”和不同类型的项目之间有某种关系。因此,“天”记录两次引用了“项目”表,因为我有两种不同类型的项目,分别称为“系列”和“事件”。

在“日子”资源中,我创建了两个字段,例如:

BelongsTo::make('Series','series',Project::class)->sortable()->nullable(),
BelongsTo::make('Event','event',Project::class)->sortable()->nullable(),

我想做的是按项目的类型过滤项目,所以我创建了这个项目:

public static function relatableProjects(NovaRequest $request, $query){
    return $query->where('type', 'Series');
}

我尝试制作relatableSeries和relatableEvents,但是它们不起作用。如何使它正确连接到字段,而不必为“系列”和“事件”创建两个单独的表。

上面的relatableQuery结束了对两个资源字段的过滤。

2 个答案:

答案 0 :(得分:0)

因为relatableQuery()引用了一个relatableModel()(所以relatableProjects()引用了Project模型),所以我能够创建另一个模型只是出于帮助的目的。

我创建了一个引用相同projects表的事件模型,然后能够创建一个relatableEvents()方法以使用where()过滤器查询。

注意:我确实还必须创建一个引用该事件模型的事件资源,因为这是Nova的工作方式,但是能够使它隐藏起来,而您无法找到有关{{ 3}}

请参见下面的修订版“ BelongsTo”字段和新模型:

日间资源

    /**
     * Build a "relatable" query for the given resource.
     *
     * This query determines which instances of the model may be attached to other resources.
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public static function relatableProjects(NovaRequest $request, $query){
        return $query->where('type', 'Series');
    }

    /**
     * Build a "relatable" query for the given resource.
     *
     * This query determines which instances of the model may be attached to other resources.
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public static function relatableEvents(NovaRequest $request, $query){
        return $query->where('type', 'Event');
    }

    /**
     * Get the fields displayed by the resource.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function fields(Request $request)
    {
        return [
            ID::make()->hideFromIndex()->hideFromDetail()->hideWhenUpdating(),
            BelongsTo::make('User','user',User::class)->sortable(),
            BelongsTo::make('Budget','budget',Budget::class)->sortable()->nullable(),
            BelongsTo::make('Series','series',Project::class)->sortable()->nullable(),
            BelongsTo::make('Event','event',Event::class)->sortable()->nullable(),
            DateTime::make('Last Updated','updated_at')->hideFromIndex()->readOnly(),
            new Panel('Schedule',$this->schedule()),
            new Panel('Time Entry',$this->timeEntries()),

        ];
    }

事件模型

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Event extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'projects';

    protected $casts = [
        'starts_on' => 'date',
        'ends_on' => 'date',
    ];

    public function event(){
        return $this->belongsTo('App\Event');
    }

    public function project(){
        return $this->belongsTo('App\Project');
    }
}

答案 1 :(得分:0)

我知道这是一个老问题,但我在 laravel nova 所属领域面临同样的问题,在某些资源中,我有一个与用户相关的属于,但这些应该在另一个资源中扮演“主管”角色,我有一个所属领域与用户相关,但这些应该是“守卫”的角色,因为 laravel nova 所属字段只需要所有用户都选择所有用户出现,似乎 nova 所属字段没有办法,或者至少我没有找到它的范围查询,所以我所做的是创建一个名为 BelongstoScoped 的 php 类,这个类扩展了 laravle nova 字段 BelongsTo 所以我覆盖了负责创建查询的方法

<?php

namespace App\Nova\Customized;

use Laravel\Nova\Query\Builder;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Http\Requests\NovaRequest;

class BelongsToScoped extends BelongsTo
{

    private  $modelScopes = [];

    //original function in laravel belongsto field
    public function buildAssociatableQuery(NovaRequest $request, $withTrashed = false)
    {
        $model = forward_static_call(
            [$resourceClass = $this->resourceClass, 'newModel']
        );

        $query = new Builder($resourceClass);
        
        //here i chaned this:
        /*
        $query->search(
                                $request,  $model->newQuery(), $request->search,
                                [], [], ''
                          );
        */
        //To this:
        /*
        $query->search(
                                $request,  $this->addScopesToQuery($model->newQuery()), $request->search,
                                [], [], ''
                          );
        */
        //The method search receives a query builder as second parameter, i just passed the result of custom function 
        //addScopesToQuery as second parameter, thi method returns the same query but with the model scopes passed

        $request->first === 'true'
                        ? $query->whereKey($model->newQueryWithoutScopes(), $request->current)
                        : $query->search(
                                $request,  $this->addScopesToQuery($model->newQuery()), $request->search,
                                [], [], ''
                          );

        return $query->tap(function ($query) use ($request, $model) {
            forward_static_call($this->associatableQueryCallable($request, $model), $request, $query, $this);
        });
    }

    //this method reads the property $modelScopes and adds them to the query
    private function addScopesToQuery($query){
        foreach($this->modelScopes as $scope){
            $query->$scope();
        }
        return $query;
    }

    // this method should be chained tho the field 
    //example: BelongsToScoped::make('Supervisores', 'supervisor', 'App\Nova\Users')->scopes(['supervisor', 'active'])
    public function scopes(Array $modelScopes){

        $this->modelScopes = $modelScopes;
        return $this;

    }

}

?>

在我的用户模型中,我有这样的主管和警卫角色的范围:

public function scopeActive($query)
    {
        return $query->where('state', 1);
    }

    public function scopeSupervisor($query)
    {
        return $query->role('supervisor');
    }

    public function scopeSuperadmin($query)
    {
        return $query->role('superadmin');
    }

    public function scopeGuarda($query)
    {
        return $query->role('guarda');
    }

所以在 laravel nova 资源中我只是包含了这个类的使用 *请记住命名空间取决于您如何命名文件,在我的情况下,我创建了自定义文件夹并将文件包含在其中:

use App\Nova\Customized\BelongsToScoped;

在 nova 资源的字段中,我是这样使用的:

BelongsToScoped::make('Supervisor', 'supervisorUser', 'App\Nova\Users\User')
                            ->scopes(['supervisor', 'active'])
                            ->searchable()

这样我就可以调用nova资源中的belongsto字段,它根据模型范围过滤用户。

我希望这对某人有所帮助,如果我的英语不是那么好,抱歉。