Introduction
Resources are static classes that are used to build CRUD interfaces for your Eloquent models. They describe how administrators should be able to interact with data from your app using tables and forms.Creating a resource
To create a resource for theApp\Models\Customer model:
app/Filament/Resources directory:
CustomerResource.php.
The classes in the Pages directory are used to customize the pages in the app that interact with your resource. They’re all full-page Livewire components that you can customize in any way you wish.
The classes in the Schemas directory are used to define the content of the forms and infolists for your resource. The classes in the Tables directory are used to build the table for your resource.
Simple (modal) resources
Sometimes, your models are simple enough that you only want to manage records on one page, using modals to create, edit and delete records. To generate a simple resource with modals:getRelations() method, as relation managers 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
If you’d like to save time, Filament can automatically generate the form and table for you, based on your model’s database columns, using--generate:
Handling soft-deletes
By default, you will not be able to interact with deleted records in the app. If you’d like to add functionality to restore, force-delete and filter trashed records in your resource, use the--soft-deletes flag when generating the resource:
Generating a View page
By default, only List, Create and Edit pages are generated for your resource. If you’d also like a View page, use the--view flag:
Specifying a custom model namespace
By default, Filament will assume that your model exists in theApp\Models directory. You can pass a different namespace for the model using the --model-namespace flag:
Custom\Path\Models\Customer. Please note the double backslashes \\ in the command that are required.
Now when generating the resource, Filament will be able to locate the model and read the database schema.
Generating the model, migration and factory at the same time
If you’d like to save time when scaffolding your resources, Filament can also generate the model, migration and factory for the new resource at the same time using the--model, --migration and --factory flags in any combination:
Record titles
A$recordTitleAttribute may be set for your resource, which is the name of the column on your model that can be used to identify it from others.
For example, this could be a blog post’s title or a customer’s name:
Resource forms
Resource classes contain aform() method that is used to build the forms on the Create and Edit pages.
By default, Filament creates a form schema file for you, which is referenced in the form() method. This is to keep your resource class clean and organized, otherwise it can get quite large:
CustomerForm class, you can define the fields and layout of your form:
components() method is used to define the structure of your form. It is an array of fields and layout components, in the order they should appear in your form.
Check out the Forms docs for a guide on how to build forms with Filament.
Hiding components based on the current operation
ThehiddenOn() method of form components allows you to dynamically hide fields based on the current page or action.
In this example, we hide the password field on the edit page:
visibleOn() shortcut method for only showing a field on one page or action:
Resource tables
Resource classes contain atable() method that is used to build the table on the List page.
By default, Filament creates a table file for you, which is referenced in the table() method. This is to keep your resource class clean and organized, otherwise it can get quite large:
CustomersTable class, you can define the columns, filters and actions of the table:
Customizing the model label
Each resource has a “model label” which is automatically generated from the model name. For example, anApp\Models\Customer model will have a customer label.
The label is used in several parts of the UI, and you may customize it using the $modelLabel property:
getModelLabel() to define a dynamic label:
Customizing the plural model label
Resources also have a “plural model label” which is automatically generated from the model label. For example, acustomer label will be pluralized into customers.
You may customize the plural version of the label using the $pluralModelLabel property:
getPluralModelLabel() method:
Automatic model label capitalization
By default, Filament will automatically capitalize each word in the model label, for some parts of the UI. For example, in page titles, the navigation menu, and the breadcrumbs. If you want to disable this behavior for a resource, you can set$hasTitleCaseModelLabel in the resource:
Resource navigation items
Filament will automatically generate a navigation menu item for your resource using the plural label. If you’d like to customize the navigation item label, you may use the$navigationLabel property:
getNavigationLabel() method:
Setting a resource navigation icon
The$navigationIcon property supports the name of any Blade component. By default, Heroicons are installed. However, you may create your own custom icon components or install an alternative library if you wish.
getNavigationIcon() method:
Sorting resource navigation items
The$navigationSort property allows you to specify the order in which navigation items are listed:
getNavigationSort() method:
Grouping resource navigation items
You may group navigation items by specifying a$navigationGroup property:
getNavigationGroup() method to set a dynamic group label:
Grouping resource navigation items under other items
You may group navigation items as children of other items, by passing the label of the parent item as the$navigationParentItem:
getNavigationParentItem() method to set a dynamic parent item label:
Generating URLs to resource pages
Filament provides agetUrl() static method on resource classes to generate URLs to resources and specific pages within them. Traditionally, you would need to construct the URL by hand or by using Laravel’s route() helper, but these methods depend on knowledge of the resource’s slug or route naming conventions.
The getUrl() method, without any arguments, will generate a URL to the resource’s List page:
getPages() array of the resource. For example, to generate a URL to the Create page:
getPages() method use URL parameters like record. To generate a URL to these pages and pass in a record, you should use the second argument:
$customer can be an Eloquent model object, or an ID.
Generating URLs to resource modals
This can be especially useful if you are using simple resources with only one page. To generate a URL for an action in the resource’s table, you should pass thetableAction and tableActionRecord as URL parameters:
CreateAction in the header, you can pass it in to the action parameter:
Generating URLs to resources in other panels
If you have multiple panels in your app,getUrl() will generate a URL within the current panel. You can also indicate which panel the resource is associated with, by passing the panel ID to the panel argument:
Customizing the resource Eloquent query
Within Filament, every query to your resource model will start with thegetEloquentQuery() method.
Because of this, it’s very easy to apply your own query constraints or model scopes that affect the entire resource:
Disabling global scopes
By default, Filament will observe all global scopes that are registered to your model. However, this may not be ideal if you wish to access, for example, soft-deleted records. To overcome this, you may override thegetEloquentQuery() method that Filament uses:
Customizing the resource URL
By default, Filament will generate a URL based on the name of the resource. You can customize this by setting the$slug property on the resource:
Resource sub-navigation
Sub-navigation allows the user to navigate between different pages within a resource. Typically, all pages in the sub-navigation will be related to the same record in the resource. For example, in a Customer resource, you may have a sub-navigation with the following pages:- View customer, a
ViewRecordpage that provides a read-only view of the customer’s details. - Edit customer, an
EditRecordpage that allows the user to edit the customer’s details. - Edit customer contact, an
EditRecordpage that allows the user to edit the customer’s contact details. You can learn how to create more than one Edit page. - Manage addresses, a
ManageRelatedRecordspage that allows the user to manage the customer’s addresses. - Manage payments, a
ManageRelatedRecordspage that allows the user to manage the customer’s payments.
getRecordSubNavigation() method to the resource class:
Setting the sub-navigation position for a resource
The sub-navigation is rendered at the start of the page by default. You may change the position for all pages in a resource by setting the$subNavigationPosition property on the resource. The value may be SubNavigationPosition::Start, SubNavigationPosition::End, or SubNavigationPosition::Top to render the sub-navigation as tabs:
Deleting resource pages
If you’d like to delete a page from your resource, you can just delete the page file from thePages directory of your resource, and its entry in the getPages() method.
For example, you may have a resource with records that may not be created by anyone. Delete the Create page file, and then remove it from getPages():
CreateAction on the List page, the EditAction on the table or View page, or the ViewAction on the table or Edit page. If you want to remove those buttons, you must delete the actions as well.
Security
Authorization
For authorization, Filament will observe any model policies that are registered in your app. The following methods are used:viewAny()is used to completely hide resources from the navigation menu, and prevents the user from accessing any pages.create()is used to control creating new records.update()is used to control editing a record.view()is used to control viewing a record.delete()is used to prevent a single record from being deleted.deleteAny()is used to prevent records from being bulk deleted. Filament uses thedeleteAny()method because iterating through multiple records and checking thedelete()policy is not very performant. When using aDeleteBulkAction, if you want to call thedelete()method for each record anyway, you should use theDeleteBulkAction::make()->authorizeIndividualRecords()method. Any records that fail the authorization check will not be processed.forceDelete()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 theforceDeleteAny()method because iterating through multiple records and checking theforceDelete()policy is not very performant. When using aForceDeleteBulkAction, if you want to call theforceDelete()method for each record anyway, you should use theForceDeleteBulkAction::make()->authorizeIndividualRecords()method. Any records that fail the authorization check will not be processed.restore()is used to prevent a single soft-deleted record from being restored.restoreAny()is used to prevent records from being bulk restored. Filament uses therestoreAny()method because iterating through multiple records and checking therestore()policy is not very performant. When using aRestoreBulkAction, if you want to call therestore()method for each record anyway, you should use theRestoreBulkAction::make()->authorizeIndividualRecords()method. Any records that fail the authorization check will not be processed.reorder()is used to control reordering records in a table.
Skipping authorization
If you’d like to skip authorization for a resource, you may set the$shouldSkipAuthorization property to true:
Protecting model attributes
Filament will expose all model attributes to JavaScript, except if they are$hidden on your model. This is Livewire’s behavior for model binding. We preserve this functionality to facilitate the dynamic addition and removal of form fields after they are initially loaded, while preserving the data they may need.
While attributes may be visible in JavaScript, only those with a form field are actually editable by the user. This is not an issue with mass assignment.
mutateFormDataBeforeFill() method:
is_admin attribute from JavaScript, as it’s not being used by the form.