Tricks

Link to related model from table

Jun 27, 2022
Dennis Koch
Table builder

I regularly want to link the related models from the table and created a little macro for it:

Column::macro('linkRecord', function ($view = 'edit') {
return $this->url(function ($record) use ($view) {
if ($record === null) {
return null;
}
 
$selectedResource = null;
$relationship = Str::before($this->getName(), '.');
$relatedRecord = $record->{$relationship};
 
if ($relatedRecord === null) {
return null;
}
 
foreach (Filament::getResources() as $resource) {
if ($relatedRecord instanceof ($resource::getModel())) {
$selectedResource = $resource;
 
break;
}
}
 
return $selectedResource::getUrl($view, $relatedRecord->getKey());
});
});
avatar

For version 3.x you must change almost the last line to:

return $selectedResource::getUrl($view, ['record' => $relatedRecord->getKey()]);

avatar

I find this tidier to implement as a custom column component - then it can be used selectively as required without polluting service providers:

<?php
 
namespace App\Table\Components;
 
use Illuminate\Support\Str;
use Filament\Facades\Filament;
use Filament\Tables\Columns\TextColumn;
 
class ModelLinkColumn extends TextColumn
{
protected function setUp(): void
{
parent::setUp();
 
$this->url(function ($record) {
if ($record === null) {
return null;
}
 
$selectedResource = null;
$relationship = Str::before($this->getName(), '.');
$relatedRecord = $record->{$relationship};
 
if ($relatedRecord === null) {
return null;
}
 
$selectedResource = collect(Filament::getResources())
->first(fn ($resource) => $relatedRecord instanceof ($resource::getModel()));
 
return $selectedResource::getUrl('view', [
'record' => $relatedRecord->getKey()
]);
});
}
}

An example in use:

ModelLinkColumn::make('supplier.name')
->label('Supplier')
👍 2
avatar

Excellent! Clean code. Works flawlessly with v3

avatar

Improved that class a little bit, so you can customize some small things: You can change the viewTybe and use different name to link than the used one :)

<?php
 
namespace App\Tables\Columns;
 
use Filament\Facades\Filament;
use Filament\Tables\Columns\TextColumn;
use Illuminate\Support\Str;
 
class ModelLinkColumn extends TextColumn
{
protected string $viewType = 'view';
protected ?string $overwriteName = null;
 
public function overwriteName($name): static
{
$this->overwriteName = $name;
$this->setUpLink();
return $this;
}
 
public function setViewType(string $viewType): static
{
$this->viewType = $viewType;
$this->setUpLink();
return $this;
}
 
protected function setUp(): void
{
parent::setUp();
$this->setUpLink();
}
 
protected function setUpLink(): void
{
$this->url(function ($record) {
if ($record === null) {
return null;
}
 
$name = $this->overwriteName ?? $this->getName();
 
$relationship = Str::before($name, '.');
$relatedRecord = $record->{$relationship};
 
if ($relatedRecord === null) {
return null;
}
 
$selectedResource = collect(Filament::getResources())->first(fn ($resource) => $relatedRecord instanceof ($resource::getModel()));
 
if ($selectedResource === null) {
return null;
}
 
return $selectedResource::getUrl($this->viewType, [
'record' => $relatedRecord->getKey(),
]);
});
}
}