Я просматривал документацию и API для Laravel Collections, но, похоже, не нашел то, что ищу:
Я хотел бы получить массив с данными модели из коллекции, но получить только указанные атрибуты.
То есть что-то вроде того Users::toArray('id','name','email')
, где коллекция фактически содержит все атрибуты для пользователей, потому что они используются в другом месте, но в этом конкретном месте мне нужен массив с пользовательскими данными и только указанные атрибуты.
Кажется, в Laravel нет помощника для этого? - Как мне это сделать проще всего?
Collection::implode()
. Он может взять свойство и извлечь его из всех объектов в коллекции. Это не дает точного ответа на этот вопрос, но может быть полезно другим, пришедшим сюда из Google, как это сделал я. laravel.com/docs/5.7/collections#method-implodeОтветы:
Вы можете сделать это, используя комбинацию существующих
Collection
методов. Поначалу это может быть немного сложно, но должно быть достаточно легко сломать.// get your main collection with all the attributes... $users = Users::get(); // build your second collection with a subset of attributes. this new // collection will be a collection of plain arrays, not Users models. $subset = $users->map(function ($user) { return collect($user->toArray()) ->only(['id', 'name', 'email']) ->all(); });
Объяснение
Во-первых,
map()
метод просто выполняет итерациюCollection
и передает каждый элемент вCollection
переданный обратный вызов. Значение, возвращаемое при каждом вызове обратного вызова, создает новое значение,Collection
созданноеmap()
методом.collect($user->toArray())
просто строит новое, временноеCollection
изUsers
атрибутов.->only(['id', 'name', 'email'])
уменьшает временноеCollection
значение только до указанных атрибутов.->all()
превращает временноеCollection
обратно в простой массив.Сложите все это вместе, и вы получите «Для каждого пользователя в коллекции пользователей вернуть массив, состоящий только из атрибутов id, name и email».
Laravel 5.5 обновить
Laravel 5.5 добавил
only
к модели метод, который в основном делает то же самое, что и методcollect($user->toArray())->only([...])->all()
, поэтому в версии 5.5+ его можно немного упростить:// get your main collection with all the attributes... $users = Users::get(); // build your second collection with a subset of attributes. this new // collection will be a collection of plain arrays, not Users models. $subset = $users->map(function ($user) { return $user->only(['id', 'name', 'email']); });
Если вы объедините это с «обменом сообщениями более высокого порядка» для коллекций, представленных в Laravel 5.4, его можно упростить еще больше:
// get your main collection with all the attributes... $users = Users::get(); // build your second collection with a subset of attributes. this new // collection will be a collection of plain arrays, not Users models. $subset = $users->map->only(['id', 'name', 'email']);
источник
::get([ 'fields', 'array' ])
поведению QueryBuilder . В принципе, для «свалок» пригодится.$newArray = Arr::only($initialArray, [ 'id', 'name' /* allowed keys list */ ]);
$users->map->only(['column', ...])
use
User::get(['id', 'name', 'email'])
, он вернет вам коллекцию с указанными столбцами, и если вы хотите сделать ее массивом, просто используйтеtoArray()
послеget()
метода, например:User::get(['id', 'name', 'email'])->toArray()
В большинстве случаев вам не нужно преобразовывать коллекцию в массив, потому что коллекции на самом деле являются массивами на стероидах, и у вас есть простые в использовании методы для управления коллекцией.
источник
->get(['id', 'email', 'name'])
который не будет запрашивать базу данных, но вернет новую коллекцию только с выбранными значениями. Такие методы, как pluck / lists, get, first и т. Д., Имеют одинаковые имена как в классе построителя запросов, так и в классе коллекции.Метод ниже также работает.
$users = User::all()->map(function ($user) { return collect($user)->only(['id', 'name', 'email']); });
источник
Теперь я придумал собственное решение этой проблемы:
1. Создал общую функцию для извлечения определенных атрибутов из массивов.
Приведенная ниже функция извлекает только определенные атрибуты из ассоциативного массива или массива ассоциативных массивов (последнее - это то, что вы получаете при выполнении $ collection-> toArray () в Laravel).
Его можно использовать так:
$data = array_extract( $collection->toArray(), ['id','url'] );
Я использую следующие функции:
function array_is_assoc( $array ) { return is_array( $array ) && array_diff_key( $array, array_keys(array_keys($array)) ); } function array_extract( $array, $attributes ) { $data = []; if ( array_is_assoc( $array ) ) { foreach ( $attributes as $attribute ) { $data[ $attribute ] = $array[ $attribute ]; } } else { foreach ( $array as $key => $values ) { $data[ $key ] = []; foreach ( $attributes as $attribute ) { $data[ $key ][ $attribute ] = $values[ $attribute ]; } } } return $data; }
Это решение не фокусируется на влиянии на производительность при циклическом просмотре коллекций в больших наборах данных.
2. Реализуйте вышесказанное с помощью специальной коллекции в Laravel.
Поскольку я хотел бы иметь возможность просто работать
$collection->extract('id','url');
с любым объектом коллекции, я реализовал собственный класс коллекции.Сначала я создал общую модель, которая расширяет модель Eloquent, но использует другой класс коллекции. Все ваши модели должны расширять эту пользовательскую модель, а не модель Eloquent.
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model as EloquentModel; use Lib\Collection; class Model extends EloquentModel { public function newCollection(array $models = []) { return new Collection( $models ); } } ?>
Во-вторых, я создал следующий пользовательский класс коллекции:
<?php namespace Lib; use Illuminate\Support\Collection as EloquentCollection; class Collection extends EloquentCollection { public function extract() { $attributes = func_get_args(); return array_extract( $this->toArray(), $attributes ); } } ?>
Наконец, все модели должны расширять вашу пользовательскую модель, например:
<?php namespace App\Models; class Article extends Model { ...
Теперь функций от нет. 1 аккуратно используются коллекцией, чтобы сделать
$collection->extract()
метод доступным.источник
Вам нужно определить
$hidden
и$visible
атрибуты. Они будут установлены глобально (это означает, что всегда будут возвращаться все атрибуты из$visible
массива).Используя метод
makeVisible($attribute)
иmakeHidden($attribute)
вы можете динамически изменять скрытые и видимые атрибуты. Подробнее: Eloquent: сериализация -> Временное изменение видимости свойствисточник
У меня была аналогичная проблема, когда мне нужно было выбрать значения из большого массива, но я хотел, чтобы результирующая коллекция содержала только значения одного значения.
pluck()
можно использовать для этой цели (если требуется только 1 ключевой элемент)вы также можете использовать
reduce()
. Примерно так с уменьшением:$result = $items->reduce(function($carry, $item) { return $carry->push($item->getCode()); }, collect());
источник
это продолжение вышеупомянутого patricus [answer] [1], но для вложенных массивов:
$topLevelFields = ['id','status']; $userFields = ['first_name','last_name','email','phone_number','op_city_id']; return $onlineShoppers->map(function ($user) { return collect($user)->only($topLevelFields) ->merge(collect($user['user'])->only($userFields))->all(); })->all();
источник
DB::table('roles')->pluck('title', 'name');
Ссылки: https://laravel.com/docs/5.8/queries#retrieving-results (поиск по pluck)
источник
похоже, это работает, но не уверен, оптимизировано ли оно для производительности или нет.
$request->user()->get(['id'])->groupBy('id')->keys()->all();
вывод:
array:2 [ 0 => 4 1 => 1 ]
источник
$users = Users::get(); $subset = $users->map(function ($user) { return array_only(user, ['id', 'name', 'email']); });
источник