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!

2
  • PS: The code example was working perfectly on Laravel 5.3 Commented Jun 28, 2017 at 6:37
  • Be are of implications listening to this and change the fetch mode: stackoverflow.com/questions/47637869/… Commented Dec 11, 2017 at 8:48

5 Answers 5

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);
});
Sign up to request clarification or add additional context in comments.

1 Comment

Ah I just realized you did not want it on a global scale. This would do that.
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;).

1 Comment

or simply DB::connection()->getPdo()->query($sql)->fetchAll(\PDO::FETCH_ASSOC);
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);

Comments

0

In Laravel < 5.4

Add default fetch mode in config/database.php

return [
    'fetch' => PDO::FETCH_CLASS,
    ...
];

1 Comment

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/upgrade
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.