Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mirkomen77's avatar

Rename "data" key in collection result

For example,

DB::table('contracts AS C')->paginate(1)

returns


 {
  "current_page": 1,
    "data": [
        {
            "id": 191,
            "buyer": "John",
            "provider": "Jane"
        }
    ],
    "from": 1,
    "last_page": 1,
    "next_page_url": "",
    "path": "",
    "per_page": 1,
    "prev_page_url": null,
    "to": 1,
    "total": 1
}

How would I change the "data" key to something else, like "contracts", to have:


 {
  "current_page": 1,
    "contracts": [
        {
            "id": 191,
            "buyer": "John",
            "provider": "Jane"
        }
    ],
    "from": 1,
    "last_page": 1,
    "next_page_url": "",
    "path": "",
    "per_page": 1,
    "prev_page_url": null,
    "to": 1,
    "total": 1
}

Many thanks

0 likes
12 replies
tykus's avatar

I don't think there is any configuration for this. If you look at the source for the Paginator class, the data word is hardcoded into the toArray() method. You have the option (if this matters for you) to extend the Laravel paginator and override the toArray() method and swapping out the Paginator that is bound into the container.

mirkomen77's avatar

That looks like a lot of trouble.

I could simply convert it to array then:

$result = DB::table('contracts AS C')->paginate(1)->toArray();
$data = $result['data'];
unset($result['data']);
$result['contracts'] = $data;


return $result;

but I was wondering if there was a more elegant solution.

tykus's avatar

Yeah, it would be a lot of trouble... that's why I wondered if it would really matter. The solution you suggest is about as elegant as it gets for renaming keys in an array, though you could shortcut it slightly by assigning directly to the new key from the old one:

$result = DB::table('contracts AS C')->paginate(1)->toArray();
$result['contracts'] = $result['data'];
unset($result['data']);
return $result;
mirkomen77's avatar

That is good.

I can put that code in a transformation class anyway :)

tykus's avatar

It depends on your needs really. Either way, I would leave the query in your controller and pass the result through the helper/transformer to replace the key.

Snapey's avatar

Is this causing you an issue in json on the client (for instance) since normally the fact that it is held as data is irrelevant

$contracts  = DB::table('contracts AS C')->paginate(1);

$contract = contracts->first();

or

$contracts = DB::table('contracts AS C')->paginate(10);

//(blade)
@foreach($contracts as $contract)

    // do stuff with one item
@endforeach 
mirkomen77's avatar

@Snapey we are following this standard http://jsonapi.org/ across our systems for consistency, therefore the json produced by default by Laravel is not quite right.

I wrote a transformer class to take care of that.

1 like
Snapey's avatar

How does that fit with a paginator? I assume you are transforming those keys also?

mirkomen77's avatar

For example:


<?php

namespace App\Libraries;

class JsonResponseTransformer
{

    public static function create($key, $paginator, $identifiers)
    {

        $in = $paginator->toArray();

        //get 'data' property into "out" array and then remove it
        $out[$key] = $in['data'];
        unset($in['data']);

        //set links object
        $out['links'] = [
            'self' => $paginator->url($paginator->currentPage()),
            'first' => $paginator->url(1),
            'prev' => $paginator->previousPageUrl(),
            'next' => $paginator->nextPageUrl(),
            'last' => $paginator->url($paginator->lastPage())
        ];

        //set meta object
        $out['meta'] = [
            'total' => $paginator->total(),
            'per_page' => $paginator->perPage(),
            'current_page' => $paginator->currentPage(),
            'last_page' => $paginator->lastPage(),
            'from' => 1,
            'to' => $paginator->lastPage()
        ];

        return array_merge($identifiers, $out);
    }
}

1 like
skeith22's avatar

I was actually looking for a solution to this right now. when using axios to handle this it's actually kinda wrong when you read the response

Here is an example as to why it would be nice to actually have support for renaming data key on pagination.

Let's say we have a component that would display a list of users.

<template>
    <div>
        <div v-for="user in data.data"> // This should be data.users
            {{ user.name }}
        <div>
    </div>
</template>

axios.get('/api/users', { params }).then(response => {
    this.data = response.data;
}).catch(error => {
    // Catch error
});

You might be saying why not just use this.users = response.data.data?

The reason is that when you have a really BIG frontend and you're using slots, components inside components and you're passing data a lot from parent to child or component to whatever component, it is disturbing and tedious to do when passing object variables that are dynamic that has 10 properties with 10 or more data inside every property AND you don't know what data you're passing. Because you're using data keyword instead of what that key name should really be.

Plus when you're reusing the components and all. IT IS CONFUSING to read. Especially for someone who is new to the project.

It would be nice if someone would actually recommend this to @TaylorOtwell, this will literally help a lot of devs who are facing this problem.

We could just have a code like this

$users = App\User::paginate(15)->renameKeys(['data' => 'users']);

{
   "total": 50,
   "per_page": 15,
   "current_page": 1,
   "last_page": 4,
   "first_page_url": "http://laravel.app?page=1",
   "last_page_url": "http://laravel.app?page=4",
   "next_page_url": "http://laravel.app?page=2",
   "prev_page_url": null,
   "path": "http://laravel.app",
   "from": 1,
   "to": 15,
   "users":[
        {
            // Result Object
        },
        {
            // Result Object
        }
   ]
}

This will find all the keys the match it and replace it with the value.

Then on your Vue code

<template>
    <div>
        // This is way better to read and to understand.
	<div v-for="user in data.users">
            {{ user.name }}
        <div>
    </div>
</template>

axios.get('/api/users', { params }).then(response => {
    this.data = response.data;
}).catch(error => {
    // Catch error
});
1 like
lasse's avatar

To future me and whoever else stumbles across this thread.

Laravel supports this now:

class ContractResource extends JsonResource
{
    public function __construct($resource)
    {
        static::wrap('contracts');
    }
}

Please or to participate in this conversation.