Добавить пользовательский атрибут в модель Laravel/Eloquent при загрузке? - программирование

Добавить пользовательский атрибут в модель Laravel/Eloquent при загрузке?

Я бы хотел добавить пользовательский атрибут/свойство в модель Laravel/Eloquent при загрузке, аналогично тому, как это можно сделать с помощью RedBean $model->open().

Например, на данный момент у меня в контроллере есть:

public function index()
{
    $sessions = EventSession::all();
    foreach ($sessions as $i => $session) {
        $sessions[$i]->available = $session->getAvailability();
    }
    return $sessions;
}

Было бы неплохо иметь возможность опустить цикл и иметь уже установленный и заполненный атрибут "Доступный".

Я попытался использовать некоторые из событий модели, описанных в документации, для прикрепления этого свойства при загрузке объекта, но без успеха.

Примечания:

  • 'available' не является полем в базовой таблице.
  • $sessions возвращается как объект JSON как часть API, поэтому вызов типа $session->available() в шаблоне не является опцией
4b9b3361

Ответ 1

Проблема вызвана тем, что метод Model toArray() игнорирует любые аксессоры, которые напрямую не связаны с столбцом в базовой таблице.

Как сказал Тейлор Отуэлл здесь, "Это намеренно и по соображениям производительности". Однако есть простой способ достичь этого:

class EventSession extends Eloquent {

    protected $table = 'sessions';
    protected $appends = array('availability');

    public function getAvailabilityAttribute()
    {
        return $this->calculateAvailability();  
    }
}

Любые атрибуты, перечисленные в свойстве $appends, будут автоматически включаться в массив или форму JSON модели при условии, что вы добавили соответствующий аксессор.

Старый ответ (для версий Laravel < 4.08):

Лучшее решение, которое я нашел, это переопределить метод toArray() и либо установить явно атрибут:

class Book extends Eloquent {

    protected $table = 'books';

    public function toArray()
    {
        $array = parent::toArray();
        $array['upper'] = $this->upper;
        return $array;
    }

    public function getUpperAttribute()
    {
        return strtoupper($this->title);    
    }

}

или, если у вас много пользовательских аксессуаров, проведите через них все и примените их:

class Book extends Eloquent {

    protected $table = 'books';

    public function toArray()
    {
        $array = parent::toArray();
        foreach ($this->getMutatedAttributes() as $key)
        {
            if ( ! array_key_exists($key, $array)) {
                $array[$key] = $this->{$key};   
            }
        }
        return $array;
    }

    public function getUpperAttribute()
    {
        return strtoupper($this->title);    
    }

}

Ответ 2

Последнее, что есть на странице документации Laravel Eloquent:

protected $appends = array('is_admin');

Это может быть использовано автоматически для добавления новых методов доступа к модели без каких-либо дополнительных действий, таких как изменение методов, таких как ::toArray().

Просто создайте getFooBarAttribute(...) и добавьте foo_bar в массив $appends.

Ответ 3

Если вы переименуете свой getAvailability() в getAvailableAttribute() ваш метод станет средством доступа, и вы сможете читать его, используя ->available прямо на вашей модели.

Документы: https://laravel.com/docs/5.4/eloquent-mutators#accessors-and-mutators

РЕДАКТИРОВАТЬ: Поскольку ваш атрибут является "виртуальным", он не включен по умолчанию в JSON-представление вашего объекта.

Но я обнаружил следующее: пользовательские методы доступа к моделям не обрабатываются при вызове → toJson()?

Чтобы заставить ваш атрибут возвращаться в массив, добавьте его в качестве ключа в массив $ attribute.

class User extends Eloquent {
    protected $attributes = array(
        'ZipCode' => '',
    );

    public function getZipCodeAttribute()
    {
        return ....
    }
}

Я не проверял это, но для вас должно быть довольно тривиально попробовать в вашей текущей настройке.

Ответ 4

У меня было что-то похожее: У меня есть изображение атрибута в моей модели, оно содержит местоположение файла в папке Storage. Изображение должно быть возвращено в кодировке base64

//Add extra attribute
protected $attributes = ['picture_data'];

//Make it available in the json response
protected $appends = ['picture_data'];

//implement the attribute
public function getPictureDataAttribute()
{
    $file = Storage::get($this->picture);
    $type = Storage::mimeType($this->picture);
    return "data:" . $type . ";base64," . base64_encode($file);
}

Ответ 5

вы можете использовать функцию setAttribute в модели для добавления настраиваемого атрибута

Ответ 6

Допустим, у вас есть 2 столбца с именами first_name и last_name в вашей таблице пользователей, и вы хотите получить полное имя. Вы можете достичь с помощью следующего кода:

class User extends Eloquent {


    public function getFullNameAttribute()
    {
        return $this->first_name.' '.$this->last_name;
    }
}

теперь вы можете получить полное имя как:

$user = User::find(1);
$user->full_name;

Ответ 7

в моем случае, создав пустой столбец и установив его аксессуар, работал нормально. мой аксессуар заполняет пользовательский возраст из столбца dob. toArray() тоже работает.

public function getAgeAttribute()
{
  return Carbon::createFromFormat('Y-m-d', $this->attributes['dateofbirth'])->age;
}

Ответ 8

В моей модели подписки мне нужно знать, что подписка приостановлена или нет. вот как я это сделал

public function getIsPausedAttribute() {
    $isPaused = false;
    if (!$this->is_active) {
        $isPaused = true;
    }
}

тогда в представлении шаблона я могу использовать $subscription->is_paused, чтобы получить результат.

getIsPausedAttribute - это формат для установки пользовательского атрибута,

и использует is_paused, чтобы получить или использовать атрибут в вашем представлении.