Jak uzyskać jednowymiarową tablicę skalarną jako wynik zapytania doktryny dql?


116

Chcę uzyskać tablicę wartości z kolumny id tabeli aukcji. Gdyby to był surowy SQL, napisałbym:

SELECT id FROM auction

Ale kiedy robię to w Doctrine i wykonuję:

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

Otrzymuję taką tablicę:

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

Zamiast tego chciałbym uzyskać taką tablicę:

array(
    1,
    2
)

Jak mogę to zrobić za pomocą Doctrine?

Odpowiedzi:


197

PHP <5.5.0

Możesz użyć array_map, a ponieważ masz tylko jeden element na tablicę, możesz elegancko użyć 'current'jako wywołania zwrotnego, zamiast pisać zamknięcie .

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

Widzieć Petra Sobotki poniżej, aby uzyskać dodatkowe informacje dotyczące użycia pamięci.

PHP> = 5.5

Jak jcbwlkr odpowiedział poniżej , zalecany sposób użycia array_column.


9
getScalarResult () da ci ciągi znaków - użyj getArrayResult () jeśli chcesz liczb całkowitych
pHoutved

więc! czy array_column () jest lepsza w zarządzaniu pamięcią, czy też na wszystkie sposoby, co powinniśmy zrobić?
Dheeraj

151

Od PHP 5.5 możesz użyć array_column do rozwiązania tego problemu

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

98

Lepszym rozwiązaniem jest użycie PDO:FETCH_COLUMN. Aby to zrobić, potrzebujesz niestandardowego hydratora:

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

Dodaj to do Doctrine:

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

Możesz go używać w ten sposób:

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

Więcej informacji: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#custom-hydration-modes


2
Zmodyfikowałem to, więc obsługuje indexBy gist.github.com/ostrolucky/f9f1e0b271357573fde55b7a2ba91a32
gadelat

18

Odpowiedź Ascariusa jest elegancka, ale uważaj na zużycie pamięci! array_map()tworzy kopię przekazanej tablicy i skutecznie podwaja użycie pamięci. Jeśli pracujesz z setkami tysięcy elementów tablicy, może to stanowić problem. Odkąd w PHP 5.4 przekazywanie czasu wywołania zostało usunięte, więc nie możesz tego zrobić

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

W takim przypadku możesz wybrać oczywiste

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

2
Wydawało się to nieco sprzeczne z intuicją, ponieważ naszym celem jest „prawie skopiowanie” tablicy w obu przypadkach. Musiałem to przetestować, aby być przekonanym, że to prawda: gist.github.com/PowerKiKi/9571aea8fa8d6160955f
PowerKiKi

4

Myślę, że w Doctrine to niemożliwe. Po prostu przekształć tablicę wyników w żądaną strukturę danych za pomocą PHP:

$transform = function($item) {
    return $item['id'];
};
$result = array_map($transform, $em->createQuery("SELECT a.id FROM Auction a")->getScalarResult());
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.