Bagaimana cara mendapatkan array skalar satu dimensi sebagai hasil query dql doktrin?

116

Saya ingin mendapatkan array nilai dari kolom id tabel Lelang. Jika ini adalah SQL mentah, saya akan menulis:

SELECT id FROM auction

Tetapi ketika saya melakukan ini dalam Ajaran dan melaksanakan:

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

Saya mendapatkan array seperti ini:

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

Sebagai gantinya, saya ingin mendapatkan array seperti ini:

array(
    1,
    2
)

Bagaimana saya dapat melakukannya dengan menggunakan Doktrin?

Dawid Ohia
sumber

Jawaban:

197

PHP <5.5

Anda dapat menggunakan array_map, dan karena Anda hanya memiliki satu item per array, Anda dapat dengan elegan menggunakan 'current'sebagai callback, daripada menulis closure .

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

Lihat jawaban Petr Sobotka di bawah ini untuk info tambahan tentang penggunaan memori.

PHP> = 5,5

Seperti jawaban jcbwlkr di bawah ini , cara yang disarankan untuk digunakan array_column.

Lionel Gaillard
sumber
9
getScalarResult () akan memberi Anda string - gunakan getArrayResult () jika Anda ingin integer
pHoutved
begitu! apakah array_column () lebih baik dalam manajemen memori atau apakah itu cara sebelumnya, apa yang harus kita lakukan?
Dheeraj
151

Mulai PHP 5.5 Anda dapat menggunakan array_column untuk menyelesaikan ini

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

Solusi yang lebih baik adalah menggunakan PDO:FETCH_COLUMN. Untuk melakukannya, Anda memerlukan hidrator khusus:

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

Tambahkan ke Doktrin:

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

Dan Anda bisa menggunakannya seperti ini:

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

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

Ioan Badila
sumber
2
Saya telah memodifikasi ini sehingga mendukung indexBy gist.github.com/ostrolucky/f9f1e0b271357573fde55b7a2ba91a32
gadelat
18

Jawaban Ascarius memang elegan, tetapi waspadalah terhadap penggunaan memori! array_map()membuat salinan larik yang dilewati dan secara efektif menggandakan penggunaan memori. Jika Anda bekerja dengan ratusan ribu item array, ini bisa menjadi masalah. Sejak PHP 5.4 call-time pass by reference telah dihapus sehingga Anda tidak dapat melakukannya

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

Dalam hal ini Anda bisa pergi dengan jelas

$ids = array();
foreach($result as $item) {
  $ids[] = $item['id'];
}
Petr Sobotka
sumber
2
Tampaknya agak kontra-intuitif, karena tujuan kita adalah "hampir menyalin" larik dalam kedua kasus. Saya harus mengujinya sendiri untuk meyakinkan bahwa itu benar: gist.github.com/PowerKiKi/9571aea8fa8d6160955f
PowerKiKi
4

Saya pikir itu tidak mungkin dalam Doktrin. Cukup ubah larik hasil menjadi struktur data yang Anda inginkan menggunakan PHP:

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