Mayeenul Islam
Mayeenul Islam

Reputation: 4762

Laravel cache::remember is returing object as an array

Laravel Cache::remember is returning a LengthAwarePaginator object as an array.

function getNotifications( $userID ) {
    $values = Cache::remember('cache-key', 10, function() {

        $query = DB::table( 'user_notifications' )
                ->leftJoin( 'notifications', 'user_notifications.notification_id', '=', 'notifications.id' )
                ->where( 'user_notifications.user_id', $userID )
                ->select( 'notifications.*' )
                ->orderBy('created_at', 'DESC')
                ->paginate(5);

        return $query;

    });

    return $values;
}

If I dd($query) before returning from Cache closure, it's returning the following object, that accepts $value->links() to display pagination. LengthAwarePaginator

But whenever the Cache is storing $query into $values it's returning values as an array: Array of values

I tried commenting out the unserialize-block:

/*foreach( $values as $key => $value ) :
    $values[$key]->meta = self::maybeUnserialize($value->meta);
endforeach;*/

and confirmed that, that's not the cause.

I also tried, but failed:

$values = collect($values);

With multiple check and cross-check I am confirming that, the issue is the Cache::remember.

How can I force the Cache::remember return things as it is? So that I can let $object->links() work for me.

The actual code can be found here.

Upvotes: 3

Views: 2836

Answers (1)

Mayeenul Islam
Mayeenul Islam

Reputation: 4762

The issue is, Cache is made to store data, not the instance. So there are two ways to do this:

  1. When caching, cache information per page, or
  2. Get all the data while fetching, but make your own pagination

Solution 1:

We went for the second. But in case you need to go for the first solution, here's the code, I got from Laracasts, provided by chrisml:

$statuses = Cache::remember("statuses_{$id}_page_{$page}", 3, function() use ($event, $sort) {
    return $event->statuses()
        ->with('comments')
        ->latest()
        ->paginate(10);
});

On the above code, the cache key is changing on every page, so the cache is storing per page.

Solution 2:

But for my case, we thought we should go for the second, and that would be wise for us, in our case. So, we've to make our own pagination. My luck that psampaz did the base for us on their blog:

So, instead of using ->paginate() we're fetching all the data first, and caching them as previous.

$values = Cache::remember('cache-key', 10, function() {

    $query = DB::table( 'user_notifications' )
            ->leftJoin( 'notifications', 'user_notifications.notification_id', '=', 'notifications.id' )
            ->where( 'user_notifications.user_id', $userID )
            ->select( 'notifications.*' )
            ->orderBy('created_at', 'DESC')
            ->get(); // <----------- here

    return $query;

});

But before returning the $values, we're making our own pagination. We made some fixes to the psampaz's code:

use Illuminate\Support\Collection;
use Illuminate\Pagination\LengthAwarePaginator;

function getNotifications( $userID ) {

    // Collapsed the cached values here :)
    $values = Cache::remember('cache-key', 10, function() {...});

    // Get current page form url e.g. &page=6.
    $currentPage = LengthAwarePaginator::resolveCurrentPage();

    // Get current path.
    $currentPath = LengthAwarePaginator::resolveCurrentPath();

    // Create a new Laravel collection from the array data.
    $collection = new Collection($values);

    // Define how many items we want to be visible on each page.
    $perPage = 5;

    // Slice the collection to get the items to display on the current page.
    $results = $collection->slice(($currentPage - 1) * $perPage, $perPage)->all();

    // Create our paginator and pass it to the view.
    $values = new LengthAwarePaginator($results, count($collection), $perPage, $currentPage, ['path' => $currentPath]);

    return $values;
}

And finally, we can easily use the $object->links() for pagination, and it's awesome! :)

Upvotes: 3

Related Questions