Comment obtenir un tableau scalaire unidimensionnel en tant que résultat de requête doctrine dql?

116

Je veux obtenir un tableau de valeurs de la colonne id de la table d'enchères. Si c'était un SQL brut, j'écrirais:

SELECT id FROM auction

Mais quand je fais cela dans Doctrine et que j'exécute:

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

Je reçois un tableau comme celui-ci:

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

Au lieu de cela, j'aimerais obtenir un tableau comme celui-ci:

array(
    1,
    2
)

Comment puis-je faire cela en utilisant Doctrine?

Dawid Ohia
la source

Réponses:

197

PHP <5,5

Vous pouvez utiliser array_map, et comme vous n'avez qu'un élément par tableau, vous pouvez élégamment utiliser 'current'comme rappel, au lieu d'écrire une fermeture .

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

Voir la réponse de Petr Sobotka ci-dessous pour plus d'informations sur l'utilisation de la mémoire.

PHP> = 5,5

Comme jcbwlkr a répondu ci - dessous , la manière recommandée de l'utiliser array_column.

Lionel Gaillard
la source
9
getScalarResult () vous donnera des chaînes - utilisez getArrayResult () si vous voulez des entiers
pHoutved le
alors! est-ce que array_column () est meilleur pour la gestion de la mémoire ou est-ce la méthode foreach, que devrions-nous faire?
Dheeraj
151

Depuis PHP 5.5, vous pouvez utiliser array_column pour résoudre ce problème

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

Une meilleure solution consiste à utiliser PDO:FETCH_COLUMN. Pour ce faire, vous avez besoin d'un hydrateur personnalisé:

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

Ajoutez-le à Doctrine:

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

Et vous pouvez l'utiliser comme ceci:

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

Plus d'infos: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#custom-hydration-modes

Ioan Badila
la source
2
J'ai modifié cela pour qu'il supporte indexBy gist.github.com/ostrolucky/f9f1e0b271357573fde55b7a2ba91a32
gadelat
18

La réponse d'Ascarius est élégante, mais méfiez-vous de l'utilisation de la mémoire! array_map()crée une copie du tableau passé et double efficacement l'utilisation de la mémoire. Si vous travaillez avec des centaines de milliers d'éléments de tableau, cela peut devenir un problème. Depuis PHP 5.4, le passage par référence a été supprimé, vous ne pouvez donc pas le faire

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

Dans ce cas, vous pouvez aller avec

$ids = array();
foreach($result as $item) {
  $ids[] = $item['id'];
}
Petr Sobotka
la source
2
Cela semble un peu contre-intuitif, puisque notre objectif est de "presque copier" le tableau dans les deux cas. J'ai dû le tester moi-même pour être convaincu que c'était vraiment vrai: gist.github.com/PowerKiKi/9571aea8fa8d6160955f
PowerKiKi
4

Je pense que c'est impossible dans Doctrine. Transformez simplement le tableau de résultats dans la structure de données souhaitée en utilisant PHP:

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