Skip to content

Commit

Permalink
feat: Add support for multiple resource for a nested model
Browse files Browse the repository at this point in the history
feat: Add support for multiple resource for a nested model
  • Loading branch information
lukas-frey authored Jun 20, 2024
2 parents 1cb5b8c + 1b7049f commit 0293639
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 20 deletions.
25 changes: 15 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Artist would be the root resource, the other would be child resources.
Currently we support **one-to-many** and **polymoprhic one-to-many** relationships only.

### Demo Project
To better understand how nested resources work and to troubleshoot any issues you might encounter, we've created a demo laravel project:
To better understand how nested resources work and to troubleshoot any issues you might encounter, we've created a demo laravel project:
https://github.com/GuavaCZ/filament-nested-resources-demo

### Quick start
Expand Down Expand Up @@ -72,19 +72,19 @@ class ArtistResource extends Resource
AlbumsRelationManager::class,
];
}

public static function getPages(): array
{
return [
'index' => Pages\ListArtists::route('/'),
'create' => Pages\CreateArtist::route('/create'),
'edit' => Pages\EditArtist::route('/{record}/edit'),
'view' => Pages\ViewArtist::route('/{record}'),

// In case of relation page.
// Make sure the name corresponds to the name of your actual relationship on the model.
'albums' => Pages\ManageArtistAlbums::route('/{record}/albums'),

// Needed to create child records
// The name should be '{relationshipName}.create':
'albums.create' => Pages\CreateArtistAlbum::route('/{record}/albums/create'),
Expand Down Expand Up @@ -114,7 +114,7 @@ class AlbumResource extends Resource
// Repeat the same for Song Resource
];
}

