webentwicklung-frage-antwort-db.com.de

Erhalten Sie nur bestimmte Attribute mit der Laravel-Sammlung

Ich habe mir die Dokumentation und API für Laravel Collections angesehen, aber ich finde nicht, wonach ich suche:

Ich möchte ein Array mit Modelldaten aus einer Sammlung abrufen, aber nur die angegebenen Attribute erhalten.

Das heißt So etwas wie Users::toArray('id','name','email'), wo die Sammlung tatsächlich alle Attribute für die Benutzer enthält, da sie an anderer Stelle verwendet werden, aber an diesem spezifischen Ort benötige ich ein Array mit Benutzerdaten und nur die angegebenen Attribute.

In Laravel scheint dafür kein Helfer zu sein? - Wie mache ich das am einfachsten?

38
preyz

Sie können dies mit einer Kombination der vorhandenen Collection-Methoden tun. Es kann ein wenig schwierig sein, zuerst zu folgen, aber es sollte leicht genug sein, es zu brechen.

// 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();
});

Erklärung

Zunächst durchläuft die map()-Methode im Grunde nur die Collection und übergibt jedes Element in der Collection an den übergebenen Callback. Der von jedem Aufruf des Rückrufs zurückgegebene Wert erstellt die neue Collection, die von der map()-Methode generiert wird.

collect($user->toArray()) baut nur eine neue temporäre Collection aus den Users-Attributen auf.

->only(['id', 'name', 'email']) reduziert die temporäre Collection auf nur die angegebenen Attribute.

->all() wandelt die temporäre Collection in ein einfaches Array um.

Fassen Sie alles zusammen und Sie erhalten "Für jeden Benutzer in der Benutzerauflistung geben Sie ein Array nur der ID, des Namens und der E-Mail-Attribute zurück."


Laravel 5.5 Update

Laravel 5.5 fügte eine only-Methode für das Model hinzu, die im Grunde dasselbe tut wie die collect($user->toArray())->only([...])->all(), sodass dies in 5.5+ leicht vereinfacht werden kann:

// 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']);
});
82
patricus

wenn Sie User::get(['id', 'name', 'email']) verwenden, wird eine Sammlung mit den angegebenen Spalten zurückgegeben. Wenn Sie ein Array daraus machen möchten, verwenden Sie einfach toArray() nach der get() -Methode :

User::get(['id', 'name', 'email'])->toArray()

In den meisten Fällen müssen Sie die Sammlung nicht in ein Array konvertieren, da es sich bei Sammlungen eigentlich um Arrays auf Steroiden handelt und Sie über benutzerfreundliche Methoden zur Bearbeitung der Sammlung verfügen.

13
Ruffles

Ich habe jetzt eine eigene Lösung dafür gefunden:

1. Erstellt eine allgemeine Funktion zum Extrahieren bestimmter Attribute aus Arrays

Die folgende Funktion extrahiert nur bestimmte Attribute aus einem assoziativen Array oder einem Array von assoziativen Arrays (das letzte ist das, was Sie erhalten, wenn Sie $ collection-> toArray () in Laravel verwenden).

Es kann wie folgt verwendet werden:

$data = array_extract( $collection->toArray(), ['id','url'] );

Ich verwende folgende Funktionen:

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;   
}

Diese Lösung konzentriert sich nicht auf die Auswirkungen auf die Leistung beim Durchlaufen der Sammlungen in großen Datensätzen.

2. Implementiere das obige über eine eigene Sammlung in Laravel

Da ich $collection->extract('id','url'); einfach für jedes Collection-Objekt ausführen möchte, habe ich eine benutzerdefinierte Collection-Klasse implementiert.

Zuerst habe ich ein allgemeines Modell erstellt, das das Eloquent-Modell erweitert, aber eine andere Collection-Klasse verwendet. Alle Ihre Modelle müssen dieses benutzerdefinierte Modell erweitern, und nicht das Eloquent-Modell.

<?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 );
    }    
}
?>

Zweitens habe ich die folgende benutzerdefinierte Auflistungsklasse erstellt:

<?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 );
    }
}   
?>

Zuletzt sollten alle Modelle stattdessen Ihr benutzerdefiniertes Modell erweitern, z.

<?php
namespace App\Models;
class Article extends Model
{
...

Nun die Funktionen ab Nr. 1 oben werden von der Sammlung ordentlich verwendet, um die $collection->extract()-Methode verfügbar zu machen.

1
preyz
  1. Sie müssen die Attribute $hidden und $visible definieren. Sie werden global gesetzt (dh, es werden immer alle Attribute aus dem $visible-Array zurückgegeben).

  2. Mit der Methode makeVisible($attribute) und makeHidden($attribute) können Sie verborgene und sichtbare Attribute dynamisch ändern. Mehr: Eloquent: Serialisierung -> Eigenschaftssicht vorübergehend ändern

1
Grzegorz Gajda
$users = Users::get();

$subset = $users->map(function ($user) {
    return array_only(user, ['id', 'name', 'email']);
});
0
NEM

dies ist eine Nachbearbeitung des Patricus [answer] [1], jedoch für verschachtelte Arrays:

$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();
0
abbood

das scheint zu funktionieren, ist sich aber nicht sicher, ob es für die Leistung optimiert ist oder nicht.

$request->user()->get(['id'])->groupBy('id')->keys()->all();

ausgabe:

array:2 [
  0 => 4
  1 => 1
]
0
ken

Ich hatte ein ähnliches Problem, bei dem ich Werte aus einem großen Array auswählen musste, aber die resultierende Sammlung sollte nur Werte eines einzelnen Werts enthalten.

pluck() könnte für diesen Zweck verwendet werden (wenn nur ein Schlüsselelement erforderlich ist)

sie können auch reduce() verwenden. So etwas mit redu:

$result = $items->reduce(function($carry, $item) {
    return $carry->Push($item->getCode());
}, collect());
0
wired00