Я бы хотел добавить пользовательский атрибут/свойство в модель Laravel/Eloquent при загрузке, аналогично тому, как это можно сделать с помощью RedBean $model->open()
.
Например, на данный момент у меня в контроллере есть:
public function index()
{
$sessions = EventSession::all();
foreach ($sessions as $i => $session) {
$sessions[$i]->available = $session->getAvailability();
}
return $sessions;
}
Было бы неплохо иметь возможность опустить цикл и иметь уже установленный и заполненный атрибут "Доступный".
Я попытался использовать некоторые из событий модели, описанных в документации, для прикрепления этого свойства при загрузке объекта, но без успеха.
Примечания:
$sessions
возвращается как объект JSON как часть API, поэтому вызов типа $session->available()
в шаблоне не является опциейПроблема вызвана тем, что метод 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);
}
}
Последнее, что есть на странице документации Laravel Eloquent:
protected $appends = array('is_admin');
Это может быть использовано автоматически для добавления новых методов доступа к модели без каких-либо дополнительных действий, таких как изменение методов, таких как ::toArray()
.
Просто создайте getFooBarAttribute(...)
и добавьте foo_bar
в массив $appends
.
toArray
.
Если вы переименуете свой 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 ....
}
}
Я не проверял это, но для вас должно быть довольно тривиально попробовать в вашей текущей настройке.
->available
доступны на $session
объекта, но $sessions
преобразуется непосредственно в строку JSON (это часть API), есть не шанс использовать это.
EventSession::all()
возвращает объект JSON из API, вы на самом деле не используете модель Laravel, верно? Извините, я запутался в том, как вы реализовали свою модель.
вы можете использовать функцию setAttribute
в модели для добавления настраиваемого атрибута
У меня было что-то симулятивное: У меня есть изображение атрибута в моей модели, это содержит расположение файла в папке "Хранение". Изображение должно быть возвращено в кодировке base64
//Add extra attribute
protected $attributes = ['pictureData'];
//Make it available in the json response
protected $appends = ['pictureData'];
//implement the attribute
public function getPictureDataAttribute()
{
$file = Storage::get($this->picture);
$type = Storage::mimeType($this->picture);
return "data:" . $type . ";base64," . base64_encode($file);
}
в моем случае, создав пустой столбец и установив его аксессуар, работал нормально. мой аксессуар заполняет пользовательский возраст из столбца dob. toArray() тоже работает.
public function getAgeAttribute()
{
return Carbon::createFromFormat('Y-m-d', $this->attributes['dateofbirth'])->age;
}
Допустим, у вас есть 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;
В моей модели подписки мне нужно знать, что подписка приостановлена или нет.
вот как я это сделал public function getIsPausedAttribute() {
$isPaused = false;
if (!$this->is_active) {
$isPaused = true;
}
}
то в шаблоне просмотра я могу использовать
$subscription->is_paused
, чтобы получить результат.
getIsPausedAttribute
- это формат для установки пользовательского атрибута,
и использует is_paused
для получения или использования атрибута в вашем представлении.