with() relation with condition retrieve all the records- Laravel - laravel-5

I want to retrieve only the listed organisations but the the database return all the records.
you can see below a record should not be returned as a listed organisation I include below the code and my Model and The result I got from the database
$organisations = Organisation::with(['year_status' => function ($query) use ($year_id) {
$query->where(['year_id' => $year_id, 'is_listed' => 1]);
}])->get();
public function year_status()
{
return $this->hasMany('App\OrganisationYearStatus');
}
and what I got :
11 => Organisation {#630 ▼
#fillable: array:8 [▶]
#connection: "mysql"
#table: null
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:14 [▼
"id" => 39
"organisation" => "Test Organisation"
"sector_id" => 1
"country_id" => 1
]
#original: array:14 [▶]
#changes: []
#casts: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: array:1 [▼
"year_status" => Collection {#632 ▼
#items: []
}
]
#touches: []
+timestamps: true
#hidden: []
#visible: []
#guarded: array:1 [▶]
}
database structure :
id
organisation_id
year_id
is_listed

Make sure your relationship is well established (Organization model hasMany year_status) and that your fields are in the visible array in the YearStatus Model.
Also, the query you're using is translated to:
SELECT * FROM organizations where exists
(select * from year_status where organizaton_id = organizations.id
and year_id = $year_id and is_listed = 1)
It doesn't fetch ALL the records existing in the database, it fetches due to the relationship + the fields you've added
Note: If you want to fetch only the organization that have OrganizationYearStatus, then you should use:
Organisation::whenHas('year_status' => function ($advancedWhenHas) use ($year_id) {
$advancedWhenHas->with(['year_status' => function ($query) use ($year_id) {
$query->where(['year_id' => $year_id, 'is_listed' => 1]);
}}])->get();
You can type out ->toSql() instead of ->get() to make sure your query is the one you expect it to be

Related

Laravel change collection attributes name

How would you change the attributes from a collection?
So the return is a Collection of Models with changed attributes, and not a Collection of arrays.
The things is, I would like to make some kinda of translation presenter, so when I get the collection I could dd($collection) and instead of 'name' it would show 'nome', also using response()->json($collection) would show the changed named.
so something like $presenterNames = ['name' => 'nome', 'id' => 'identificador']; and the names that aren't here would call normally.
Collection {#213 ▼
#items: array:2 [▼
0 => Category {#215 ▼
+timestamps: false
#fillable: array:2 [▶]
#connection: "mysql"
#table: "categories"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:3 [▼
"id" => 1
"name" => "categoria1"
"slug" => "categoria1"
]
#original: array:3 [▶]
#changes: []
#casts: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
#hidden: []
#visible: []
#guarded: array:1 [▶]
#slugOptions: null
}
1 => Category {#219 ▶}
]
}
so basically I would like to change
#attributes: array:3 [▼
"id" => 1
"name" => "categoria1"
"slug" => "categoria1"
]
to this
#attributes: array:3 [▼
"identificador" => 1
"nome" => "categoria1"
"slug" => "categoria1"
]
Dinamicaly by using a assoc array.
Solution :
In your Model add below code.
protected $appends = ['nome'];
public function getNomeAttribute(){
return $this->attributes['name'];
}
You can access it by querying $modelObj->nome;
Do the same for all needed attributes.
This will also reflect in your JSON response.
Thanks
Reference : https://laravel.com/docs/5.7/eloquent-mutators#defining-an-accessor

How to get only relations from eloquent query

I got the following code:
$popularProducts = PopularProduct::with('product')->get();
This is how I get all of products from popular_products (contains only product_id) table with relations for products table. But I have this result:
Collection {#409 ▼
#items: array:1 [▼
0 => PopularProduct {#411 ▼
#connection: "mysql"
#table: null
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:4 [▶]
#original: array:4 [▶]
#changes: []
#casts: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: array:1 [▼
"product" => Product {#462 ▶}
]
#touches: []
+timestamps: true
#hidden: []
#visible: []
#fillable: []
#guarded: array:1 [▶]
}
]
}
I need to take only relations->product field. How can I take it?
You can do it like this
$products = PopularProduct::with('product')->get()->pluck('product');
if you like the result to be keyed you can do it like this
$products = PopularProduct::with('product')->get()->pluck('product','id');
// you can key it with **id** of the table (popularProduct) or by **id_product** of relationship (product)
if you like only to retrieve specific fields from relation you can try something like this
$products = PopularProduct::with('product:id,product_name')->get()->pluck('product','id');
You can use whereHas method (if there is a relationship between these tables)
$popular_products = Product::whereHas('products', function ($query) {
$query->where('popular_products',$ids);
})->get()
You need to iterate over the collection:
#foreach ($popularProducts as $popularProduct)
{{ $popularproduct->product->id }}
#endforeach
If you just want to get all products from the collection, use the pluck() method:
$products = $popularProducts->pluck('product');
Update
In the comments, you've said you want to get links directly from DB:
Product::has('popularProduct')->pluck('links');
This will work if you've defined the popularProduct relationship in the Product model.

