Как получить одномерный скалярный массив в качестве результата запроса доктрины dql?

116

Я хочу получить массив значений из столбца id таблицы аукциона. Если бы это был необработанный SQL, я бы написал:

SELECT id FROM auction

Но когда я делаю это в Doctrine и выполняю:

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

Я получаю такой массив:

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

Вместо этого я хотел бы получить такой массив:

array(
    1,
    2
)

Как я могу это сделать с помощью Doctrine?

Давид Охия
источник

Ответы:

197

PHP <5.5

Вы можете использовать array_map, и, поскольку у вас есть только один элемент на массив, вы можете элегантно использовать его 'current'как обратный вызов вместо написания закрытия .

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

См . Ответ Петра Соботки ниже для получения дополнительной информации об использовании памяти.

PHP> = 5.5

Как jcbwlkr ответил ниже , рекомендуемый способ его использования array_column.

Лайонел Гайяр
источник
9
getScalarResult () выдаст вам строки - используйте getArrayResult (), если вам нужны целые числа
pHoutved
так! лучше ли array_column () управлять памятью или это метод foreach, что мы должны делать?
Дирадж
151

Начиная с PHP 5.5 вы можете использовать array_column для решения этой проблемы.

$result = $em->createQuery("SELECT a.id FROM Auction a")->getScalarResult();
$ids = array_column($result, "id");
jcbwlkr
источник
98

Лучшее решение - использовать PDO:FETCH_COLUMN. Для этого вам понадобится специальный гидратор:

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

Добавьте это в Доктрину:

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

И вы можете использовать это так:

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

Дополнительная информация: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#custom-hydration-modes

Иоан Бадила
источник
2
Я изменил это так, чтобы он поддерживал index Автор: gist.github.com/ostrolucky/f9f1e0b271357573fde55b7a2ba91a32
gadelat
18

Ответ Аскария элегантен, но остерегайтесь использования памяти! array_map()создает копию переданного массива и эффективно удваивает использование памяти. Если вы работаете с сотнями тысяч элементов массива, это может стать проблемой. Поскольку передача времени вызова PHP 5.4 по ссылке была удалена, вы не можете выполнять

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

В этом случае вы можете пойти с очевидным

$ids = array();
foreach($result as $item) {
  $ids[] = $item['id'];
}
Петр Соботка
источник
2
Это казалось немного противоречащим интуиции, поскольку наша цель - «почти скопировать» массив в обоих случаях. Мне пришлось проверить это сам, чтобы убедиться, что это правда: gist.github.com/PowerKiKi/9571aea8fa8d6160955f
PowerKiKi
4

Я думаю, что в Доктрине это невозможно. Просто преобразуйте массив результатов в нужную структуру данных с помощью PHP:

$transform = function($item) {
    return $item['id'];
};
$result = array_map($transform, $em->createQuery("SELECT a.id FROM Auction a")->getScalarResult());
Minras
источник