worksome / model-attributes
Model attributes are dynamically generated data on models added as a relationship.
Requires
- php: ^8.2
- illuminate/contracts: ^9.46|^10.0
- spatie/laravel-package-tools: ^1.14.1
Requires (Dev)
- nunomaduro/collision: ^6.2
- nunomaduro/larastan: ^2.3
- orchestra/testbench: ^7.18|^8.0
- pestphp/pest: ^1.22.3
- pestphp/pest-plugin-laravel: ^1.4
- pestphp/pest-plugin-parallel: ^1.1
- worksome/coding-style: ^2.3
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Model attributes are dynamically generated values for models. They are used as eloquent relationships which can be eager loaded.
Installation
You can install the package via composer:
composer require worksome/model-attributes
Usage
Assuming we have the following table structure:
users:
- id
reviews:
- id
- user_id
- stars
And the following models:
class User extends Model
{
public function reviews()
{
$this->hasMany(Review::class);
}
}
class Review extends Model
{
public function user()
{
$this->belongsTo(User::class);
}
}
We can add a rating property to each user that is the calculated average of a users reviews. First we're going to create a Model attribute:
class Rating extends \Worksome\ModelAttributes\ModelAttribute
{
protected $casts = [
'id' => 'int',
'user_id' => 'int',
'rating' => 'float',
];
public static function attributeGlobalScope(Builder $query): void
{
$ratingModel = new Rating();
$query
->groupBy($ratingModel->user()->getForeignKeyName())
->addSelect([
$ratingModel->getKeyName(), // id
$ratingModel->user()->getForeignKeyName(), // user_id
\DB::raw('avg(stars) as rating'), // rating
]);
}
}
and add it as a relationship to the user model
public function rating(): \Worksome\ModelAttributes\AttributeRelation|\Illuminate\Database\Eloquent\Relations\HasOne
{
return new \Worksome\ModelAttributes\AttributeRelation(
$this->hasOne(Rating::class)
);
}
So that it can be used like so:
$user = User::first();
$rating = $user->rating; // The rating model attribute created above
$rating->rating // the actual rating
Since model attributes are essentially dynamically generated data, and the rating is a scalar, we can override the getValue() method of a model in order to "reach" the rating faster:
public function getValue()
{
return $this->rating;
}
And now the rating can be accessed like so:
User::first()->rating;
And because it's a relationship it can be eager loaded:
User::with('rating')->get()->map->rating;
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Credits
License
The MIT License (MIT). Please see License File for more information.