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?

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.


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");

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


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'];
}

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());
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.