I have the following tables:
users
- id
- username
kids
- id
- user_id
groups
- id
group_user
- id
- group_id
- user_id
sits
- id
- user_id
They of course have addl fields, but it's just extraneous info.
My User model contains:
public function kids()
{
return $this->hasMany('Kid');
}
public function sits()
{
return $this->hasMany('Sit');
}
public function groups()
{
return $this->belongsToMany('Group')->withPivot('status');
}
My UserController#show method looks like this:
public function show($user)
{
$user = User::find($user)->load('kids', 'groups', 'sits');
return $user;
}
So, when I hit /user/show/1 I get the JSON I expect.
{
"id": "1",
"username": "somename",
"email": "somename#example.com",
"kids": [
{
"id": "4",
"user_id": "1"
},
{
"id": "3",
"user_id": "1"
},
{
"id": "1",
"user_id": "1"
}
],
"groups": [
{
"id": "1",
"name": "Group Name",
"pivot": {
"user_id": "1",
"group_id": "1"
}
}
],
"sits": [
{
"id": "2",
"user_id": "1",
"start": "2014-01-16 00:00:31",
"end": "2014-01-16 00:00:31",
"sitter_id": "2"
}
]
}
But my question is what is the "Laravel Way" to add another object to this response that is filtered? Let's say I wanted to return sits but also upcomingSits where it was filtered by a certain "start" date or where "sitter_id"=0.
Where is the proper MVC approach for that sort of logic and how would I use Laravel to return it in this response?
You can do something like this:
$user = User::with('kids', 'groups', 'sits')->find($user_id)->toArray();
$sits = Sit::where(.....)->get()->toArray();
return Response::json(array(
'user' => $user,
'sits' => $sits
));
Related
I have a comments table, with theses fields: id, body, and parent_id. comments can have subcomments, that's why it is using the parent_id field, I would like to know how I can achieve this nested result:
[
{
"id": 1,
"body": "test",
"parent_id": null,
"comments": [
{
"id": 2,
"body": "test",
"parent_id": 1,
"comments": [
{
"id": 3,
"body": "test",
"parent_id": 2
},
{
"id": 4,
"body": "test",
"parent_id": 2
}
]
},
{
"id": 5,
"body": "test",
"parent_id": 1,
"comments": []
}
]
},
{
"id": 6,
"body": "test",
"parent_id": null,
"comments": []
}
]
Without using eloquent eager loading(with()), just using the query builder, thank you.
Since the possible answer could be too long, I am posting it directly as an answer. You could achieve this by creating a recursive method in your controller like below:
public function commentsLoop($comments, $parent = null)
{
$result = [];
foreach ($comments as $comment) {
if ($comment['parent_id'] === $parent) {
$subComment = commentsLoop($comments, $comment['id']);
if ($subComment) {
$comment['comments'] = $subComment;
}
$result[] = $comment;
}
}
return $result;
}
And then, you can call it from your main method in your controller like below:
public function comments()
{
$comments = DB::table('comments')->all()->toArray();
return $this->commentsLoop($comments);
}
However, if you would use eloquent instead, creating a relationship to self in your model would be the answer.
Relation method
User model:
public function children()
{
return $this->hasMany(self::class, 'referrer_id')->with('children');
}
Controller Method:
$user = User::with('children')->where('id',$this->request->UserId)->get();
Response
{
"status": true,
"status_code": "Success",
"message": true,
"payload": {
"profile": [
{
"id": 1,
"referrer_id": null,
"name": "beciwerugy",
"username": "lahaky",
"email": "figo#mailinator.com",
"children": [
{
"id": 3,
"referrer_id": 1,
"name": "asd",
"username": "asde",
"email": "asda#asd.com",
"children": [
{
"id": 4,
"referrer_id": 3,
"name": "asd",
"username": "asde12",
"email": "as12a#asd.com",
]
}
]
}
]
}
]
}
]
}
}
I want to count all nestedchild at once
Currently im getting all nested child in ther list
but i just want count
So, in my application I have models: user, category, service(i.e subcategory) and userService.
There exists many to many relationship between user and category, user and service. And one to many between category and service.
// Tables
Users : id, name, email, password
Categories : id, name
Services : id, name, category_id
user_services: id, user_id, category_id, service_id
Relationship is defined in model as:
// User Model
public function services()
{
return $this->belongsToMany('App\Models\V1\Service', 'user_services', 'user_id', 'service_id');
}
public function categories()
{
return $this->belongsToMany('App\Models\V1\Category', 'user_services', 'user_id', 'category_id');
}
// category model
public function services()
{
return $this->hasMany(Service::class);
}
After populating my db with some random data, the user_services table look like this:
// user_services table
id user_id category_id service_id
1 1 1 1
2 1 1 2
3 2 1 1
so far code is good but when i want particular user with services and categories, i am not able to get it as i expected.
The eloquent method that used to fetch user with services and categories:
public function userWithCategoryServices(Request $request)
{
return User::where('id', $request->id)->with(categories.services)->get();
}
The problem with this is:
As there is case one user with one category can have multiple services, so this eloquent method will return same category multiple times. But i want all services belonging to one category grouped in single category key for that particular user.
Another problem, instead of fetching services of that particular user only,but it will fetch all services from db for users particular category.
[
{
"id": 1,
"name": "Ashish Bogati",
"email": "abbaasdaashisdh23#gmail.com",
"categories": [
{
"id": 1,
"name": "IT",
"pivot": {
"user_id": 1,
"category_id": 1
},
"services": [
{
"id": 1,
"name": "Web Developer",
"category_id": 1,
},
{
"id": 2,
"name": "Web Design",
"category_id": 1
},
{
"id": 3,
"name": "Database Design",
"category_id": 1
}
]
},
{
"id": 1,
"name": "IT",
"pivot": {
"user_id": 1,
"category_id": 1
},
"services": {
"id": 1,
"name": "Web Developer",
"category_id": 1
},
{
"id": 2,
"name": "Web Design",
"category_id": 1
},
{
"id": 3,
"name": "Database Design",
"category_id": 1
}
]
}
]
}
]
As in this response, category name IT is repeated twice for user and all services are fetched for that category instead of for particular user only.
Response i wanted:
[
{
"id": 1,
"name": "Ashish Bogati",
"email": "abbaasdaashisdh23#gmail.com",
"categories": [
{
"id": 1,
"name": "IT",
"pivot": {
"user_id": 1,
"category_id": 1
},
"services": [
{
"id": 1,
"name": "Web Developer",
"category_id": 1,
},
{
"id": 2,
"name": "Web Design",
"category_id": 1
},
]
}
]
the database design is a little strange.we meet duplicate category_id in user_services.but that's is not the problem
//in service model
public function category()
{
return $this->hasOne(Category::class);
}
public function userWithCategoryServices(Request $request)
{
$services = User::where('id', $request->id)->with("services.category")->get();
$servicesGrouped = $services['services']->groupBy('category_id');
}
the services will be right.there will be no more unwanted data.
this is so far we can do by Laravel eloquent.
because the relation map is user->services->category.not user->categories->services
use php to build the structure of the wanted response.
But as Restful principle.you should make api pure.which means one api give only one type of entity.client will be more clear with the rest api and deal with complex structure themself.
public function userWithCategoryServices(Request $request)
{
$services = User::where('id', $request->id)->with("services.category")->get()->toArray();
$categories = []
for($services as $service){
if(!isset($categories[$service['category_id']])){
$categories[$service['category_id']] = $service['category'];
$categories[$service['category_id']]['services'] = [];
}
unset($service['category']);
$categories[$service['category_id']]['services'][] = $service;
}
$categories = array_values($categories);
unset($services['services']);
$services['categories'] = $categories;
return $services;
}
I have tables, users, profiles, contacts. 1 user has 1 profile, 1 profile has many contacts, I want to get profile with filtered contact and selected column (I don't want get all column). I success with coding below
UserController.php
$profile = $user->with(['profile.emails', 'profile.phones'])->first();
User.php
public function profile()
{
return $this->hasOne(Profile::class);
}
Profile.php
public function emails()
{
return $this->hasMany(Contact::class)
->where('type', 'email');
}
public function phones()
{
return $this->hasMany(Contact::class)
->where('type', 'phone');
}
result data like this
{
"username": "user",
"email": "user#mail.com",
"profile": {
"first_name": "Alex",
"last_name": "Ariana",
"emails": [
{
"id": 1,
"profile_id": 1,
"type": "email",
"prefix": "Personal",
"value": "alex#mail.com",
"is_primary": 0,
},
{
"id": 2,
"profile_id": 1,
"type": "email",
"prefix": "Business",
"value": "business#mail.com",
"is_primary": 1,
}
],
"phones": [
{
"id": 3,
"profile_id": 1,
"type": "phone",
"prefix": "45",
"value": "564637345345",
"is_primary": 1,
}
]
}
}
but then I add select on the relation like this
public function emails()
{
return $this->hasMany(Contact::class)
->select([DB::raw('IFNULL(prefix, "Email") AS type'), 'value AS url', 'is_primary'])
->where('type', 'email');
}
public function phones()
{
return $this->hasMany(Contact::class)
->select(['prefix', 'value AS number', 'is_primary'])
->where('type', 'phone');
}
then I got empty contact data like this
{
"id": 1,
"username": "user",
"email": "user#mail.com",
"profile": {
"first_name": "Alex",
"last_name": "Ariana",
"emails": [ ],
"phones": [ ]
}
}
Why this is happen?, if I access from user via hasManyThrough it works, but when I use hasMany, it result empty.
i'm new in laravel and php and now i wanna create a rest api
I have this query:
$questions = Question::with(
array('picture' => function($query){
$query>select('question_id','picture_name')>pluck('picture_name')>all();
},
'user'=>function($query){
$query->select('id','image','name');
}))->get()->toArray();
my query return this json:
{
"questions:": [
{
"id": 1,
"title": "23",
"caption": "last",
"address": "lsdbabfd",
"picture": [
{
"question_id": 1,
"picture_name": "1527484678.jpg"
},
{
"question_id": 1,
"picture_name": "1527485120.jpg"
}
],
"user": {
"id": 1,
"image": "defaultPicture",
"name": "alex"
}
}
]
}
but i want this json:
{
"questions:": [
{
"id": 1,
"title": "23",
"caption": "last",
"address": "lsdbabfd",
"picture": [
"1527484678.jpg",
"1527485120.jpg"
],
"user": {
"id": 1,
"image": "defaultPicture",
"name": "alex"
}
}
]
}
how can i do that?
i already tried to do that with Laravel pluck method and Eloquent Mutators
you can add attribute method
class Question extends Model
{
...
protected $appends = ['pictures'];
public function getPicturesAttribute()
{
return $this->pictures->pluck('picture_id');
}
}