Wie erhalte ich ein eindimensionales skalares Array als Ergebnis einer Doktrin-DQL-Abfrage?

116

Ich möchte ein Array von Werten aus der ID-Spalte der Auktionstabelle abrufen. Wenn dies ein rohes SQL wäre, würde ich schreiben:

SELECT id FROM auction

Aber wenn ich dies in Lehre tue und ausführe:

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

Ich bekomme ein Array wie folgt:

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

Stattdessen möchte ich ein Array wie dieses erhalten:

array(
    1,
    2
)

Wie kann ich das mit Doctrine machen?

Dawid Ohia
quelle

Antworten:

197

PHP <5,5

Sie können verwenden array_map, und da Sie nur ein Element pro Array haben, können Sie es elegant 'current'als Rückruf verwenden, anstatt einen Abschluss zu schreiben .

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

Siehe Petr Sobotka Antwort unten für weitere Informationen in Bezug auf die Speichernutzung.

PHP> = 5,5

Wie jcbwlkr unten antwortete , ist die empfohlene Verwendung array_column.

Lionel Gaillard
quelle
9
getScalarResult () gibt Ihnen Zeichenfolgen - verwenden Sie getArrayResult (), wenn Sie ganze Zahlen wollen
pHoutved
so! Ist array_column () besser in der Speicherverwaltung oder ist es der richtige Weg, was sollen wir tun?
Dheeraj
151

Ab PHP 5.5 können Sie array_column verwenden , um dies zu lösen

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

Eine bessere Lösung ist zu verwenden PDO:FETCH_COLUMN. Dazu benötigen Sie einen benutzerdefinierten Hydrator:

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

Fügen Sie es der Lehre hinzu:

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

Und Sie können es so verwenden:

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

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

Ioan Badila
quelle
2
Ich habe dies so geändert, dass es indexBy gist.github.com/ostrolucky/f9f1e0b271357573fde55b7a2ba91a32
gadelat
18

Die Antwort von Ascarius ist elegant, aber Vorsicht vor der Speichernutzung! array_map()Erstellt eine Kopie des übergebenen Arrays und verdoppelt effektiv die Speichernutzung. Wenn Sie mit Hunderttausenden von Array-Elementen arbeiten, kann dies zu einem Problem werden. Da PHP 5.4 Call-Time-Pass-by-Reference entfernt wurde, können Sie dies nicht tun

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

In diesem Fall können Sie mit offensichtlich gehen

$ids = array();
foreach($result as $item) {
  $ids[] = $item['id'];
}
Petr Sobotka
quelle
2
Das schien etwas kontraintuitiv zu sein, da unser Ziel darin besteht, das Array in beiden Fällen "fast zu kopieren". Ich musste es selbst testen, um überzeugt zu sein, dass es tatsächlich wahr ist: gist.github.com/PowerKiKi/9571aea8fa8d6160955f
PowerKiKi
4

Ich denke, dass es in der Lehre unmöglich ist. Transformieren Sie einfach das Ergebnisarray mit PHP in die gewünschte Datenstruktur:

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