Search code examples
phplaravelmodeleloquent

Laravel how to add a custom function in an Eloquent model?


I have a Product model

class Product extends Model
{
    ...

    public function prices()
    {
        return $this->hasMany('App\Price');
    }

    ...
}

I want to add a function which will return the lowest price, and in controller I can get the value using:

Product::find(1)->lowest;

I added this in Product model:

public function lowest()
{
    return $this->prices->min('price');
}

but I got an error saying:

Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation

And if I use Product::find(1)->lowest();, it will work. Is it possible to get Product::find(1)->lowest; to work?

Any help would be appreciated.


Solution

  • When you try to access a function in the model as a variable, laravel assumes you're trying to retrieve a related model. They call them dynamic properties. What you need instead is a custom attribute.

    Before Laravel 9

    Laravel 6 docs: https://laravel.com/docs/6.x/eloquent-mutators

    add following method to your model:

    public function getLowestAttribute()
    {
        //do whatever you want to do
        return 'lowest price';
    }
    

    Now you should be able to access it like this:

    Product::find(1)->lowest;
    

    EDIT: New in Laravel 9

    Laravel 9 offers a new way of dealing with attributes:

    Docs: https://laravel.com/docs/9.x/eloquent-mutators#accessors-and-mutators

    // use Illuminate\Database\Eloquent\Casts\Attribute;
    
    public function lowest(): Attribute
    {
         return new Attribute(
            get: function( $originalValue ){
             //do whatever you want to do
             //return $modifiedValue;
          });
    
         /**
          * Or alternatively:-
          *
          * return Attribute::get( function( $originalValue ){
          *    // do whatever you want to do
          *    // return $modifiedValue;
          * });
          */
    }