A part of the The problem with indirections post was about the behaviour of the Eloquent Model
class. This got me thinking, what if it was rewritten with PHP 8.4 as a minimum requirement.
The fields
Now
At the moment it is not required to add the fields as a property to get the values from the database.
For mass assignment you need the protected fillable property. But there is also a protected guarded property, which is the opposite of the fillable
attribute.
The default value can be added with the protected attributes property.
The relations are always functions.
And also accessors and mutators are functions.
class Person extends Model
{
protected $fillable = ['first_name'];
protected $attributes = ['first_name' => 'nobody'];
public function children(): HasMany
{
return $this->hasMany(Person::class, 'parent_id');
}
protected function firstName(): Attribute
{
return Attribute::make(
get: fn (string $value) => ucfirst($value),
set: fn (string $value) => strtolower($value),
);
}
}
Future
Because PHP 8.4 introduced property hooks the Model class could be:
class Person extends Model
{
public string $firstName = 'nobody' {
get => ucfirst($this->firstName);
set => strtolower($this->firstname)
}
public HasMany $children {
get => $this->hasMany(Person::class, 'parent_id');
set => $this->hasMany(Person::class, 'parent_id');
}
}
Metadata
Now
A lot of the metadata is set by a mix of public and protected properties.
And a few are constants.
class Person extends Model
{
const CREATED_AT = 'creation_date';
protected $table = 'custom_persons';
public $incrementing = false;
}
Future
Because we now use properties for the fields, using properties for metadata is asking for problems. Attributes would be a more logical choice.
use Illuminate\Database\Eloquent\Attributes as Eloquent;
#[Eloquent\Table('custom_persons')]
#[Eloquent\NoAutoIncrement]
#[Eloquent\CreationColumn('creation_date')]
class Person extends Model
{
}
Serialisation
Now
There are the protected hidden and visible properties to manipulate the output of the toArray
and toJson
methods.
There is also a functionality to add computed fields to the output.
class Person extends Model
{
protected hidden = ['fingerprint']
protected $appends = ['full_name'];
protected function fullName(): Attribute
{
return new Attribute(
get: fn () => $this->firstName . ' ' . $this->lastName,
);
}
}
Future
This is a mix of a property hook and an attribute.
#[Eloquent\HiddenFromSerialisation(['fingerprint'])]
class Person extends Model
{
public string $fullname {
get => $this->firstName . ' ' . $this->lastName;
}
}
Because the $fullname
property is a part of the class, it is not needed to configure it.
Conclusion
I am sure I'm missing a lot of options of the Model
class. I wanted to have a glance of what the class could be if it evolved with PHP.
What already can happen is moving the properties to attributes.
Are there changes you want to see to make the Model
class more in tune with the new PHP functionality?
Top comments (0)