danilogiacomi/filament-nested-resources

dev-main 2024-06-26 11:28 UTC

This package is auto-updated.

Last update: 2024-09-24 15:30:27 UTC


README

Filament Cluster Banner

Filament Nested Resources

Latest Version on Packagist Total Downloads

Filament Nested Resources 允许您创建任何深度的嵌套资源。这对于过于复杂而无法作为独立资源使用的关系管理器来说很有用。

首次公开发布在此。

展示

Screenshot 1 Screenshot 2

支持我们

您的支持对我们插件持续进步至关重要。我们感谢迄今为止所有为我们的旅程做出贡献的用户。

虽然我们的插件对所有用户都可用,但如果您正在将其用于商业目的,并认为它为您的事业增添了显著价值,我们诚恳地请求您考虑通过 GitHub Sponsors 支持我们。这种赞助将帮助我们持续开发和维护,以保持插件强大且最新。您捐赠的任何金额都将极大地帮助我们实现目标。加入我们,使这个插件变得更好,并推动进一步的创新。

安装

您可以通过 composer 安装此包

composer require guava/filament-nested-resources

用法

在整个文档中,我引用了 root 嵌套资源和 child 嵌套资源。唯一的区别是 Root 是关系树中的第一个资源。

在示例中:ArtistResource > AlbumResource > SongResource

Artist 将是根资源,其他则是子资源。

支持的关系

目前我们仅支持 一对一多态一对一 关系。

演示项目

为了更好地了解嵌套资源的工作原理以及解决您可能遇到的问题,我们创建了一个演示 Laravel 项目:[https://github.com/GuavaCZ/filament-nested-resources-demo](https://github.com/GuavaCZ/filament-nested-resources-demo)

快速入门

为了设置嵌套资源,您需要执行以下步骤

  1. 在您想要嵌套的资源(根和所有子资源)上,添加 NestedResource 特性。您需要实现 getAncestor 方法。对于根资源,返回 null,对于所有子资源,根据以下文档实现它。
  2. 在第一步中资源的每个页面上,添加 NestedPage 特性。
  3. 创建一个 RelationManager([Filament 文档](https://filamentphp.com/docs/3.x/panels/resources/relation-managers#creating-a-relation-manager))或一个 RelationPage([Filament 文档](https://filamentphp.com/docs/3.x/panels/resources/relation-managers#relation-pages))来绑定资源。将 NestedRelationManager 特性添加到其中任何一个。

让我们想象一下展示截图中的场景,其中我们具有这个模式

  1. Artist 模型。
  2. Album 模型(属于 Artist)。
  3. Song 模型(属于 Album)。

首先我们创建 ArtistResource

use Filament\Resources\Resource;
use Guava\FilamentNestedResources\Concerns\NestedResource;

class ArtistResource extends Resource
{
    use NestedResource;

    // If using Relation Manager:
    public static function getRelations(): array
    {
        return [
            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'),
        ];
    }

    public static function getAncestor(): ?Ancestor
    {
        return null;
    }
}

接下来,我们创建 AlbumResource

use Filament\Resources\Resource;
use Guava\FilamentNestedResources\Concerns\NestedResource;

class AlbumResource extends Resource
{
    use NestedResource;

    public static function getRelations(): array
    {
        return [
            // Repeat the same for Song Resource
        ];
    }

    public static function getAncestor() : ?Ancestor
    {
        // Configure the ancestor (parent) relationship here
        return Ancestor::make(
            'albums', // Relationship name
            'artist', // Inverse relationship name
        );
    }
}

ArtistResourceAlbumResource 的每个页面上,我们添加 NestedPage 特性

use Filament\Resources\Pages\CreateRecord;
use Guava\FilamentNestedResources\Concerns\NestedPage;

class CreateArtist extends CreateRecord
{
    use NestedPage;

    //
}
use Filament\Resources\Pages\EditRecord;
use Guava\FilamentNestedResources\Concerns\NestedPage;

class EditArtist extends EditRecord
{
    use NestedPage;

    //
}
use Filament\Resources\Pages\ListRecords;
use Guava\FilamentNestedResources\Concerns\NestedPage;

class ListArtists extends ListRecords
{
    use NestedPage;

    //
}

现在让我们创建一个新的页面,它将用于创建子记录。在 ArtistResource/Pages 中创建 CreateArtistAlbum 页面

use Guava\FilamentNestedResources\Pages\CreateRelatedRecord;
use Guava\FilamentNestedResources\Concerns\NestedPage;

class CreateArtistAlbum extends CreateRelatedRecord
{
    use NestedPage;

    // 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;
}

别忘了在 getPages 方法中注册页面。

最后,我们创建 AlbumsRelationManager 或如果您更喜欢使用关系页面,则创建 ManageArtistAlbums 页面。我们只需要在这里添加 NestedRelationManager 特性。

针对RelationManager

use Filament\Resources\RelationManagers\RelationManager;
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;
}

针对RelationPage

use Filament\Resources\Pages\ManageRelatedRecords;
use Guava\FilamentNestedResources\Concerns\NestedPage;
use Guava\FilamentNestedResources\Concerns\NestedRelationManager;

class ManageArtistAlbums extends ManageRelatedRecords
{
    use NestedPage; // Since this is a standalone page, we also need this trait
    use NestedRelationManager;

    //
}

可选,我们建议从您的子NestedResources(在这种情况下为AlbumResource)中删除indexcreate页面。

定制面包屑

每个资源都可以控制自己的面包屑部分,默认由一个index面包屑和一个detail面包屑组成。

index面包屑通常重定向到索引页面。

detail面包屑通常重定向到详细(编辑或查看)页面,默认情况下将显示记录的路由键(如果没有配置则为ID)。

您可以通过NestedResourcegetBreadcrumbRecordLabel方法覆盖标签

public static function getBreadcrumbRecordLabel(Model $record)
{
    return $record->first_name . ' ' . $record->last_name;
}

或者,您可以通过在资源上重写getBreadcrumbs方法来完全覆盖资源的面包屑部分

public static function getBreadcrumbs(Model $record, string $operation): array
{
    return [
        'my-custom-url' => 'My custom label',
];
}

贡献

请参阅CONTRIBUTING以获取详细信息。

安全漏洞

请审查我们关于如何报告安全漏洞的安全策略

鸣谢

许可证

MIT许可证(MIT)。请参阅许可证文件以获取更多信息。