Courses

PHP for Laravel Developers

"implements" vs "extends": Interfaces in Filament User Model

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:

  1. What does it mean implements FilamentUser? How is it different from extends?
  2. Why is that FilamentUser in the Contracts namespace? What are "contracts"?
  3. What happens if we don't define the canAccessPanel() method exactly as described?

Let's answer those, one by one.


Implements vs Extends: Interfaces

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:

  • Method name
  • Method "visibility" (public/private/protected)
  • Method parameters
  • Method return type

Why Interface?

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.


Why "Contract"?

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.


What if we don't implement the method?

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.

avatar

As you can see, the interface doesn't have the "body" of that method, only the definition:

Method name

Method "visibility" (public/private/protected)

Method parameters

Method return type

Only public visability!

It's called a method signature.

👍 2