如何将一维标量数组作为doctrine dql查询结果?

Daw*_*hia 104 php doctrine-orm

我想从Auction表的id列中获取一组值.如果这是一个原始SQL我会写:

SELECT id FROM auction
Run Code Online (Sandbox Code Playgroud)

但是当我在Doctrine中执行此操作并执行:

$em->createQuery("SELECT a.id FROM Auction a")->getScalarResult(); 
Run Code Online (Sandbox Code Playgroud)

我得到一个像这样的数组:

array(
    array('id' => 1),
    array('id' => 2),
)
Run Code Online (Sandbox Code Playgroud)

相反,我想得到这样的数组:

array(
    1,
    2
)
Run Code Online (Sandbox Code Playgroud)

我怎么能用Doctrine做到这一点?

Lio*_*ard 189

PHP <5.5

你可以使用array_map,因为你只有每个数组的项目,你可以优雅地 'current'用作回调,而不是编写一个闭包.

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

有关内存使用的其他信息,请参阅下面的Petr Sobotka的答案.

PHP> = 5.5

正如jcbwlkr在下面回答的那样,建议使用它的方式array_column.

  • getScalarResult()将为您提供字符串 - 如果需要整数,请使用getArrayResult() (7认同)
  • 我喜欢优雅. (6认同)

jcb*_*lkr 134

从PHP 5.5开始,您可以使用array_column来解决此问题

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

  • PHP 5.5+的最佳解决方案 (4认同)

小智 91

更好的解决方案是使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

将其添加到Doctrine:

$em->getConfiguration()->addCustomHydrationMode('COLUMN_HYDRATOR', 'MyProject\Hydrators\ColumnHydrator');
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

$em->createQuery("SELECT a.id FROM Auction a")->getResult("COLUMN_HYDRATOR");
Run Code Online (Sandbox Code Playgroud)

更多信息:http: //docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#custom-hydration-modes

  • 我已经修改了它,所以它支持 indexBy https://gist.github.com/ostrolucky/f9f1e0b271357573fde55b7a2ba91a32 (3认同)
  • +1这是正确的答案。不要为不需要的内容编写解决方法!相反,为您需要的东西写一个解决方案:-) (2认同)

小智 17

Ascarius的答案很优雅,但要小心内存使用!array_map()创建传递数组的副本,有效地使内存使用量翻倍.如果您使用数十万个数组项,这可能会成为一个问题.由于PHP 5.4通过引用传递的调用时间已被删除,因此您无法做到

// note the ampersand
$ids = array_map('current', &$result);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,你可以明显地去

$ids = array();
foreach($result as $item) {
  $ids[] = $item['id'];
}
Run Code Online (Sandbox Code Playgroud)

  • 这看起来有点违反直觉,因为我们的目标是在两种情况下"几乎复制"数组.我必须自己测试才能确信它确实是真的:https://gist.github.com/PowerKiKi/9571aea8fa8d6160955f (2认同)

Tho*_*uer 17

从doctrine/orm 2.10.0开始,有一个内置的解决方案:

use Doctrine\ORM\AbstractQuery;

$query = $em->createQuery("SELECT a.id FROM Auction a");
return $query->getSingleColumnResult();
// Same as:
return $query->getResult(AbstractQuery::HYDRATE_SCALAR_COLUMN);
Run Code Online (Sandbox Code Playgroud)

文档:https://www.doctrine-project.org/projects/doctrine-orm/en/2.10/reference/dql-doctrine-query-language.html#scalar-column-Hydration


Min*_*ras 5

我认为在 Doctrine 中这是不可能的。只需使用 PHP 将结果数组转换为您想要的数据结构:

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