Laravel : How to add a key value into an object?

How to add a key value into an object?
I want to add "tags" => ["foo","bar"] into every record,demo:
ArticlesController.php
public function index()
{
$articles = user()->articles;
dd($articles); //This is a collection
//loop the collection,and add `"tags" => ["foo","bar"]` into every record
$multiplied = $articles->map(function ($item, $key) {
dd($item);//result below
//how to write here?
});
$newArticles = $multiplied->all();
dd($newArticles);
return view('articles', compact('newArticles'));
}
result of dd($item):
Article {#498 ▼
#fillable: array:2 [▶]
#casts: array:1 [▶]
#connection: "mysql"
#table: null
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:6 [▼
"id" => 1
"title" => "hello"
"content" => "hello world"
"user_id" => 2
"created_at" => "2017-07-23 15:34:52"
"updated_at" => "2017-07-23 15:34:55"
]
#original: array:6 [▶]
#dates: []
#dateFormat: null
#appends: []
#events: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#hidden: []
#visible: []
#guarded: array:1 [▶]
}
question:
How to write the code in map()?
$item->tags = ['foo', 'bar'];
return $item;
inside map will do the job.
But do the map to $newArticles.
simple
$object->new_key="value";

Laravel map to return single value shows as object, not as string

Within my view, I am displaying a value but it's showing as an object: ["Jamie Rogers"]. I want to remove the [" ... "]part.
Function:
$auditor = $audit->map(function ($user) {
return $user->name;
});
Initial structure of Audit:
Collection {#432 ▼
#items: array:1 [▼
0 => Score {#410 ▼
#table: "scores"
#fillable: array:3 [▶]
#connection: null
#primaryKey: "id"
#keyType: "int"
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:9 [▶]
#original: array:9 [▼
"id" => 5
"score" => 0.11
"name" => "Jamie Rogers"
"created_at" => null
"updated_at" => "2017-03-19 17:47:23"
]
#relations: array:1 [▶]
#hidden: []
#visible: []
#appends: []
#guarded: array:1 [▶]
#dates: []
#dateFormat: null
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
+wasRecentlyCreated: false
}
]
}
If I cast the value, using return (string) $user->name, it doesn't change it.
To get the first (and only) object of the collection, use the pluck method, followed by the first method:
$auditor = $audit->pluck('name')->first();
A map function is available on collection when you map on a collection it means that you want to do something with the data & return the processed data e.g you have first name & last name now in your API you want to response as full name
$collection->map(function($value, $key) {//https://laravel.com/docs/5.4/collections#method-map
return [
'full_name' => $value->firstName . ' ' . $value->lastname
]
});
In map function you pass function will get two value first is value & second is the key.
so in your case you can also do it in this way also
$collection->map(function($value, $key) {
return [
'name' => $value->name
]
})->first();
But for less coding manniL's answer is more better then me.
In pluck you can get a key value like array_column but unlike pluck works on collections only. You can also tell pluck method to what will be the key for values if you pass a second parameter the key will be the value of that column. Also like to mention pluck also return a collection object. So you can use all the methods like first on that object.

Search value deeply nested within a Laravel Collection

I have an Eloquent Collection just like this (dumped):
Collection {#788 ▼
#items: array:3 [▼
0 => Rating {#787 ▼
#table: "ratings"
+timestamps: false
#connection: null
#primaryKey: "id"
#keyType: "int"
#perPage: 15
+incrementing: true
#attributes: array:3 [▼
"id" => 1
"rating" => "50"
"type" => "min"
]
#original: array:3 [▶]
#relations: []
#hidden: []
#visible: []
#appends: []
#fillable: []
#guarded: array:1 [▶]
#dates: []
#dateFormat: null
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
+wasRecentlyCreated: false
}
1 => Rating {#786 ▶}
2 => Rating {#785 ▶}
]
}
In one of my views, I need to show only the Ratings with 'max' type and I am trying to filter the collection without success until now.
My tries so far:
if ($ratings && $ratings -> search('max') != false)
OR
if ($ratings && $ratings -> contains('max'))
So... What is the smart and eloquent way of achieving this?
Thanks in advance.
You can use the where method: https://laravel.com/docs/5.4/collections#method-where
$filtered_ratings = $ratings->where('type', 'max');
You could also use the filter() method on the collection.
return $collection->filter(function ($value, $key) {
if($value->type == 'max'){
return $value;
}
});

Resources