2015-08-07 18 views
8

Quando si crea una query utilizzando la sintassi DB::table('foo'), viene creata una classe generica (stdClass). C'è un modo per lanciare le righe risultanti in una classe specifica?Trasmetti i risultati della query Laravel alla classe

Ecco qualche esempio di codice che dovrebbe spiegare che cosa voglio fare:

$result = DB::table('foo')->get(); 
$converted = (Foo) $result; // Not going to work 

voglio esprimere tutti i (stdClass) oggetti della matrice alla classe Foo.

risposta

20

Sì, è possibile idratare i risultati nelle classi desiderate. Ho trovato la risposta sepolta in un pasticcio di mezze risposte e domande confuse che costituiscono il terribile Laracasts.com forum. Grazie per aver posto la domanda qui invece che lì.

Una volta arrivati ​​i risultati, idratare utilizzando la classe del modello:

$result = DB::table('foo')->get(); 
$converted = Foo::hydrate($result); 

Edit: trovato alcuni documentation on the hydrate method troppo, se questo aiuta

Edit 2: mi sono trovato in un situazione in cui avevo bisogno di trasmettere risultati da uno array o da uno collection, a seconda dei risultati di una query. Quando è stata restituita una raccolta, è stata correttamente idratata, ma quando il risultato è stato un array, erano solo stdClass. I wrote a quick method aggiunto al mio master model che utilizzava una raccolta di matrici o oggetti o un oggetto di impaginazione e lo lanciava correttamente sull'oggetto che volevo.

+0

Ma cosa succede se si utilizza l'impaginazione Eg $ coll = DB :: tavolo ('foo') -> orderBy ('title') -> paginate (30);. Poi idratazione fallisce ... Tutte le idee (Sry? - sono nuovo di laravel) – derRobert

+0

@derRobert Nessun problema: a volte in Laravel fare qualcosa che sembra normale o logico può essere molto faticoso Chiamare 'pagination' restituisce un oggetto' AbstractPaginator' che CONTIENE i risultati, quindi devono essere convertiti all'interno l'impaginatore: il mio Edit 2 da sopra link a una funzione che ho scritto che fa esattamente questo. Prendi il '$ coll 'tha t hai sopra, e lo lanci usando la mia funzione: 'Foo :: castResults ($ coll)' – dKen

-1

Sì. Per esempio:

$query = DB::table('example_tbl')->where('id', $id)->get(); 
    $cast = (array)$query; 
    var_dump($cast); 
+0

Forse avrei dovuto essere più specfico. Questo vale anche per le classi? – OskarD90

+0

'Builder :: get()' restituisce comunque una matrice di oggetti. 'var_dump ($ query) === var_dump ($ cast)' qui –

+0

sì.Ma prova a vedere un po 'di più. Sarà ancora un oggetto. Affinché tu acceda al valore, userai questo "->". Ma se lanci un array, puoi usare questo "[]" per ottenere il valore. – aldrin27

1

In genere si sarebbe raggiungere questo impostando la dichiarazione DOP fetch_style di PDO :: FETCH_CLASS come di seguito

$statement->fetchAll(PDO::FETCH_CLASS, "App\User");

Se si guarda il metodo Illuminate\Database\Connection::select vedrai che mentre è possibile impostare fetch_style/fetchMode, non è possibile il secondo argomento.

public function select($query, $bindings = array(), $useReadPdo = true) 
{ 
    return $this->run($query, $bindings, function($me, $query, $bindings) use ($useReadPdo) 
    { 
     if ($me->pretending()) return array(); 

     // For select statements, we'll simply execute the query and return an array 
     // of the database result set. Each element in the array will be a single 
     // row from the database table, and will either be an array or objects. 
     $statement = $this->getPdoForSelect($useReadPdo)->prepare($query); 

     $statement->execute($me->prepareBindings($bindings)); 

     return $statement->fetchAll($me->getFetchMode()); 
    }); 
} 

Né si può ottenere l'accesso alla dichiarazione prima fetchAll è chiamato a chiamare PDOStatement::setFetchMode per esempio.

Si potrebbe tentare di estendere Illuminate\Database\Connection e utilizzarlo in tutte le altre classi correlate a Database estendendo e sostituendo, se necessario, ma sembra un'attività pesante da mantenere.

L'altra opzione è quella di utilizzare Eloquent che restituirà le classi di un tipo particolare, ma si ottiene il leggero sovraccarico aggiuntivo di idratazione degli oggetti del modello.

class Foo extends Illuminate\Database\Eloquent\Model { 
    protected $table = 'foo'; 
} 

Foo::all() 
Foo::where('col', 1)->get() 
0

Non è possibile digitare il cast in questo modo.
È possibile modificare la classe Foo per gestire l'oggetto e lavorare con esso.

class Foo { 
    private $object = null; 
    public function __construct(stdClass $object) { 
    $this->object = $object; 
    } 

    public function __get($property) { 
    if (property_exists($this->object, $property)) { 
     return $this->object->$property; 
    } 
    } 

    public function __set($property, $value) { 
    if (property_exists($this->object, $property)) { 
     $this->object->$property = $value; 
    } 
    return $this; 
    } 

    public static function make(stdClass $object) { 
    return new self($object); 
    } 

    public static function makeCollection(array $collection) { 
    foreach($collection AS $key => $Item) { 
     $collection[$key] = self::make($Item); 
    } 
    return $collection; 
    } 
} 

$result = DB::table('foo')->get(); 
$converted = Foo::makeCollection($result); 
+1

Questo non funzionerà perché 'Builder :: get' restituisce una matrice di oggetti stdClass, non un singolo oggetto. È possibile eseguire iterazioni sul set di risultati e applicarlo per creare una nuova serie di risultati. –

+0

ha aggiornato la mia risposta (: – num8er

+1

Funzionerà. Per le persone che stanno leggendo questo, ricorda che avrai il risultato impostato due volte in memoria (in $ result e $ convertiti) quindi non dimenticare di cancellare '$ result' e pagare attenzione alla selezione di set di risultati grandi –

Problemi correlati