Laravel, как добавить пользовательскую функцию в модель Eloquent?

У меня есть модель продукта

class Product extends Model
{
    ...

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

    ...
}

Я хочу добавить функцию, которая вернет самую низкую цену, а в контроллере я могу получить значение, используя:

Product::find(1)->lowest;

Я добавил это в модель продукта:

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

но я получил сообщение об ошибке:

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

И если я использую Product::find(1)->lowest();, он будет работать. Можно ли использовать Product::find(1)->lowest;?

Любая помощь будет оценена.

Ответ 1

Когда вы пытаетесь получить доступ к функции в модели как к переменной, laravel предполагает, что вы пытаетесь получить связанную модель. Они называют их динамическими свойствами. Вместо этого вам нужен собственный атрибут.

Добавьте следующий метод в вашу модель:

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

Теперь вы сможете получить к нему доступ следующим образом:

Product::find(1)->lowest;

Ответ 2

Использовать Eloquent accessors

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

Тогда

$product->lowest;

Ответ 3

Вы можете использовать вышеуказанные методы или использовать следующий метод для добавления функции непосредственно в существующую модель:

class Company extends Model
{
    protected $table = 'companies';

    // get detail by id
    static function detail($id)
    {
        return self::find($id)->toArray();
    }

    // get list by condition
    static function list($name = '')
    {
        if ( !empty($name) ) return self::where('name', 'LIKE', $name)->get()->toArray();
        else return self::all()->toArray();
    }
}

Или используйте Illuminate\Support\Facades\DB; внутри вашей функции. Надеюсь, что это поможет другим.

Ответ 4

почему ты просто не делаешь это? я знаю, это не то, что вы просили, и иногда это может быть плохой практикой. но в твоем случае я думаю, это хорошо.

$product = Product::with(['prices' => function ($query) {
   $query->min('price');
}])->find($id);