diff --git a/docs/03-resources/01-overview.md b/docs/03-resources/01-overview.md index 87a10936fa..e47448cee1 100644 --- a/docs/03-resources/01-overview.md +++ b/docs/03-resources/01-overview.md @@ -42,7 +42,7 @@ php artisan make:filament-resource Customer --simple Your resource will have a "Manage" page, which is a List page with modals added. -Additionally, your simple resource will have no `getRelations()` method, as [relation managers](relation-managers) are only displayed on the Edit and View pages, which are not present in simple resources. Everything else is the same. +Additionally, your simple resource will have no `getRelations()` method, as [relation managers](managing-relationships) are only displayed on the Edit and View pages, which are not present in simple resources. Everything else is the same. ### Automatically generating forms and tables @@ -474,8 +474,8 @@ Sub-navigation allows the user to navigate between different pages within a reso - View customer, a [`ViewRecord` page](viewing-records) that provides a read-only view of the customer's details. - Edit customer, an [`EditRecord` page](editing-records) that allows the user to edit the customer's details. - Edit customer contact, an [`EditRecord` page](editing-records) that allows the user to edit the customer's contact details. You can [learn how to create more than one Edit page](editing-records#creating-another-edit-page). -- Manage addresses, a [`ManageRelatedRecords` page](relation-managers#relation-pages) that allows the user to manage the customer's addresses. -- Manage payments, a [`ManageRelatedRecords` page](relation-managers#relation-pages) that allows the user to manage the customer's payments. +- Manage addresses, a [`ManageRelatedRecords` page](managing-relationships#relation-pages) that allows the user to manage the customer's addresses. +- Manage payments, a [`ManageRelatedRecords` page](managing-relationships#relation-pages) that allows the user to manage the customer's payments. To add a sub-navigation to each "singular record" page in the resource, you can add the `getRecordSubNavigation()` method to the resource class: diff --git a/docs/03-resources/06-deleting-records.md b/docs/03-resources/06-deleting-records.md index 0faae5c826..206d3f7b63 100644 --- a/docs/03-resources/06-deleting-records.md +++ b/docs/03-resources/06-deleting-records.md @@ -106,6 +106,8 @@ Users may delete records if the `delete()` method of the model policy returns `t They also have the ability to bulk-delete records if the `deleteAny()` method of the policy returns `true`. Filament uses the `deleteAny()` method because iterating through multiple records and checking the `delete()` policy is not very performant. +You can use the `authorizeIndividualRecords()` method on the `BulkDeleteAction` to check the `delete()` policy for each record individually. + ### Authorizing soft deletes The `forceDelete()` policy method is used to prevent a single soft-deleted record from being force-deleted. `forceDeleteAny()` is used to prevent records from being bulk force-deleted. Filament uses the `forceDeleteAny()` method because iterating through multiple records and checking the `forceDelete()` policy is not very performant. diff --git a/docs/03-resources/07-relation-managers.md b/docs/03-resources/07-managing-relationships.md similarity index 97% rename from docs/03-resources/07-relation-managers.md rename to docs/03-resources/07-managing-relationships.md index e71dbdc883..d92171b595 100644 --- a/docs/03-resources/07-relation-managers.md +++ b/docs/03-resources/07-managing-relationships.md @@ -32,7 +32,7 @@ From a UX perspective, this solution is only suitable if your related model only > These are compatible with `BelongsTo`, `HasOne` and `MorphOne` relationships. -All layout form components ([Grid](../../schemas/layouts#grid-component), [Section](../../schemas/sections), [Fieldset](../../schemas/layouts#fieldset-component), etc.) have a [`relationship()` method](../../forms/advanced#saving-data-to-relationships). When you use this, all fields within that layout are saved to the related model instead of the owner's model: +All layout form components ([Grid](../../schemas/layouts#grid-component), [Section](../../schemas/sections), [Fieldset](../../schemas/layouts#fieldset-component), etc.) have a [`relationship()` method](../../forms/overview#saving-data-to-relationships). When you use this, all fields within that layout are saved to the related model instead of the owner's model: ```php use Filament\Forms\Components\FileUpload; @@ -51,7 +51,7 @@ Fieldset::make('Metadata') In this example, the `title`, `description` and `image` are automatically loaded from the `metadata` relationship, and saved again when the form is submitted. If the `metadata` record does not exist, it is automatically created. -This feature is explained more in depth in the [Forms documentation](../../forms/advanced#saving-data-to-relationships). Please visit that page for more information about how to use it. +This feature is explained more in depth in the [Forms documentation](../../forms/overview#saving-data-to-relationships). Please visit that page for more information about how to use it. ## Creating a relation manager @@ -584,7 +584,7 @@ Relation managers are Livewire components. When they are first loaded, the owner $this->getOwnerRecord() ``` -However, if you're inside a `static` method like `form()` or `table()`, `$this` isn't accessible. So, you may [use a callback](../../forms/advanced#form-component-utility-injection) to access the `$livewire` instance: +However, if you're inside a `static` method like `form()` or `table()`, `$this` isn't accessible. So, you may [use a callback](../../forms/overview#field-utility-injection) to access the `$livewire` instance: ```php use Filament\Forms; @@ -721,7 +721,7 @@ RelationGroup::make('Contacts', [ You may decide that you want a resource's form and table to be identical to a relation manager's, and subsequently want to reuse the code you previously wrote. This is easy, by calling the `form()` and `table()` methods of the resource from the relation manager: ```php -use App\Filament\Resources\Blog\PostResource; +use App\Filament\Resources\Blog\Posts\PostResource; use Filament\Schemas\Schema; use Filament\Tables\Table; @@ -741,7 +741,7 @@ public function table(Table $table): Table If you're sharing a form component from the resource with the relation manager, you may want to hide it on the relation manager. This is especially useful if you want to hide a `Select` field for the owner record in the relation manager, since Filament will handle this for you anyway. To do this, you may use the `hiddenOn()` method, passing the name of the relation manager: ```php -use App\Filament\Resources\Blog\PostResource\RelationManagers\CommentsRelationManager; +use App\Filament\Resources\Blog\Posts\PostResource\RelationManagers\CommentsRelationManager; use Filament\Forms\Components\Select; Select::make('post_id') @@ -754,7 +754,7 @@ Select::make('post_id') If you're sharing a table column from the resource with the relation manager, you may want to hide it on the relation manager. This is especially useful if you want to hide a column for the owner record in the relation manager, since this is not appropriate when the owner record is already listed above the relation manager. To do this, you may use the `hiddenOn()` method, passing the name of the relation manager: ```php -use App\Filament\Resources\Blog\PostResource\RelationManagers\CommentsRelationManager; +use App\Filament\Resources\Blog\Posts\PostResource\RelationManagers\CommentsRelationManager; use Filament\Tables\Columns\TextColumn; TextColumn::make('post.title') @@ -766,7 +766,7 @@ TextColumn::make('post.title') If you're sharing a table filter from the resource with the relation manager, you may want to hide it on the relation manager. This is especially useful if you want to hide a filter for the owner record in the relation manager, since this is not appropriate when the table is already filtered by the owner record. To do this, you may use the `hiddenOn()` method, passing the name of the relation manager: ```php -use App\Filament\Resources\Blog\PostResource\RelationManagers\CommentsRelationManager; +use App\Filament\Resources\Blog\Posts\PostResource\RelationManagers\CommentsRelationManager; use Filament\Tables\Filters\SelectFilter; SelectFilter::make('post') @@ -779,7 +779,7 @@ SelectFilter::make('post') Any configuration that you make inside the resource can be overwritten on the relation manager. For example, if you wanted to disable pagination on the relation manager's inherited table but not the resource itself: ```php -use App\Filament\Resources\Blog\PostResource; +use App\Filament\Resources\Blog\Posts\PostResource; use Filament\Tables\Table; public function table(Table $table): Table @@ -792,7 +792,7 @@ public function table(Table $table): Table It is probably also useful to provide extra configuration on the relation manager if you wanted to add a header action to [create](#creating-related-records), [attach](#attaching-and-detaching-records), or [associate](#associating-and-dissociating-records) records in the relation manager: ```php -use App\Filament\Resources\Blog\PostResource; +use App\Filament\Resources\Blog\Posts\PostResource; use Filament\Tables\Table; public function table(Table $table): Table @@ -953,7 +953,7 @@ public static function getRecordSubNavigation(Page $page): array When registering a relation manager in a resource, you can use the `make()` method to pass an array of [Livewire properties](https://livewire.laravel.com/docs/properties) to it: ```php -use App\Filament\Resources\Blog\PostResource\RelationManagers\CommentsRelationManager; +use App\Filament\Resources\Blog\Posts\PostResource\RelationManagers\CommentsRelationManager; public static function getRelations(): array { diff --git a/docs/03-resources/08-nesting.md b/docs/03-resources/08-nesting.md new file mode 100644 index 0000000000..589e74c5a6 --- /dev/null +++ b/docs/03-resources/08-nesting.md @@ -0,0 +1,67 @@ +--- +title: Nested resources +--- + +## Overview + +[Relation managers](managing-relationships#creating-a-relation-manager) and [relation pages](managing-relationships#relation-pages) provide you with an easy way to render a table of related records inside a resource. + +For example, in a `CourseResource`, you may have a relation manager or page for `lessons` that belong to that course. You can create and edit lessons from the table, which opens modal dialogs. + +However, lessons may be too complex to be created and edited in a modal. You may wish that lessons had their own resource, so that creating and editing them would be a full page experience. This is a nested resource. + +## Creating a nested resource + +To create a nested resource, you can use the `make:filament-resource` command with the `--nested` option: + +```bash +php artisan make:filament-resource Lesson --nested +``` + +To access the nested resource, you will also need a [relation manager](managing-relationships#creating-a-relation-manager) or [relation page](managing-relationships#relation-pages). This is where the user can see the list of related records, and click links to the "create" and "edit" pages. + +To create a relation manager or page, you can use the `make:filament-relation-manager` or `make:filament-page` command: + +```bash +php artisan make:filament-relation-manager CourseResource lessons title + +php artisan make:filament-page ManageCourseLessons --resource=CourseResource --type=ManageRelatedRecords +``` + +When creating a relation manager or page, Filament will ask if you want each table row to link to a resource instead of opening a modal, to which you should answer "yes" and select the nested resource that you just created. + +After generating the relation manager or page, it will have a property pointing to the nested resource: + +```php +use App\Filament\Resources\Courses\Resources\Lessons\LessonResource; + +protected static ?string $relatedResource = LessonResource::class; +``` + +The nested resource class will have a property pointing to the parent resource: + +```php +use App\Filament\Resources\Courses\CourseResource; + +protected static ?string $parentResource = CourseResource::class; +``` + +## Customizing the relationship names + +In the same way that relation managers and pages predict the name of relationships based on the models in those relationships, nested resources do the same. Sometimes, you may have a relationship that does not fit the traditional relationship naming convention, and you will need to inform Filament of the correct relationship names for the nested resource. + +To customize the relationship names, first remove the `$parentResource` property from the nested resource class. Then define a `getParentResourceRegistration()` method: + +```php +use App\Filament\Resources\Courses\CourseResource; +use Filament\Resources\ParentResourceRegistration; + +public static function getParentResourceRegistration(): ?ParentResourceRegistration +{ + return CourseResource::asParent() + ->relationship('lessons') + ->inverseRelationship('course'); +} +``` + +You can omit the calls to `relationship()` and `inverseRelationship()` if you want to use the default names. diff --git a/docs/03-resources/08-global-search.md b/docs/03-resources/09-global-search.md similarity index 100% rename from docs/03-resources/08-global-search.md rename to docs/03-resources/09-global-search.md diff --git a/docs/03-resources/09-widgets.md b/docs/03-resources/10-widgets.md similarity index 99% rename from docs/03-resources/09-widgets.md rename to docs/03-resources/10-widgets.md index 5db5a9c64a..c448466a8e 100644 --- a/docs/03-resources/09-widgets.md +++ b/docs/03-resources/10-widgets.md @@ -1,5 +1,5 @@ --- -title: Widgets +title: Using widgets on resource pages --- ## Introduction diff --git a/docs/03-resources/10-custom-pages.md b/docs/03-resources/11-custom-pages.md similarity index 98% rename from docs/03-resources/10-custom-pages.md rename to docs/03-resources/11-custom-pages.md index b110353108..f5734326a6 100644 --- a/docs/03-resources/10-custom-pages.md +++ b/docs/03-resources/11-custom-pages.md @@ -1,5 +1,5 @@ --- -title: Custom pages +title: Custom resource pages --- ## Introduction diff --git a/docs/03-resources/12-nesting.md b/docs/03-resources/12-nesting.md deleted file mode 100644 index 7ae87e7ad7..0000000000 --- a/docs/03-resources/12-nesting.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: Nested resources ---- - -- Define `getParentResource()` on the child, returning the parent class name or `ParentResource::asParent()`, which then allows you to chain `->relationship()` or `->inverseRelationship()` to customize those names -- Remove the `index` route from the child resource, as this is handed by the parent -- Define a `RelationManager` or `ManageRelatedRecords` page on the parent resource for the child. If it's a page, the route should use the kebab relationship name -- Page / RM does not need much as it can read from the resource, but define `$relatedResource` prop on it instead of form/table, and if it's a page you prob want the `CreateAction` in the page header instead of table header -- When generating link to fake "index" page for child resource, page with kebab relationship name on parent used first, then view page w/ relation manager, then edit page w/ relation manager, then index page of parent diff --git a/docs/03-resources/11-security.md b/docs/03-resources/12-security.md similarity index 97% rename from docs/03-resources/11-security.md rename to docs/03-resources/12-security.md index 8ff93a3c5a..8a3ec7cc06 100644 --- a/docs/03-resources/11-security.md +++ b/docs/03-resources/12-security.md @@ -1,5 +1,5 @@ --- -title: Security +title: Resource security --- ## Protecting model attributes diff --git a/docs/12-components/02-table.md b/docs/12-components/02-table.md index 791ac9e3b8..5ae19ea9a4 100644 --- a/docs/12-components/02-table.md +++ b/docs/12-components/02-table.md @@ -116,7 +116,7 @@ Now that the table is using a relationship instead of a plain Eloquent query, al If your relationship uses a pivot table, you can use all pivot columns as if they were normal columns on your table, as long as they are listed in the `withPivot()` method of the relationship *and* inverse relationship definition. -Relationship tables are used in the Panel Builder as ["relation managers"](../panels/resources/relation-managers#creating-a-relation-manager). Most of the documented features for relation managers are also available for relationship tables. For instance, [attaching and detaching](../panels/resources/relation-managers#attaching-and-detaching-records) and [associating and dissociating](../panels/resources/relation-managers#associating-and-dissociating-records) actions. +Relationship tables are used in the Panel Builder as ["relation managers"](../panels/resources/managing-relationships#creating-a-relation-manager). Most of the documented features for relation managers are also available for relationship tables. For instance, [attaching and detaching](../panels/resources/managing-relationships#attaching-and-detaching-records) and [associating and dissociating](../panels/resources/relation-managers#associating-and-dissociating-records) actions. ## Generating table Livewire components with the CLI