Przeglądałem dokumentację i API dla kolekcji Laravel, ale nie wydaje mi się, aby znaleźć to, czego szukam:
Chciałbym pobrać tablicę z danymi modelu z kolekcji, ale uzyskać tylko określone atrybuty.
To znaczy coś takiego Users::toArray('id','name','email')
, gdzie kolekcja faktycznie zawiera wszystkie atrybuty dla użytkowników, ponieważ są one używane gdzie indziej, ale w tym konkretnym miejscu potrzebuję tablicy z danymi użytkownika i tylko określonymi atrybutami.
Wygląda na to, że w Laravel nie ma pomocnika? - Jak mogę to zrobić najłatwiej?
Collection::implode()
. Może pobrać właściwość i wyodrębnić ją ze wszystkich obiektów w kolekcji. To nie odpowiada dokładnie na to pytanie, ale może być przydatne dla innych, którzy przyszli tu z Google, tak jak ja. laravel.com/docs/5.7/collections#method-implodeOdpowiedzi:
Możesz to zrobić, korzystając z kombinacji istniejących
Collection
metod. Na początku może to być trochę trudne, ale powinno być wystarczająco łatwe do zerwania.// 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(); });
Wyjaśnienie
Po pierwsze,
map()
metoda w zasadzie po prostu wykonuje iterację przez polecenieCollection
i przekazuje każdy element wCollection
przekazanym wywołaniu zwrotnym. Wartość zwracana z każdego wywołania wywołania zwrotnego buduje nowyCollection
wygenerowany przezmap()
metodę.collect($user->toArray())
jest po prostu budowaniem nowego, tymczasowegoCollection
zUsers
atrybutów.->only(['id', 'name', 'email'])
redukuje tymczasoweCollection
tylko do określonych atrybutów.->all()
zamienia tymczasową zCollection
powrotem w zwykłą tablicę.Połącz wszystko razem, a otrzymasz „Dla każdego użytkownika w kolekcji użytkowników, zwróć tablicę zawierającą tylko identyfikator, nazwę i atrybuty adresu e-mail”.
Aktualizacja Laravel 5.5
Laravel 5.5 dodał
only
metodę do Modelu, która zasadniczo robi to samo co thecollect($user->toArray())->only([...])->all()
, więc można to nieco uprościć w 5.5+ do:// 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']); });
Jeśli połączysz to z „przesyłaniem komunikatów wyższego rzędu” dla kolekcji wprowadzonym w Laravel 5.4, można to jeszcze bardziej uprościć:
// 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']);
źródło
::get([ 'fields', 'array' ])
zachowania QueryBuildera . Zasadniczo byłoby to przydatne w przypadku „zrzutów”.$newArray = Arr::only($initialArray, [ 'id', 'name' /* allowed keys list */ ]);
$users->map->only(['column', ...])
use
User::get(['id', 'name', 'email'])
, zwróci Ci kolekcję z określonymi kolumnami, a jeśli chcesz uczynić ją tablicą, po prostu użyjtoArray()
poget()
metodzie, jak poniżej:User::get(['id', 'name', 'email'])->toArray()
W większości przypadków nie musisz konwertować kolekcji na tablicę, ponieważ kolekcje są w rzeczywistości tablicami na sterydach i masz łatwe w użyciu metody manipulowania kolekcją.
źródło
->get(['id', 'email', 'name'])
która nie będzie ponownie sprawdzać bazy danych, ale zwróci nową kolekcję zawierającą tylko wybrane wartości. Metody takie jak pluck / lists, get, first itp. Mają takie same nazwy w obu klasach: w klasie konstruktora zapytań iw klasie kolekcji.Poniższa metoda również działa.
$users = User::all()->map(function ($user) { return collect($user)->only(['id', 'name', 'email']); });
źródło
Mam teraz własne rozwiązanie tego problemu:
1. Utworzono ogólną funkcję wyodrębniania określonych atrybutów z tablic
Poniższa funkcja wyodrębnia tylko określone atrybuty z tablicy asocjacyjnej lub tablicy tablic asocjacyjnych (ostatnia jest tym, co otrzymujesz wykonując $ collection-> toArray () w Laravel).
Można go używać w następujący sposób:
$data = array_extract( $collection->toArray(), ['id','url'] );
Używam następujących funkcji:
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; }
To rozwiązanie nie koncentruje się na wpływie na wydajność podczas przeglądania kolekcji w dużych zestawach danych.
2. Zaimplementuj powyższe poprzez niestandardową kolekcję w Laravel
Ponieważ chciałbym móc po prostu to zrobić
$collection->extract('id','url');
na dowolnym obiekcie kolekcji, zaimplementowałem niestandardową klasę kolekcji.Najpierw stworzyłem ogólny Model, który rozszerza model Eloquent, ale używa innej klasy kolekcji. Wszystkie modele, których potrzebujesz, aby rozszerzyć ten niestandardowy model, a nie model elokwentny wtedy.
<?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 ); } } ?>
Po drugie stworzyłem następującą klasę kolekcji niestandardowej:
<?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 ); } } ?>
Na koniec wszystkie modele powinny zamiast tego rozszerzyć model niestandardowy, na przykład:
<?php namespace App\Models; class Article extends Model { ...
Teraz funkcje z nr. 1 powyżej są starannie używane przez kolekcję, aby udostępnić
$collection->extract()
metodę.źródło
Musisz zdefiniować
$hidden
i określić$visible
atrybuty. Zostaną ustawione jako globalne (co oznacza, że zawsze zwracają wszystkie atrybuty z$visible
tablicy).Stosując metodę
makeVisible($attribute)
imakeHidden($attribute)
można dynamicznie zmieniać ukrytych i widocznych atrybutów. Więcej: Eloquent: Serialization -> Tymczasowa modyfikacja widoczności właściwościźródło
Miałem podobny problem, gdy musiałem wybrać wartości z dużej tablicy, ale chciałem, aby wynikowa kolekcja zawierała tylko wartości jednej wartości.
pluck()
może być użyty do tego celu (jeśli wymagany jest tylko 1 kluczowy element)możesz również użyć
reduce()
. Coś takiego z redukuj:$result = $items->reduce(function($carry, $item) { return $carry->push($item->getCode()); }, collect());
źródło
to jest kontynuacja patricus [odpowiedź] [1] powyżej, ale dla zagnieżdżonych tablic:
$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();
źródło
DB::table('roles')->pluck('title', 'name');
Źródła: https://laravel.com/docs/5.8/queries#retrieving-results (szukaj pluck)
źródło
wydaje się, że działa, ale nie jestem pewien, czy jest zoptymalizowany pod kątem wydajności, czy nie.
$request->user()->get(['id'])->groupBy('id')->keys()->all();
wynik:
array:2 [ 0 => 4 1 => 1 ]
źródło
$users = Users::get(); $subset = $users->map(function ($user) { return array_only(user, ['id', 'name', 'email']); });
źródło