i'm developing an api with Laravel and DingoAPI which returns the message threads of the user with pagination.
$threads = Thread::forUser($currentUserId)->latest('updated_at')->simplePaginate(1);
return API::response()->array($threads);
and i get this kind of response :
{
"per_page": 1,
"current_page": 1,
"next_page_url": "http://my.app/api/messages?page=2",
"prev_page_url": null,
"from": 1,
"to": 1,
"data": [
{
"id": 1,
"subject": null,
"created_at": "2016-03-18 12:33:38",
"updated_at": "2016-03-18 12:33:38",
"deleted_at": null
}
]
}
What can i do to remove some field of the response ? i just need data and next_page_url …
i tried this way :
$array_response = [
'next_page_url' => $threads['next_page_url'],
'data' => $threads['data']
];
but only null values are returned.
I guess Dingo Api is doing some work behind the scene…
Try this
$threads = Thread::forUser($currentUserId)->latest('updated_at')->simplePaginate(1);
$arrayResponse = json_decode(API::response()->array($threads));
$arrayResponseEdited = [
'next_page_url' => $arrayResponse['next_page_url'],
'data' => $arrayResponse['data']
];
return arrayResponseEdited;
Related
In laravel I'm getting products array that looks like this
dd($activity->load('products'));
"products": [
{
"id": 1,
"pivot": {
"activity_id": 1,
"product_id": 10,
"quantity": 16
}
},
{
"id": 2,
"pivot": {
"activity_id": 1,
"product_id": 11,
"quantity": 20
}
}
]
I want to get an array of objects and pluck only the pivot.product_id and pivot.quantity from the products array
Expected result:
"selected_products": [
{
"id": 10,
"quantity": 16
},
{
"id": 11,
"quantity": 20
}
]
What I tried
return $activity
->load('products')
->products()
->get()
->mapWithKeys(function ($product, $key) {
return ['id' => $product->pivot->product_id, 'quantity' => $product->pivot->quantity];
});
Result
{
"id": 10,
"quantity": 16
}
There are 2 problems on your code.
First, load('products') is redundant. You cam simple call $activity->products. Or if you need filter on the products , use $activity->products()->where(...)->get()
Second, you should use map for indexed array. mapWithKeys is using for associative array.
return $activity->products
->map(function ($product, $key) {
return ['id' => $product->pivot->product_id, 'quantity' => $product->pivot->quantity];
});
I am trying to update a column in a Collection but nothing seems to work.
Tried update and $kk->amount = 100 and ['amount'] = 100 but none of that is working.
$newReturnBoxes = collect([
{
"boxable_id": 2,
"box_id": 1,
"boxable_type": "return",
"amount": 3,
"created_at": "2022-03-29T08:29:03.000000Z",
"updated_at": "2022-03-29T08:29:03.000000Z"
},
{
"boxable_id": 3,
"box_id": 1,
"boxable_type": "return",
"amount": 4,
"created_at": "2022-03-29T08:32:02.000000Z",
"updated_at": "2022-03-29T08:32:02.000000Z"
},
{
"boxable_id": 3,
"box_id": 2,
"boxable_type": "return",
"amount": 2,
"created_at": null,
"updated_at": null
}
]);
$returnBoxes->each(function ($trx) use ($newReturnBoxes) {
$amount = $trx->amount;
$boxId = $trx->box_id;
if ($newReturnBoxes->contains('box_id', $boxId)) {
// Already contains key, increment amount
$kk = $newReturnBoxes->firstWhere('box_id', $boxId);
$kk['amount'] = 100; // actually want to increase prev amount with current amount
} else {
$newReturnBoxes->push([
'box_id' => $boxId,
'amount' => $amount
]);
}
});
Maybe the problem is that you are not passing the $newReturnBoxes by reference.
Try to replace this:
use ($newReturnBoxes)
With this:
use (&$newReturnBoxes)
Reference: https://www.php.net/manual/en/language.references.pass.php
i have a problem for the response, i want to change the response API because i need for my mobile APP, the feature have filter object based on date. So i hope you all can help me to solve the problem
i wanna change the response for my API
before:
{
"tasks": [
{
"id": 7,
"user_id": 1,
"title": "gh",
"date": "2022-02-10 13:05:00",
"deskripsi": "gfh",
"created_at": "2022-02-09T06:05:56.000000Z",
"updated_at": "2022-02-09T06:05:56.000000Z"
},
{
"id": 5,
"user_id": 1,
"title": "ghf",
"date": "2022-02-17 16:05:00",
"deskripsi": "fghf",
"created_at": "2022-02-09T06:05:12.000000Z",
"updated_at": "2022-02-09T06:05:12.000000Z"
},
{
"id": 6,
"user_id": 1,
"title": "fgh",
"date": "2022-02-17 18:05:00",
"deskripsi": "gh",
"created_at": "2022-02-09T06:05:40.000000Z",
"updated_at": "2022-02-09T06:05:40.000000Z"
}
]
}
here is the code for the response API above
return response([
'tasks' => Task::where('user_id', auth()->user()->id)->where('date','>',NOW())->orderBy('date','asc')->get(),
],200);
and i want to change it my response API into this response
{
"tasks": [
{
"date": "2022-02-10",
"task": [
{
"id": 7,
"user_id": 1,
"title": "gh",
"date": "2022-02-10 13:05:00",
"deskripsi": "gfh",
"created_at": "2022-02-09T06:05:56.000000Z",
"updated_at": "2022-02-09T06:05:56.000000Z"
},
{
"id": 7,
"user_id": 1,
"title": "gh",
"date": "2022-02-10 15:05:00",
"deskripsi": "gfh",
"created_at": "2022-02-09T06:05:56.000000Z",
"updated_at": "2022-02-09T06:05:56.000000Z"
}
]
},
{
"date": "2022-02-12",
"task": [
{
"id": 7,
"user_id": 1,
"title": "gh",
"date": "2022-02-12 13:05:00",
"deskripsi": "gfh",
"created_at": "2022-02-09T06:05:56.000000Z",
"updated_at": "2022-02-09T06:05:56.000000Z"
}
]
},
]
}
Do groupBy on the resulting Collection from the query (see docs: https://laravel.com/docs/9.x/collections#method-groupby)
For example, you could do:
$tasksGroupedByDate = Task::where(.......)
->get()
->groupBy(fn (Task $task) => $task->date->format('Y-m-d'));
(Note: above uses PHP 7.4 arrow functions. Also, add a date cast on the date column in your Task model to be able to use ->format( directly on the date field)
The above code results to:
{
'2022-01-01' => [
{ Task object },
{ Task object },
{ Task object },
],
'2022-01-02' => [
{ Task object },
{ Task object },
{ Task object },
],
}
(used Task object for brevity, but that will be ['id' => 1, 'title' => 'Task name', .....])
To morph that to the structure you want, you can use map and then values to remove the keys and turn it back to an ordered array:
$tasksGroupedByDate->map(fn ($tasksInGroup, $date) => [
'date' => $date,
'task' => $tasksInGroup
])->values();
If you want to combine everything into one method chain:
return [
'tasks' => Task::where(......)
->get()
->groupBy(fn (Task $task) => $task->date->format('Y-m-d'))
->map(fn ($tasksInGroup, $date) => [
'date' => $date,
'task' => $tasksInGroup
])
->values(),
];
It sounds like you want to create a human friendly date field based on the date column, then group by it.
While solutions do exists to accomplish this at the database level, I believe you'd still need to loop around it again afterwards to get the hierarchy structure you're looking for. I don't think it's too complicated for PHP to loop through it.
My suggestion is as follows:
Before:
return response([
'tasks' => Task::where('user_id', auth()->user()->id)
->where('date','>',NOW())->orderBy('date','asc')->get(),
],200);
After:
$out = [];
$tasks = Task::where('user_id', auth()->user()->id)
->where('date','>',NOW())->orderBy('date','asc')->get();
foreach($tasks as $task) {
$date = strtok((string)$task->date, ' ');
if (empty($out[$date])) {
$out[$date] = (object)['date' => $date, 'task' => []];
}
$out[$date]->task[] = $task;
}
$out = array_values($out);
return response(['tasks' => $out], 200);
Note in the above I'm using the function strtok. This function might look new even to the most senior of php developers.... It's a lot like explode, except it can be used to grab only the first part before the token you're splitting on. While I could have used explode, since the latter part after the token isn't needed, strtok is better suited for the job here.
$task = Task::where('user_id', auth()->user()->id)->where('date','>',NOW())->orderBy('date','asc')->get();
foreach($task as $item){
$date[] = item->date;
$result = Task::where('user_id', auth()->user()->id)->where('date','=', $date)->get();
}
return response([
'tasks' =>
['date' => $date,
'task' => $task]
],200);
maybe something like this
I'm stuck and probably missing something really obvious.. but..
I'm trying to pass an array of roles via jwt to my SPA (not a jwt question - that bit works fine)
I get my list of role names via
$roles = $this->roles->pluck('title')->toArray();
the roles function is
public function roles()
{
return $this->belongsToMany(Role::class);
}
in laravel this works fine and logging $roles out I see ["Admin"]
on the SPA response, however, I see the entire roles object joined to the user object (the user object is supposed to be passed over here) eg:
{
"user": {
"id": 1,
"name": "Admin",
"email": "example#example.com",
"email_verified_at": null,
"user_loggedin_state": null,
"user_login_time": null,
"user_login_hash": "",
"user_log_out_time": null,
"user_phone": "123456",
"user_job": null,
"created_at": null,
"updated_at": null,
"deleted_at": null,
"team_id": 1,
"roles": [
{
"id": 1,
"title": "Admin",
"created_at": null,
"updated_at": null,
"deleted_at": null,
"pivot": {
"user_id": 1,
"role_id": 1
}
}
]
}
}
What I want is
{
"user": {
"id": 1,
"name": "Admin",
"email": "example#example.com",
"email_verified_at": null,
"user_loggedin_state": null,
"user_login_time": null,
"user_login_hash": "",
"user_log_out_time": null,
"user_phone": "123456",
"user_job": null,
"created_at": null,
"updated_at": null,
"deleted_at": null,
"team_id": 1,
"roles": ["Admin"]
}
}
I definitely pass the array to jwt, not the object - to validate this I wrapped the $roles in a function
public function rolesArray()
{
$roles = $this->roles->pluck('title')->toArray();
Log::info($roles);
return $roles;
}
and the jwt fn
public function getJWTCustomClaims() {
return [
'roles' => $this->rolesArray(),
];
}
Use API Resources for getting your own outputs.
Run this command to make a new resource for getting users:
php artisan make:resource UserListResource
In App/Http/Resourcers open UserListResource.php file
Change toArray method to:
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'email_verified_at' => $this->email_verified_at,
'user_loggedin_state' => $this->user_loggedin_state,
'user_login_time' => $this->user_login_time,
'user_login_hash' => $this->user_login_hash,
'user_log_out_time' => $this->user_log_out_time,
'user_phone' => $this->user_phone,
'user_job' => $this->user_job,
'create_dates' => [
'created_at_human' => $this->created_at->diffForHumans(),
'created_at' => $this->created_at
],
'update_dates' => [
'updated_at_human' => $this->updated_at->diffForHumans(),
'updated_at' => $this->updated_at
],
'deleted_dates' => [
'deleted_at_human' => $this->deleted_at->diffForHumans(),
'deleted_at' => $this->deleted_at
],
'team_id' => $this->team_id
'roles' => new RolesShowResource($this->roles),
];
}
Then make Roles resources:
php artisan make:resource RolesShowResource
Open the RolesShowResource.php and do these changes:
public function toArray($request)
{
return [
'title' => $this->title,
];
}
So when you want to return objects try using the code below in fetching users:
return UserListResource::collection($users);
ok the bleeding obvious was that all this data is of course in the JWT payload..
I was confused since the moment I added stuff in the custom fields - Laravel sent the User object across in the response as well (which I want to find a way of stopping since its in the clear)
I need to send multiple object to the api resources. So I am returning multiple Object inside array.Everything works fine but not showing any pagination meta data. like Current_page,next_page url etc.
return [
'across_city' => ServiceProviderCollection::collection($across_city),
'near_by' => ServiceProviderCollection::collection($near_by)
];
My resource
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class ServiceProviderCollection extends Resource
{
public function toArray($request)
{
return
[
'name'=>$this->forename,
'rating'=>$this->rating,
'price'=>$this->price,
'distance'=>round($this->distances,1),
];
}
}
My Controller:
here I have two type of users . near_by users and Users across the city. I sent them to the ServiceProviderCollection As an array.
$user_city = $userObj->location->city;
$locationObj = Location::whereNotIn('id', $blockeduser)->where('city',$user_city)->first();
$across_city = $locationObj->users()->simplePaginate(20);
$near_by = User::join('locations as l', 'users.location_id', '=', 'l.id')
->select('users.*', DB::raw('(6371 * acos(cos(radians(' . $coordinates['latitude'] . ')) * cos(radians(`lat`)) * cos(radians(`lng`) - radians(' . $coordinates['longitude'] . ')) + sin(radians(' . $coordinates['latitude'] . ')) * sin(radians(`lat`)))) as distances'))
->having('distances', '<', $max_distance)
->orderBy('distances', 'ASC')
->where('role_id',2)
->whereNotIn('id', $blockeduser)
->simplePaginate(20);
return [
'across_city' => ServiceProviderCollection::collection($across_city),
'near_by' => ServiceProviderCollection::collection($near_by)
];
I want Json Data with pagination.
{"data":{
"across_city": [
{
"name": "??",
"rating": 0,
"price": 0,
"distance": 0,
}
],
"links": {
"first": "",
"last": "",
"prev": null,
"next": ""
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 3,
"path": "",
"per_page": 2,
"to": 2,
"total": 6
},
{
"near_by": [
{
"name": "??",
"rating": 0,
"price": 0,
"distance": 0,
}
],
"links": {
"first": "",
"last": "",
"prev": null,
"next": ""
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 3,
"path": "",
"per_page": 2,
"to": 2,
"total": 6
}
}
I have no idea, what the purpose of ServiceProviderCollection is. If it creates a regular collection then there is a better way to do so.
To be able to paginate a simple collection you need to add this helper function to your base:
function paginateCollection($items, $perPage = 15, $page = null, $options = [])
{
$page = $page ?: (\Illuminate\Pagination\Paginator::resolveCurrentPage() ?: 1);
$items = $items instanceof \Illuminate\Support\Collection ? $items : \Illuminate\Support\Collection::make($items);
return new \Illuminate\Pagination\LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);
}
With this function in place you can make
return [
'across_city' => paginateCollection(collect($across_city), 20),
'near_by' => paginateCollection(collect($near_by), 20)
];
Edit
Do you have generated the corresponding resource collections?
Like so: php artisan make:resource Cities --collection
If so, you can return a paginated resource collection