我在 Nova 有一个(相对)基本的需求,但我似乎无法弄清楚,我慢慢开始觉得我处理事情的方式是错误的。 所以,我有一个
User
、Company
、Device
和 Transfer
模型以及各自的资源,关于资源设置的所有内容都是默认的。
架构如下:
users
:id, company_id
companies
:id, type_id, name
,其中 type_id
指向三种预填充类型之一(制造商、经销商、客户)devices
:id, imei
transfers
:id, from_company_id, to_company_id, accepted_at
Transfer
与 Device
处于多对多关系中。转让背后的想法是制造商转让给经销商,经销商转让给客户,所以这实际上只是一种单向的事情。
现在问题出现在以下逻辑关键点: 在我的
Transfer
资源页面中,我想根据当前经过身份验证的用户所属公司的类型显示不同的字段。基本上,如果公司是:
DEALER
列,其中填充了转移的 toCompany
关系;CONTRAGENT
列,其中填充了转账的 fromCompany
或 toCompany
关系(取决于当前 auth() 公司的数学)DEALER
列,其中填充了转账的 fromCompany
所有描述的逻辑都可以与以下代码一起正常工作(
App\Nova\Transfer.php
原样),直到我想最终在详细信息页面上显示传输的设备:
<?php
namespace App\Nova;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\BelongsToMany;
use Laravel\Nova\Http\Requests\NovaRequest;
class Transfer extends Resource
{
public static $model = \App\Models\Transfer::class;
public static $title = 'id';
public static $search = [
'id',
];
public static $with = [
'fromCompany',
'toCompany'
];
public function fields(Request $request)
{
$company = auth()->company();
if($company->hasType('manufacturer'))
{
$contragentTitle = 'Dealer';
$contragent = 'toCompany';
}
else if($company->hasType('dealer'))
{
//\Debugbar::info($this); //showing empty resource when populating the devices
$contragentTitle = 'Contragent';
$contragent = $this->fromCompany->is($company) ? 'toCompany' : 'fromCompany'; //exception here, since the resource is empty and fromCompany is null
}
else
{
$contragentTitle = 'Dealer';
$contragent = 'fromCompany';
}
$contragentCompanyField = BelongsTo::make("$contragentTitle company", $contragent, Company::class);
if($company->hasType('dealer'))
{
$contragentCompanyField->displayUsing(function ($contragentCompany) use ($contragent){
return $contragentCompany->title() . " (".($contragent == 'toCompany' ? 'Outgoing' : "Incoming").')';
});
}
return [
ID::make(__('ID'), 'id')->sortable(),
$contragentCompanyField,
BelongsToMany::make('Devices') //problematic field, when removed, everything is fine...
];
}
public static function indexQuery(NovaRequest $request, $query)
{
if(auth()->check())
{
return $query->where(function($subQuery){
return $subQuery->where('from_company_id', auth()->company()->id)->orWhere('to_company_id', auth()->company()->id);
});
}
}
public function cards(Request $request)
{
return [];
}
public function filters(Request $request)
{
return [];
}
public function lenses(Request $request)
{
return [];
}
//action is working fine (additional canRun added to avoid policy conflicts)
public function actions(Request $request)
{
return [
(new Actions\AcceptTransfer())->showOnTableRow()->canSee(function ($request) {
if ($request instanceof \Laravel\Nova\Http\Requests\ActionRequest) {
return true;
}
return $this->resource->exists
&& $this->resource->toCompany->is(auth()->company())
&& $this->resource->accepted_at === null;
})->canRun(function ($request) {
return true;
})
];
}
}
现在发生的奇怪的事情是,
fields()
方法在Nova后台的多个ajax请求中被多次调用,并且在填充设备关系表时,它在没有资源的情况下被调用,尽管实际上从来不需要调用(据我所知,Nova 背后的机制)或者至少在获取关系时,您仍然必须在某处获取模型信息(至少是 ID)...所以基本上,如果我是经销商公司,我看不到正在转移的设备(当前抛出 calling is() on null
异常)。
现在,这恰好是一个大问题,因为它阻碍了我转账所需的大部分内容,但总的来说,到目前为止我不喜欢我的方法,所以......实现这一目标的正确方法是什么
multi-layer
资源?理想情况下,我想定义三种不同的传输资源类,并以某种方式告诉 nova 根据用户公司的类型使用哪一种(因为分支很可能会变得更加复杂,因此按照当前的方法变得更加丑陋),但我可以'不知道该怎么做。
我也考虑过将整个逻辑转移到一个单独的 Nova 工具中,但我真的对它们还不太了解,也不知道这是否是正确的选择......唯一阻止我的是我仍然不会能够优雅地解决多层问题,并且必须自己编写许多其他有用的 Nova CRUD 逻辑和视图...
任何解释(关于
fields()
的多次调用以及为什么资源为空)或解决这种情况的一般结构建议将不胜感激!非常感谢!
编辑: 我能够通过利用
viaResourceId
来规避该错误,因此我最终使用了 $this
来代替:
$transfer = $this->id ? $this->resource : \App\Models\Transfer::find($request->viaResourceId);
但是混乱的代码和不必要的调用仍然是一个悬而未决的问题。再次提前致谢!
这是我如何处理此问题的示例:
public function fields(NovaRequest $request)
{
/** @var \App\Models\User $user */
$user = $this->id ? $this->resource : \App\Models\User::find($request->viaResourceId);
if ($user && $user->whatEver()) {
// display special fields in preview/detail view
return [...];
}
// display for index and if no model is found
return [...];
}
public function fields(NovaRequest $request)
{
/** @var \App\Models\User $user */
$user = $request->findModel();
if ($user && $user->whatEver()) {
// display special fields in preview/detail view
return [...];
}
// display for index and if no model is found
return [...];
}
从请求中检索具有所有属性的模型(Nova 4.34.3) 在 BelongsToMany 字段中,您可以使用
$request->findParentModel()
代替。
还检查 NovaRequest 对象上的这些方法:
findModelOrFail
findModelQuery
findRelatedModel