Laravel 5.4 - 如何设置PDO Fetch模式?

10

自定义 fetch 模式的能力在 L5.4 中被移除,并默认采用 PDO::FETCH_OBJ。

升级指南中指出,您可以通过使用事件侦听器来覆盖此设置:

Event::listen(StatementPrepared::class, function ($event) {
    $event->statement->setFetchMode(...);
});

我真的不明白如何实现这个:

1)代码应该放在哪里?应该在 EventServiceProvider 中注册吗?
2)StatementPrepared 事件何时触发?(我只需要更改特定存储库函数的获取模式,而不是全局范围内)。
3)获取模式是否会自动为后续查询恢复默认值?

这里是我的代码示例:

<?php

namespace App\Repositories\Backend;

use DB;
use PDO;

class SystemRepository
{
    /**
     * Get the connection status variables.
     *
     * @return array
     */
    public function getConnectionStatus()
    {
        DB::connection('backend')->setFetchMode(PDO::FETCH_ASSOC);

        $result = DB::connection('backend')
            ->select(DB::raw("
                SHOW STATUS
                WHERE Variable_name = 'Max_used_connections'
                OR Variable_name = 'Max_used_connections_time'
                OR Variable_name = 'Threads_connected'
            "))
        ;

        DB::connection('backend')->setFetchMode(PDO::FETCH_CLASS);

        return $result;
    }
}

谢谢!


PS:这个代码示例在 Laravel 5.3 上运行得非常完美。 - Edward
注意听取此内容并更改获取模式:https://stackoverflow.com/questions/47637869/database-query-builder-sometimes-returns-array-instead-of-object-running-as-a-qu - patriziotomato
4个回答

8

前往:app/Providers/EventServiceProvider.php

在文件顶部添加以下内容:

use Illuminate\Database\Events\StatementPrepared;

boot方法中添加:
Event::listen(StatementPrepared::class, function ($event) {
    $event->statement->setFetchMode(\PDO::FETCH_ASSOC);
});

2
啊,我刚意识到你不想在全局范围内使用。这会实现那个效果。 - Scott

0
在 Laravel < 5.4 中,可以在 config/database.php 中添加默认的获取模式。
return [
    'fetch' => PDO::FETCH_CLASS,
    ...
];

2
根据文档,这对于 Laravel 5.4 版本以下的版本非常有效。任何等于或高于 5.4 的版本都需要使用 Scott 的建议 https://laravel.com/docs/5.4/upgrade。 - fungusanthrax

0
$dbh=DB::getPdo();
$sth = $dbh->prepare("SHOW STATUS
            WHERE Variable_name = 'Max_used_connections'
            OR Variable_name = 'Max_used_connections_time'
            OR Variable_name = 'Threads_connected' ");
$sth->execute(); 
$result = $sth->fetch(PDO::FETCH_CLASS);
print_r($result);

试试这个。对我有用。你只需要使用DB trait(use DB;)。


6
简单来说, DB::connection()->getPdo()->query($sql)->fetchAll(\PDO::FETCH_ASSOC) 的作用是执行一个 SQL 查询语句,并返回结果集。 - wp78de
@wp78de - 那个一行代码非常完美。谢谢。 - Eilert Hjelmeseth

0

我发现另外一个选项可以绕过它,那就是添加环境变量

DB_FETCHMODE=FETCH_ASSOC

在config/database中为connections.mysql添加。
'fetch_mode' => env('DB_FETCHMODE', 'FETCH_ASSOC'),

在 illuminate/datbase/connection.php 中,将 prepared 函数替换为:
protected function prepared (PDOStatement $statement){ 
    $config = $this->config;
    $statement->setFetchMode($config['fetch_mode'] == "FETCH_OBJ" ? 5 : ($config['fetch_mode'] == "FETCH_NUM" ? 3 : 2)); 
    $this->event(new Events\StatementPrepared(
        $this, $statement ));
    return $statement; 
 }

这将为您的应用程序设置默认的FETCH_ASSOC

如果您想像以前一样进行更改, 请添加

config(['database.connections.mysql.fetch_mode' => 'FETCH_OBJ']);

的替代品

DB::setFetchMode(PDO::FETCH_ASSOC);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接