I have the following collections:
User
{
"id": 1,
"name": "Bob"
},
{
"id": 2,
"name": "Mary"
}
Stuff
{
"id": 1,
"user_id": 1,
"name": "Bob's stuff"
},
{
"id": 2,
"user_id": 2,
"name": "Mary's stuff"
},
{
"id": 3,
"user_id": 0,
"name": "Everyone's stuff"
},
{
"id": 4,
"user_id": null,
"name": "Global stuff"
}
... and the following models:
class User extends Eloquent {
public function stuff() {
return $this -> hasMany( 'Stuff' ) ;
}
}
class Stuff extends Eloquent {
public function user() {
return $this -> belongsTo( 'User' ) ;
}
}
How to I automatically add Everyone's stuff ( User.id == 0 ) and Global stuff ( User.id == null ) to everybody's model? In other words, if I was querying for Bob's stuff I wish to get the following:
{
"id": 1,
"user_id": 1,
"name": "Bob's stuff"
},
{
"id": 3,
"user_id": 0,
"name": "Everyone's stuff"
},
{
"id": 4,
"user_id": null,
"name": "Global stuff"
}
You can use this:
public function stuff() {
return $this->hasMany(Stuff::class)->orWhere('user_id', 0)->orWhereNull('user_id');
}
A disadvantage is that you can't just add other WHERE clauses:
$user->stuff()->where('foo', 'bar')->get(); // Doesn't work as expected.
As a consequence, eager loading doesn't work.
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.
I have a many to many relation with table users,items and the pivot table user_item and i need to call the query : Select * from user_item where user_id=$user->id in laravel and return the results in json format. I try with
$user=User::find(session('user_id'))->items()->get();
return response ()->json($user);
But it doesn't work. How can I do that?
class User extends Authenticatable {
public function items (){
return $this->belongsToMany ("App\Models\Item", "user_item", "user", "item");
}
}
class Item extends Models {
public function users (){
return $this->belongsToMany ("App\Models\User", "user_item", "item", "user");
}
}
You can define columns in your pivote table using withpivot method
public function items (){
return $this->belongsToMany ("App\Models\Item", "user_item",
"user", "item")->withPivot(['column1', 'column2','another_column']);
}
to get relation instead of using get(), you should use like below:
$user=User::find(session('user_id'))->items;
return response ()->json($user);
above will give below json result:
[{
"id": 4,
"name": "PC",
"pivot": {
"column1": 1,
"column2": 4,
"another_column": "2016-03-03"
}
},
{
"id": 5,
"name": "Phone",
"pivot": {
"column1": 1,
"column2": 4,
"another_column": "2016-03-03"
}
}]
you can also include pivot in use user model using with():
$user=User::with('items')->find(session('user_id'));
return response ()->json($user);
give json result something like:
{
"id": 1,
"name": "User Name",
"email": "email#user.com",
"created_at": null,
"updated_at": null,
"items": [{
"id": 4,
"name": "PC",
"pivot": {
"column1": 1,
"column2": 4,
"another_column": "2016-03-03"
}
},
{
"id": 5,
"name": "Phone",
"pivot": {
"column1": 1,
"column2": 4,
"another_column": "2016-03-03"
}
}]
}]
I have attempted to achieve to pull the user's info and the product details (Which specified the nickname and name) when the product name equal to "Oops" but I have no idea why the getProducts does not return any things.
User Model
public function getProducts(){
return $this->hasMany('App\Models\Product','users_id');
}
Product Model
public function users(){
return $this->belongsTo(User::class);
}
The code of pulling data:
$products = User::with(['getProducts' => function($query){
$query->select("users_id","name","nickname");
}])->get();
The current output:
"data": [
{
"id": 1,
"name": "John Smith",
"email": "john.smith#hotmail.com",
"email_verified_at": null,
"created_at": "2021-04-08T13:29:13.000000Z",
"updated_at": "2021-04-08T13:29:13.000000Z",
"role": 0,
"get_products": [
]
},
{
"id": 2,
"name": "Kelvin Ooi",
"email": "kelvin.ooi#hotmail.com",
"email_verified_at": null,
"created_at": "2021-04-08T13:29:13.000000Z",
"updated_at": "2021-04-13T12:07:11.000000Z",
"role": 1,
"get_products": [
{
"nickname":"MCD",
"name":"Oops"
},
{
"nickname":"Mary Brown",
"name":"Oops"
},
{
"nickname":"Kentucy",
"name":"KFC"
},
{
"nickname":"Texas Chicken",
"name":"TXS"
}
]
}
]
The expected output
"data": [
{
"id": 1,
"name": "John Smith",
"email": "john.smith#hotmail.com",
"email_verified_at": null,
"created_at": "2021-04-08T13:29:13.000000Z",
"updated_at": "2021-04-08T13:29:13.000000Z",
"role": 0,
"get_products": [
]
},
{
"id": 2,
"name": "Kelvin Ooi",
"email": "kelvin.ooi#hotmail.com",
"email_verified_at": null,
"created_at": "2021-04-08T13:29:13.000000Z",
"updated_at": "2021-04-13T12:07:11.000000Z",
"role": 1,
"get_products": [
{
"nickname":"MCD",
"name":"Oops"
},
{
"nickname":"Mary Brown",
"name":"Oops"
}
]
}
]
getProducts is not a good name for the relationship, lets simply call it products.
public function products()
{
return $this->hasMany('App\Models\Product','users_id');
}
Your code in the comment doesn't work because you specify the where clause in the main query, not the sub query.
return User::with(['products' => function ($query) {
$query->select("users_id","name","nickname");
}])
// This got to be in the sub query.
->where("products.name","Oops")
->get();
So let's update your code to this:
$productName = 'Oops';
return User::with(['products' => function ($query) use ($productName) {
$query->select("users_id","name","nickname", "price")
->where("name","LIKE", "%{$productName}%");
}])
->get();
I have seen your comment to this answer. Let's define a total custom attribute for the User model:
class User extends Model
{
protected $appends = ['total'];
public function getTotalAttribute()
{
// This is higher order message, if you haven't used it: https://laravel.com/docs/8.x/collections#higher-order-messages
return $this->products->sum->price;
}
}
Then the total attribute will be part of any user.
I have categories with id, parent_id, slug , pivot table category_language which columns are id,category_id,language_id,value
As you can see I can translate parent category, but can't send desired $lang_id to children translations, so each children having all translations
here is what I get:
{
"id": 1,
"parent_id": 0,
"slug": "personal-computers",
"created_at": "2019-12-27 15:05:31",
"updated_at": "2019-12-27 15:05:31",
"children": [
{
"id": 3,
"parent_id": 1,
"slug": "accessories-for-pc",
"created_at": "2019-12-27 15:05:32",
"updated_at": "2019-12-27 15:05:32",
"translations": [
{
"id": 1,
"code": "en",
"name": "English",
"pivot": {
"category_id": 3,
"language_id": 1,
"value": "Acc for PC",
"id": 7
}
},
{
"id": 2,
"code": "ru",
"name": "Русский",
"pivot": {
"category_id": 3,
"language_id": 2,
"value": "Аксессуары для ноутбуков и ПК",
"id": 8
}
},
{
"id": 3,
"code": "ro",
"name": "Romana",
"pivot": {
"category_id": 3,
"language_id": 3,
"value": "aksessuari-dlya-noutbukov-i-pk-ro",
"id": 9
}
}
]
}
],
"translations": [
{
"id": 1,
"code": "en",
"name": "English",
"pivot": {
"category_id": 1,
"language_id": 1,
"value": "PC",
"id": 1
}
}
]
}
Controller:
return Category::with('children')
->with(array('translations'=>function($query) use ($lang_id){
$query->where('language_id',$lang_id);
}))
->where('parent_id',0)->first();
Model
class Category extends Model
{ ..
public function translations()
{
return $this->belongsToMany('App\Models\Translation','category_language', 'category_id' ,'language_id' )->withPivot('value','id');
}
public function children()
{
return $this->hasMany( 'App\Models\Category' , 'parent_id' , 'id' )->with('translations');
}
}
you can add condition in children method
public function children()
{
return $this->hasMany( 'App\Models\Category' , 'parent_id' , 'id' )->with('translations')->where('language_id', 1);
}
Dry7 answer was close to the one I've implemented later, so I upvoted him.
Finally in model I've added: ...->where('language_id',helper_SetCorrectLangIdForQuery());
and function helper_SetCorrectLangIdForQuery is using global helper of Laravel request()->lang . If lang=enz, than it takes default language from another helper.
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');
}
}