Laravel 5.4 - How to set PDO Fetch Mode?
Asked Answered
A

5

11

The ability to customize the fetch mode was removed from L5.4 and is defaulted to PDO::FETCH_OBJ.

The upgrade guide states that you can override this by using an event listener:

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

I can't for the life of me understand how to implement this:

1) Where should I place the code? Should I register it with the EventServiceProvider?
2) When does the StatementPrepared event fire? (I only need to change the Fetch Mode for specific repository functions, not on a global scale).
3) Does the FetchMode revert itself automatically for subsequent queries?

Here's an example of my code:

<?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;
    }
}

Thank you!

Alumna answered 28/6, 2017 at 6:35 Comment(2)
PS: The code example was working perfectly on Laravel 5.3Alumna
Be are of implications listening to this and change the fetch mode: #47638369Conduplicate
D
8

Go to: app/Providers/EventServiceProvider.php

Add this to the top of the file:

use Illuminate\Database\Events\StatementPrepared;

In the boot method add:

Event::listen(StatementPrepared::class, function ($event) {
    $event->statement->setFetchMode(\PDO::FETCH_ASSOC);
});
Deflective answered 5/7, 2017 at 2:19 Comment(1)
Ah I just realized you did not want it on a global scale. This would do that.Deflective
P
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);

Try this. worked for me. You require only DB trait(use DB;).

Photoperiod answered 12/6, 2018 at 12:15 Comment(2)
or simply DB::connection()->getPdo()->query($sql)->fetchAll(\PDO::FETCH_ASSOC);Nationalize
@Nationalize - that one liner is perfect. Thank you.Dolf
C
0

In Laravel < 5.4

Add default fetch mode in config/database.php

return [
    'fetch' => PDO::FETCH_CLASS,
    ...
];
Catch answered 15/8, 2019 at 9:4 Comment(1)
Per the docs, this works great for Laravel versions below 5.4. Anything equal to or above 5.4 needs to use Scott's recommendation laravel.com/docs/5.4/upgradeEnlistment
D
0

Theres another option I find to by pass it Add env

DB_FETCHMODE=FETCH_ASSOC

In config/database add for connections.mysql

'fetch_mode' => env('DB_FETCHMODE', 'FETCH_ASSOC'),

In illuminate/datbase/connection.php replace prepared function with

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

This make default FETCH_ASSOC for your application

Then if you want to change it like before, add

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

a replacement of

DB::setFetchMode(PDO::FETCH_ASSOC);
Driskell answered 1/10, 2019 at 6:5 Comment(0)
W
0

I gave up on changing the fetch mode back and wrote a helper function to convert collections back into arrays-of-arrays:

/**
 * Converts any iterable to an array-of-arrays. Intended for use with Laravel's {@link \Illuminate\Support\Collection} type.
 * Provided for backwards-compatibility because FETCH_ASSOC is no longer available.
 * Avoid using this in new code to prevent overhead of conversion.
 *
 * @return array[][]
 */
public function collection2array(iterable $collection): array {
    $out = [];
    foreach($collection as $el) {
        $out[] = (array)$el;
    }
    return $out;
}

I wouldn't recommend using it all over the place because it probably reduces performance but to get past some errors I had, this was the easiest.

Wehrle answered 3/12, 2023 at 22:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.