worksome / model-attributes
Model attributes are dynamically generated data on models added as a relationship.
Installs: 250 513
Dependents: 0
Suggesters: 0
Security: 0
Stars: 4
Watchers: 9
Forks: 1
Open Issues: 0
pkg:composer/worksome/model-attributes
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
 
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.