¿Cómo obtener una matriz escalar unidimensional como resultado de una consulta de doctrine dql?

116

Quiero obtener una matriz de valores de la columna de identificación de la tabla de subastas. Si este fuera un SQL sin formato, escribiría:

SELECT id FROM auction

Pero cuando hago esto en Doctrine y ejecuto:

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

Obtengo una matriz como esta:

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

En cambio, me gustaría obtener una matriz como esta:

array(
    1,
    2
)

¿Cómo puedo hacer eso usando Doctrine?

Dawid Ohia
fuente

Respuestas:

197

PHP <5.5

Puede usar array_map, y dado que solo tiene un elemento por matriz, puede usarlo elegantemente 'current'como devolución de llamada, en lugar de escribir un cierre .

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

Consulte la respuesta de Petr Sobotka a continuación para obtener información adicional sobre el uso de la memoria.

PHP> = 5.5

Como responde jcbwlkr a continuación , la forma recomendada de usarlo array_column.

Lionel Gaillard
fuente
9
getScalarResult () le dará cadenas - use getArrayResult () si quiere enteros
pHoutved
¡entonces! ¿Array_column () es mejor en la gestión de la memoria o es de la forma anterior, qué debemos hacer?
Dheeraj
151

A partir de PHP 5.5, puede usar array_column para resolver esto

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

Una mejor solución es usar PDO:FETCH_COLUMN. Para hacerlo, necesita un hidratante personalizado:

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

Agrégalo a Doctrine:

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

Y puedes usarlo así:

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

Más información: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#custom-hydration-modes

Ioan Badila
fuente
2
He modificado esto para que sea compatible con indexBy gist.github.com/ostrolucky/f9f1e0b271357573fde55b7a2ba91a32
gadelat
18

La respuesta de Ascarius es elegante, ¡pero cuidado con el uso de la memoria! array_map()crea una copia de la matriz pasada y efectivamente duplica el uso de memoria. Si trabaja con cientos de miles de elementos de matriz, esto puede convertirse en un problema. Dado que el paso de tiempo de llamada de PHP 5.4 por referencia se ha eliminado, no puede hacer

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

En ese caso puedes ir con obvio

$ids = array();
foreach($result as $item) {
  $ids[] = $item['id'];
}
Petr Sobotka
fuente
2
Eso parecía un poco contrario a la intuición, ya que nuestro objetivo es "casi copiar" la matriz en ambos casos. Tuve que probarlo yo mismo para estar convencido de que es realmente cierto: gist.github.com/PowerKiKi/9571aea8fa8d6160955f
PowerKiKi
4

Creo que es imposible en Doctrine. Simplemente transforme la matriz de resultados en la estructura de datos que desee usando PHP:

$transform = function($item) {
    return $item['id'];
};
$result = array_map($transform, $em->createQuery("SELECT a.id FROM Auction a")->getScalarResult());
Minras
fuente