Come ottenere un array scalare unidimensionale come risultato di una query doctrine dql?


116

Voglio ottenere un array di valori dalla colonna id della tabella Auction. Se questo fosse un SQL grezzo scriverei:

SELECT id FROM auction

Ma quando lo faccio in Doctrine ed eseguo:

$em->createQuery("SELECT a.id FROM Auction a")->getScalarResult(); 

Ottengo un array come questo:

array(
    array('id' => 1),
    array('id' => 2),
)

Invece, mi piacerebbe ottenere un array come questo:

array(
    1,
    2
)

Come posso farlo usando Doctrine?

Risposte:


197

PHP <5.5

Puoi usare array_map, e poiché hai solo un elemento per array, puoi elegantemente usare 'current'come callback, invece di scrivere una chiusura .

$result = $em->createQuery("SELECT a.id FROM Auction a")->getScalarResult();
$ids = array_map('current', $result);

Vedere la risposta di Petr Sobotka di seguito per ulteriori informazioni sull'utilizzo della memoria.

PHP> = 5,5

Come ha risposto jcbwlkr di seguito , il modo consigliato da usare array_column.


9
getScalarResult () ti darà le stringhe - usa getArrayResult () se vuoi numeri interi
pHoutved

così! array_column () è migliore nella gestione della memoria o è il modo foreach, cosa dovremmo fare?
Dheeraj

151

A partire da PHP 5.5 puoi usare array_column per risolvere questo problema

$result = $em->createQuery("SELECT a.id FROM Auction a")->getScalarResult();
$ids = array_column($result, "id");

98

Una soluzione migliore è usare PDO:FETCH_COLUMN. Per farlo hai bisogno di un idratante personalizzato:

//MyProject/Hydrators/ColumnHydrator.php
namespace DoctrineExtensions\Hydrators\Mysql;

use Doctrine\ORM\Internal\Hydration\AbstractHydrator, PDO;

class ColumnHydrator extends AbstractHydrator
{
    protected function hydrateAllData()
    {
        return $this->_stmt->fetchAll(PDO::FETCH_COLUMN);
    }
}

Aggiungilo a Doctrine:

$em->getConfiguration()->addCustomHydrationMode('COLUMN_HYDRATOR', 'MyProject\Hydrators\ColumnHydrator');

E puoi usarlo in questo modo:

$em->createQuery("SELECT a.id FROM Auction a")->getResult("COLUMN_HYDRATOR");

Maggiori informazioni: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#custom-hydration-modes


2
L'ho modificato in modo che supporti indexBy gist.github.com/ostrolucky/f9f1e0b271357573fde55b7a2ba91a32
gadelat

18

La risposta di Ascarius è elegante, ma attenzione all'uso della memoria! array_map()crea una copia dell'array passato e raddoppia efficacemente l'utilizzo della memoria. Se lavori con centinaia di migliaia di elementi dell'array, questo può diventare un problema. Dal momento che PHP 5.4 call-time pass by reference è stato rimosso quindi non puoi farlo

// note the ampersand
$ids = array_map('current', &$result);

In tal caso puoi andare con ovvio

$ids = array();
foreach($result as $item) {
  $ids[] = $item['id'];
}

2
Sembrava un po 'controintuitivo, dal momento che il nostro obiettivo è "quasi copiare" l'array in entrambi i casi. Ho dovuto provarlo da solo per essere convinto che fosse effettivamente vero: gist.github.com/PowerKiKi/9571aea8fa8d6160955f
PowerKiKi

4

Penso che sia impossibile in Dottrine. Trasforma semplicemente l'array dei risultati nella struttura dati che desideri utilizzando PHP:

$transform = function($item) {
    return $item['id'];
};
$result = array_map($transform, $em->createQuery("SELECT a.id FROM Auction a")->getScalarResult());
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.