public static function getAncestor() : ?Ancestor
{
// Configure the ancestor (parent) relationship here
Expand Down Expand Up @@ -147,7 +147,7 @@ use Guava\FilamentNestedResources\Concerns\NestedPage;
class EditArtist extends EditRecord
{
use NestedPage;

//
}
```
Expand All @@ -174,10 +174,12 @@ class CreateArtistAlbum extends CreateRelatedRecord
{
use NestedPage;

// This page also needs to know the ancestor relationship used (just like relation managers):
// This page also needs to know the ancestor relationship used (just like relation managers):
protected static string $relationship = 'albums';

//
// We can usually guess the nested resource, but if your app has multiple resources for this
// model, you will need to explicitly define it
// public static string $nestedResource = AlbumResource::class;
}
```
Don\`t forget to register the page in the `getPages` method.
Expand All @@ -192,7 +194,10 @@ use Guava\FilamentNestedResources\Concerns\NestedRelationManager;
class AlbumsRelationManager extends RelationManager
{
use NestedRelationManager;
//

// We can usually guess the nested resource, but if your app has multiple resources for this
// model, you will need to explicitly define the it
// public static string $nestedResource = AlbumResource::class;
}
```

Expand All @@ -218,7 +223,7 @@ Every resource can control their own part of the breadcrumb, which by default co

The `index` breadcrumb typically redirects to the index page.

The `detail` breadcrumb typically redirects to the detail (edit or view) and by default, will display the route key (ID if not configured otherwise) of the record.
The `detail` breadcrumb typically redirects to the detail (edit or view) and by default, will display the route key (ID if not configured otherwise) of the record.

You can override the label via the `getBreadcrumbRecordLabel` method of a `NestedResource`:

Expand Down
4 changes: 2 additions & 2 deletions src/Actions/NestedCreateAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

namespace Guava\FilamentNestedResources\Actions;

use Filament\Facades\Filament;
use Filament\Tables\Actions\CreateAction;
use Guava\FilamentNestedResources\Ancestor;

trait NestedCreateAction
{
protected function configureCreateAction(CreateAction $action): void
{
$resource = Filament::getModelResource($this->getRelationship()->getRelated());
$resource = $this->getNestedResource();

/** @var Ancestor $ancestor */
$ancestor = $resource::getAncestor();

Expand Down
2 changes: 1 addition & 1 deletion src/Actions/NestedEditAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ protected function configureEditAction(Tables\Actions\EditAction $action): void
parent::configureEditAction($action);

$action->url(
fn (Model $record) => Filament::getModelResource($record)::getUrl(
fn (Model $record) => $this->getNestedResource($record)::getUrl(
'edit',
['record' => $record],
)
Expand Down
2 changes: 1 addition & 1 deletion src/Actions/NestedViewAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ protected function configureViewAction(Tables\Actions\ViewAction $action): void
parent::configureViewAction($action);

$action->url(
fn (Model $record) => Filament::getModelResource($record)::getUrl(
fn (Model $record) => $this->getNestedResource($record)::getUrl(
'view',
['record' => $record],
)
Expand Down
16 changes: 15 additions & 1 deletion src/Concerns/NestedRelationManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,27 @@

namespace Guava\FilamentNestedResources\Concerns;

use Guava\FilamentNestedResources\Actions\NestedCreateAction;
use Filament\Facades\Filament;
use Illuminate\Database\Eloquent\Model;
use Guava\FilamentNestedResources\Actions\NestedEditAction;
use Guava\FilamentNestedResources\Actions\NestedViewAction;
use Guava\FilamentNestedResources\Actions\NestedCreateAction;

/**
* @property string $nestedResource
*/
trait NestedRelationManager
{
use NestedCreateAction;
use NestedEditAction;
use NestedViewAction;

public function getNestedResource(?Model $record = null): string
{
if (property_exists(static::class, 'nestedResource')) {
return static::$nestedResource;
}

return Filament::getModelResource($record ?? $this->getRelationship()->getRelated());
}
}
22 changes: 17 additions & 5 deletions src/Pages/CreateRelatedRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@

use function Filament\Support\is_app_url;

/**
* @property string $nestedResource
*/
class CreateRelatedRecord extends Page
{
use HasUnsavedDataChangesAlert;
Expand Down Expand Up @@ -81,7 +84,7 @@ public function getRecord(): Model

protected function authorizeAccess(): void
{
abort_unless(Filament::getModelResource($this->getRelation()->getRelated())::canCreate(), 403);
abort_unless($this->getNestedResource()::canCreate(), 403);
}

protected function fillForm(): void
Expand Down Expand Up @@ -180,7 +183,7 @@ protected function handleRecordCreation(array $data): Model
}

if (
Filament::getModelResource($record)::isScopedToTenant() &&
$this->getNestedResource($record)::isScopedToTenant() &&
($tenant = Filament::getTenant())
) {
return $this->associateRecordWithTenant($record, $tenant);
Expand All @@ -206,7 +209,7 @@ protected function associateRecordWithParent(Model $record, Model $owner)

protected function associateRecordWithTenant(Model $record, Model $tenant): Model
{
$relationship = Filament::getModelResource($record)::getTenantRelationship($tenant);
$relationship = $this->getNestedResource($record)::getTenantRelationship($tenant);

if ($relationship instanceof HasManyThrough) {
$record->save();
Expand Down Expand Up @@ -281,7 +284,7 @@ public function form(Form $form): Form
*/
protected function getForms(): array
{
$resource = Filament::getModelResource($this->getRelation()->getRelated());
$resource = $this->getNestedResource();

return [
'form' => $this->form($resource::form(
Expand All @@ -300,6 +303,15 @@ public function getFormStatePath(): ?string
return 'data';
}

public function getNestedResource(?Model $record = null): string
{
if (property_exists(static::class, 'nestedResource')) {
return static::$nestedResource;
}

return Filament::getModelResource($record ?? $this->getRelation()->getRelated());
}

public static function canCreateAnother(): bool
{
return static::$canCreateAnother;
Expand All @@ -312,7 +324,7 @@ public static function disableCreateAnother(): void

protected function getRedirectUrl(): string
{
$resource = Filament::getModelResource($this->getRecord());
$resource = $this->getNestedResource($this->getRecord());

if ($resource::hasPage('view') && $resource::canView($this->getRecord())) {
return $resource::getUrl('view', ['record' => $this->getRecord(), ...$this->getRedirectUrlParameters()]);
Expand Down

0 comments on commit 0293639

Please sign in to comment.