Choosing the right tool for the job
Filament provides many ways to manage relationships in the app. Which feature you should use depends on the type of relationship you are managing, and which UI you are looking for.Relation managers - interactive tables underneath your resource forms
These are compatible with
HasMany, HasManyThrough, BelongsToMany, MorphMany and MorphToMany relationships.Select & checkbox list - choose from existing records or create a new one
These are compatible with
BelongsTo, MorphTo and BelongsToMany relationships.BelongsToMany relationship with a select, you’ll be able to select multiple options, not just one. Records will be automatically added to your pivot table when you submit the form. If you wish, you can swap out the multi-select dropdown with a simple checkbox list. Both components work in the same way.
Repeaters - CRUD multiple related records inside the owner’s form
These are compatible with
HasMany and MorphMany relationships.Layout form components - saving form fields to a single relationship
These are compatible with
BelongsTo, HasOne and MorphOne relationships.relationship() method. When you use this, all fields within that layout are saved to the related model instead of the owner’s model:
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. Please visit that page for more information about how to use it.
Creating a relation manager
To create a relation manager, you can use themake:filament-relation-manager command:
CategoryResourceis the name of the resource class for the owner (parent) model.postsis the name of the relationship you want to manage.titleis the name of the attribute that will be used to identify posts.
CategoryResource/RelationManagers/PostsRelationManager.php file. This contains a class where you are able to define a form and table for your relation manager:
getRelations() method:
Customizing the relation manager’s URL parameter
If you pass a key to the array returned fromgetRelations(), it will be used in the URL for that relation manager when switching between multiple relation managers. For example, you can pass posts to use ?relation=posts in the URL instead of a numeric array index:
Read-only mode
Relation managers are usually displayed on either the Edit or View page of a resource. On the View page, Filament will automatically hide all actions that modify the relationship, such as create, edit, and delete. We call this “read-only mode”, and it is there by default to preserve the read-only behavior of the View page. However, you can disable this behavior, by overriding theisReadOnly() method on the relation manager class to return false all the time:
Unconventional inverse relationship names
For inverse relationships that do not follow Laravel’s naming guidelines, you may wish to use theinverseRelationship() method on the table:
Handling soft-deletes
By default, you will not be able to interact with deleted records in the relation manager. If you’d like to add functionality to restore, force-delete and filter trashed records in your relation manager, use the--soft-deletes flag when generating the relation manager:
Listing related records
Related records will be listed in a table. The entire relation manager is based around this table, which contains actions to create, edit, attach / detach, associate / dissociate, and delete records. You may use any features of the Table Builder to customize relation managers.Listing with pivot attributes
ForBelongsToMany and MorphToMany relationships, you may also add pivot table attributes. For example, if you have a TeamsRelationManager for your UserResource, and you want to add the role pivot attribute to the table, you can use:
withPivot() method of the relationship and inverse relationship.
Creating related records
Creating with pivot attributes
ForBelongsToMany and MorphToMany relationships, you may also add pivot table attributes. For example, if you have a TeamsRelationManager for your UserResource, and you want to add the role pivot attribute to the create form, you can use:
withPivot() method of the relationship and inverse relationship.
Customizing the CreateAction
To learn how to customize the CreateAction, including mutating the form data, changing the notification, and adding lifecycle hooks, please see the Actions documentation.
Editing related records
Editing with pivot attributes
ForBelongsToMany and MorphToMany relationships, you may also edit pivot table attributes. For example, if you have a TeamsRelationManager for your UserResource, and you want to add the role pivot attribute to the edit form, you can use:
withPivot() method of the relationship and inverse relationship.
Customizing the EditAction
To learn how to customize the EditAction, including mutating the form data, changing the notification, and adding lifecycle hooks, please see the Actions documentation.
Attaching and detaching records
Filament is able to attach and detach records forBelongsToMany and MorphToMany relationships.
When generating your relation manager, you may pass the --attach flag to also add AttachAction, DetachAction and DetachBulkAction to the table:
$table arrays:
Preloading the attachment modal select options
By default, as you search for a record to attach, options will load from the database via AJAX. If you wish to preload these options when the form is first loaded instead, you can use thepreloadRecordSelect() method of AttachAction:
Attaching with pivot attributes
When you attach record with theAttach button, you may wish to define a custom form to add pivot attributes to the relationship:
$action->getRecordSelect() returns the select field to pick the record to attach. The role text input is then saved to the pivot table’s role column.
Please ensure that any pivot attributes are listed in the withPivot() method of the relationship and inverse relationship.
Scoping the options to attach
You may want to scope the options available toAttachAction:
Searching the options to attach across multiple columns
By default, the options available toAttachAction will be searched in the recordTitleAttribute() of the table. If you wish to search across multiple columns, you can use the recordSelectSearchColumns() method:
Attaching multiple records
Themultiple() method on the AttachAction component allows you to select multiple values:
Customizing the select field in the attached modal
You may customize the select field object that is used during attachment by passing a function to therecordSelect() method:
Selecting records to attach using a modal table
You may use thetableSelect() method to select records in the attachment modal using a full Filament table, instead of a simple select dropdown:
ProductsTable class is a standard Filament table class, with a configure() method that defines the table’s columns:
Handling duplicates
By default, you will not be allowed to attach a record more than once. This is because you must also set up a primaryid column on the pivot table for this feature to work.
Please ensure that the id attribute is listed in the withPivot() method of the relationship and inverse relationship.
Finally, add the allowDuplicates() method to the table:
Improving the performance of detach bulk actions
By default, theDetachBulkAction will load all Eloquent records into memory, before looping over them and detaching them one by one.
If you are detaching a large number of records, you may want to use the chunkSelectedRecords() method to fetch a smaller number of records at a time. This will reduce the memory usage of your application:
- To allow individual records in the collection to be authorized with a model policy before detaching (using
authorizeIndividualRecords('delete'), for example). - To ensure that model events are run when detaching records, such as the
deletinganddeletedevents in a model observer.
fetchSelectedRecords(false) method, which will not fetch the records into memory before detaching them, and instead will detach them in a single query:
Associating and dissociating records
Filament is able to associate and dissociate records forHasMany and MorphMany relationships.
When generating your relation manager, you may pass the --associate flag to also add AssociateAction, DissociateAction and DissociateBulkAction to the table:
$table arrays:
Preloading the associate modal select options
By default, as you search for a record to associate, options will load from the database via AJAX. If you wish to preload these options when the form is first loaded instead, you can use thepreloadRecordSelect() method of AssociateAction:
Scoping the options to associate
You may want to scope the options available toAssociateAction:
Searching the options to associate across multiple columns
By default, the options available toAssociateAction will be searched in the recordTitleAttribute() of the table. If you wish to search across multiple columns, you can use the recordSelectSearchColumns() method:
Associating multiple records
Themultiple() method on the AssociateAction component allows you to select multiple values:
Customizing the select field in the associate modal
You may customize the select field object that is used during association by passing a function to therecordSelect() method:
Improving the performance of dissociate bulk actions
By default, theDissociateBulkAction will load all Eloquent records into memory, before looping over them and dissociating them one by one.
If you are dissociating a large number of records, you may want to use the chunkSelectedRecords() method to fetch a smaller number of records at a time. This will reduce the memory usage of your application:
- To allow individual records in the collection to be authorized with a model policy before dissociation (using
authorizeIndividualRecords('update'), for example). - To ensure that model events are run when dissociating records, such as the
updatingandupdatedevents in a model observer.
fetchSelectedRecords(false) method, which will not fetch the records into memory before dissociating them, and instead will dissociate them in a single query:
Viewing related records
When generating your relation manager, you may pass the--view flag to also add a ViewAction to the table:
ViewAction to the $table->recordActions() array:
Deleting related records
By default, you will not be able to interact with deleted records in the relation manager. If you’d like to add functionality to restore, force-delete and filter trashed records in your relation manager, use the--soft-deletes flag when generating the relation manager:
Customizing the DeleteAction
To learn how to customize the DeleteAction, including changing the notification and adding lifecycle hooks, please see the Actions documentation.
Importing related records
TheImportAction can be added to the header of a relation manager to import records. In this case, you probably want to tell the importer which owner these new records belong to. You can use import options to pass through the ID of the owner record:
afterSave() hook of the importer:
Accessing the relationship’s owner record
Relation managers are Livewire components. When they are first loaded, the owner record (the Eloquent record which serves as a parent - the main resource model) is saved into a property. You can read this property using:static method like form() or table(), $this isn’t accessible. So, you may use a callback to access the $livewire instance:
$livewire->ownerRecord in.
Grouping relation managers
You may choose to group relation managers together into one tab. To do this, you may wrap multiple managers in aRelationGroup object, with a label:
Conditionally showing relation managers
By default, relation managers will be visible if theviewAny() method for the related model policy returns true.
You may use the canViewForRecord() method to determine if the relation manager should be visible for a specific owner record and page:
Combining the relation manager tabs with the form
On the Edit or View page class, override thehasCombinedRelationManagerTabsWithContent() method:
Customizing the content tab
On the Edit or View page class, override thegetContentTabComponent() method, and use any Tab customization methods:
Setting the position of the form tab
By default, the form tab is rendered before the relation tabs. To render it after, you can override thegetContentTabPosition() method on the Edit or View page class:
Customizing relation manager tabs
To customize the tab for a relation manager, override thegetTabComponent() method, and use any Tab customization methods:
tab() method:
Sharing a resource’s form and table with a relation manager
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 theform() and table() methods of the resource from the relation manager:
Hiding a shared form component on the relation manager
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 aSelect 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:
Hiding a shared table column on the relation manager
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 thehiddenOn() method, passing the name of the relation manager:
Hiding a shared table filter on the relation manager
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 thehiddenOn() method, passing the name of the relation manager:
Overriding shared configuration on the relation manager
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:Customizing the relation manager Eloquent query
You can apply your own query constraints or model scopes that affect the entire relation manager. To do this, you can pass a function to themodifyQueryUsing() method of the table, inside which you can customize the query:
Customizing the relation manager title
To set the title of the relation manager, you can use the$title property on the relation manager class:
getTitle() method on the relation manager class:
$table->heading() method:
Customizing the relation manager record title
The relation manager uses the concept of a “record title attribute” to determine which attribute of the related model should be used to identify it. When creating a relation manager, this attribute is passed as the third argument to themake:filament-relation-manager command:
title attribute of the Post model will be used to identify a post in the relation manager.
This is mainly used by the action classes. For instance, when you attach or associate a record, the titles will be listed in the select field. When you edit, view or delete a record, the title will be used in the header of the modal.
In some cases, you may want to concatenate multiple attributes together to form a title. You can do this by replacing the recordTitleAttribute() configuration method with recordTitle(), passing a function that transforms a model into a title:
recordTitle(), and you have an associate action or attach action, you will also want to specify search columns for those actions:
Relation pages
Using aManageRelatedRecords page is an alternative to using a relation manager, if you want to keep the functionality of managing a relationship separate from editing or viewing the owner record.
This feature is ideal if you are using resource sub-navigation, as you are easily able to switch between the View or Edit page and the relation page.
To create a relation page, you should use the make:filament-page command:
getPages() method:
table() and form().
Adding relation pages to resource sub-navigation
If you’re using resource sub-navigation, you can register this page as normal ingetRecordSubNavigation() of the resource:
Passing properties to relation managers
When registering a relation manager in a resource, you can use themake() method to pass an array of Livewire properties to it:
status in the relation manager class using $this->status.
Disabling lazy loading
By default, relation managers are lazy-loaded. This means that they will only be loaded when they are visible on the page. To disable this behavior, you may override the$isLazy property on the relation manager class: