I am developing a Laravel admin using Laravel Nova. I have DB structure:
works
id
device_id
work_type
devices
id
serial_number
device_type_id
device_types
id
device_name
brand_id
brands
id
brand
This is the Work model class
class Work extends Model {
public function device()
{
return $this->belongsTo( device::class );
}
}
This is the Device model class
class Device extends Model {
public function deviceType()
{
return $this->belongsTo( DeviceType::class, 'device_type_id' );
}
}
This is the DeviceType model class
class DeviceType extends Model
{
public function brand()
{
return $this->belongsTo( Brand::class );
}
}
This is my actual Nova resource
class Work extends Resource
{
public function fields(Request $request)
{
return [
BelongsTo::make( 'Serial number', 'device', 'App\Nova\Device' )->searchable()
];
}
}
On the Laravel Nova "Works" index page, I would like something like that: | Work ID | Serial number | Device type | Brand | | -------- | -------------- | ----------- | ------- | | 1234 | 12345678901234 | S20 | Samsung | | 2345 | 99999999999999 | S21 | Samsung |
I have no idea how to display "Device type" and "Brand" columns.
These columns also should be sortable.
To display device_type
and brand
as columns on your Works
index page is fairly simple. Just add the device_type
and brand
as custom attributes to your Works
model. Afterwards, you can access them in your Nova resource.
Work model
class Work extends Model {
public function device()
{
return $this->belongsTo( device::class );
}
public function getBrandAttribute(): string
{
return $this->device->deviceType->brand->brand ?? '';
}
public function getDeviceTypeAttribute(): string
{
return $this->device->deviceType->device_name ?? '';
}
}
Work Nova Resource
class Work extends Resource
{
// Override indexQuery to your liking, joining tables
public static function indexQuery(NovaRequest $request, $query)
{
return $query->join('devices', 'devices.id', '=','works.device_id')
->join('device_types', 'device_types.id', '=', 'device_type_id')
->join('brands', 'brands.id', '=', 'brand_id')
->select([
'works.*',
'devices.device_type_id as device_type_id',
'devices_types.device_name as device_name',
'devices_types.brand_id as brand_id',
'brands.brand as brand'
]);
}
public function fields(Request $request)
{
return [
BelongsTo::make( 'Serial number', 'device', 'App\Nova\Device' )
->searchable(),
Text::make('Device name', 'device_name')
->onlyOnIndex()
->sortable(),
Text::make('Brand', 'brand')
->onlyOnIndex()
->sortable(),
];
}
}
Unfortunately, sorting is not out-of-the-box possible with Laravel Nova on these custom attributes, since the sorting is done on Database level.
Alternatively, you could try and updating the indexQuery
function as described here. There might be packages out there that add this functionality.
Edit
I have tinkered around with this in one of my own projects, it does seem to work by overriding the indexQuery
. However, I do not have the models set-up the way you do so I did not test my answer. I also do not know how well this performs on large scale. See example above, and let me know if it works. Btw, you can remove the custom attributes
from your model if you decide to override the indexQuery
method.