Black Friday: coupon FRIDAY24 for 40% off Yearly/Lifetime membership! Read more here
Courses

PHP for Laravel Developers

Aliases and Multi-Level "extends": User Model

Now let's look at a specific Eloquent Model called User. It has some extra features on top of the regular Model.

Here's the code of the default Laravel 10 User model:

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
 
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
 
// ... properties like $fillable, $hidden, $casts
}

Potential questions to be asked here:

  1. A typical Laravel Model extends Model. What's that Authenticatable here?
  2. What's inside those use XXXXX files? Are those PHP classes?

Classes with Same Names: What to Do?

In addition to the public app/Models/User class, Laravel has its own "core" User class, in the Illuminate/Foundation/Auth namespace.

So, our User Model class should extend that Illuminate User class. And we have a naming conflict!

// That would throw an error
class User extends User
{
// ...
}

That's why we need to assign a different "alias" name to the extended class, on top in the "use" section, using the "as" keyword. Laravel creators called it "Authenticatable":

use Illuminate\Foundation\Auth\User as Authenticatable;
 
class User extends Authenticatable
{
// ...
}

Multi-level "extends"

Let's look at what's inside that User class inside the Laravel framework.

Illuminate/Foundation/Auth/User.php

use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\MustVerifyEmail;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\Access\Authorizable;
 
class User extends Model...
{
use Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;
}

You have already seen both syntaxes:

  • extends Model means the "parent" class to inherit properties/classes from it
  • use Authenticatable, Authorizable, ... are all Traits to include behavior from them

But have you noticed the hierarchy of classes here?

  1. app/Models/User extends Illuminate/Auth/User
  2. Illuminate/Auth/User extends Model

So yes, it is important to understand this fundamental OOP principle. You can build a "tree" of such classes, extending each other and expanding the properties/methods of each other.


Another Example of "inheritance": FormRequest

Another example of this hierarchy is Laravel validation with FormRequest classes.

If you run:

php artisan make:request StoreTaskRequest

You will end up with a class something like this:

app/Http/Requests/StoreTaskRequest.php:

use Illuminate\Foundation\Http\FormRequest;
 
class StoreTaskRequest extends FormRequest
{
public function authorize()
{
return false;
}
 
public function rules()
{
return [
//
];
}
}

See that extends FormRequest? If we click it in our IDE and see what's inside, we land on this class in the Laravel framework, from the /vendor folder:

Illuminate/Foundation/Http/FormRequest.php:

namespace Illuminate\Foundation\Http;
 
use Illuminate\Http\Request;
 
class FormRequest extends Request ...
{
use ValidatesWhenResolvedTrait;
 
// ...

Ok, another extends? Let's dive deeper: what's inside of that Request?

Illuminate/Http/Request.php:

use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
 
class Request extends SymfonyRequest
{
use Concerns\CanBePrecognitive,
Concerns\InteractsWithContentTypes,
Concerns\InteractsWithFlashData,
Concerns\InteractsWithInput,
Macroable;
 
// ...

Ok, so this Laravel class actually extends the Symfony class with the same name!

Here, we have a 3-level hierarchy, which may be even deeper if we dive into the underlying Symfony source.

So, you get the idea of hierarchy, so-called "inheritance"?

A practical non-framework example for this could be this:

  1. You create your own TaskRequest class with some common rules
  2. Then you create separate classes, StoreTaskRequest and UpdateTaskRequest, that both extend the same TaskRequest but override/change some of its behavior in their own way.

No comments or questions yet...