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.
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
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.
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;
That is good.
I can put that code in a transformation class anyway :)
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.
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
@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.
How does that fit with a paginator? I assume you are transforming those keys also?
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);
}
}
This will be help to you.
https://gist.github.com/vijaybajrot/1540a0bc1959a04f811e24cb04e72063
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
});
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.