Добавить аксессор по запросу

Я пытаюсь иногда добавить свой Accessor к результату Eloquent запроса.

Вот мой аксессуар:

public function getCatAttribute() {
    return "Here's a cat!";
}

Если я добавлю его, используя protected $appends = array('cat'); массив, он загружается просто отлично каждый раз.

Однако, удаляя это, поскольку я не хочу, чтобы оно всегда добавляло его, я не могу заставить его загрузить его в запрос Eloquent.

Вот что я попробовал:

$items = Item::with('cat')->get();

Как мне этого добиться?

2 ответа

Извините, если я опаздываю на вечеринку.

Вы не можете сделать:

$items = Item::with('cat')->get();

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

Вместо этого вы можете сделать это:

$items = Item::get();
$items->append('cat'); // this allows you to append accessors on-demand

РЕДАКТИРОВАТЬ:

ИМО единственный способ сделать это, это расширить класс вашей модели и использовать $appends как вы уже упоминали. Так что-то вроде

class ModelWithCat extends MyModel
{
    protected $appends = ['cat_attribute']
}

а затем назвать это как

ModelWithCat::get();

Ниже мой старый ответ для справки:

Я разбирал аналогичную проблему, в моем случае мне нужно было передать данные JSON из построителя запросов в таблицу Vue, и мне нужно было преобразовать данные в серверную часть, чтобы таблица Vue могла напрямую использовать эти данные. Мой код в контроллере выглядел так:

$query = Photo::query()->with(['user']);
if($filter) {
    $query->where('title', 'like', "%{$filter}%")
}
return $query->orderBy($field, $dir)->paginate($limit)

Я не нашел способа вызвать средство доступа для коллекции, и я не смог просмотреть результаты класса Paginator. Наконец, я понял, что это возвращает JSON в конце, который я могу изменить перед отправкой в ​​Vue. Итак, я закончил что-то вроде этого:

// transform the data before return them
$res_json = $query->orderBy($field, $dir)->paginate($limit)->toJson();
$res_decoded = json_decode( $res_json );
foreach($res_decoded->data as $item) {
    // transform the data.. you could probably call your accessor here like 
    // $item->cat = $item->cat , for me it was easier to just write the logic
    // here instead
    $item->license = 'dynamic-license';
}
return response()->json($res_decoded);

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

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

Item::get()->append('attibute_name');

Плюс при работе с пагинацией

$paginate = Item::paginate(10); // receive LengthAwarePaginator Instance
$items = collect($paginate->items()); // receive paginated items only to append
$items->each->append('attribute_name') // then simply you append it what auto accessor will do in toArray()

Вы уловили идею.

Я не знаю, понимаю ли я проблему, но вы можете создать аксессор для несуществующего атрибута. Если у вас есть cat атрибут, вы можете создать:

public function getModCatAttribute($value) {
  if ($this->cat == 'dog') {
     return "I'm a dog";
  }
  return $this->cat;
}

так что вы можете получить доступ сейчас $model->cat а также $model->mod_cat, Для общего использования этот метод лучше, потому что у вас всегда будет доступ к исходному свойству и к измененному, и вы всегда будете знать, какое из них изменено.

Но вы также можете сделать это следующим образом:

public function getCatAttribute($value) {
  if ($this->cat == 'dog') {
     return "I'm a dog";
  }
  return $this->cat;
}

И теперь вы можете получить доступ $model->cat и результат полагаться на то, что у вас есть внутри $cat приписывать.

Другие вопросы по тегам