If you want to use the Filament admin panel, here's the code of the User
Model configured for it:
app/Models/User.php:
namespace App\Models; use Filament\Models\Contracts\FilamentUser;use Filament\Panel;use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable implements FilamentUser{ // ... public function canAccessPanel(Panel $panel): bool { return str_ends_with($this->email, '@yourdomain.com') && $this->hasVerifiedEmail(); }}
Three questions:
implements FilamentUser
? How is it different from extends
?FilamentUser
in the Contracts
namespace? What are "contracts"?canAccessPanel()
method exactly as described?Let's answer those, one by one.
The syntax extends XYZ
we had seen earlier means that our new class inherits all the same behavior of that parent class, with the ability to override something on top.
But what if we don't have a specific parent class but instead want to define a set of rules that all the "children" classes should follow?
Meet interfaces.
They are not classes. They don't have any implementations of properties/methods, but they have their definitions inside.
So, FilamentUser
is an interface:
vendor/filament/filament/src/Models/Contracts/FilamentUser.php
namespace Filament\Models\Contracts; use Filament\Panel; interface FilamentUser{ public function canAccessPanel(Panel $panel): bool;}
That's it, a short PHP file, right? So what is its purpose?
As I mentioned above, it defines the rules for all the classes that want to follow them.
In human language, if you want to use Filament and want your User model to have the ability to access the admin panel, you need to define the canAccessPanel()
method in your User class: that's the rule of the interface.
As you can see, the interface doesn't have the "body" of that method, only the definition:
Maybe some of you may ask: "Why not create a class and use extends here"?
The point is that Filament, as a framework, doesn't actually "know" what should be inside of that method. Framework creators can't define the panel access for you: only you, as a framework user, can define who can access the panel in your case.
So, Filament's role is to define the rules, and your role is to implement them.
Another question: why is it called a "contract"?
The word "contract" is a synonym for the "interface". It's just often used more broadly in many programming languages. If you think about it, it's a more human-language description of a "set of rules". By using Filament, you "sign a virtual contract" to follow its rules in your classes.
The word "interface" is a PHP language word for "contracts". But this word is also used in other languages, so if you talk on any dev forums or communities, they would likely understand you if you use either of those terms.
And it's not just a Filament thing: Laravel framework also uses Contracts as a namespace in Illuminate/Contracts, where many interfaces are defined inside.
Finally, what happens if we don't define that canAccessPanel()
in our User model?
We will get a PHP error:
Even PhpStorm IDE underlines the class immediately if you use implement FilamentUser
but don't actually implement its method(s):
In other words, without this method, Filament wouldn't work at all. That's why it's a strict rule to implement it. That's the whole point of interfaces: to give us strict rules.