Order Nested Eager Loading Eloquent Laravel - php

I have problem with eloquent query. I am using eager loading (one-to-many Polymorphic Relationship) to sortby 'historyable.date', JSON below.
[
{
"product_id":12,
"product_name": "Product C",
"historyable_type":"App\\Delivery",
"historyable":{
"id":2,
"date":"0303\/0404\/2020",
"for":"Customer A",
"created_at":"2020-04-02T09:46:48.000000Z",
}
},
{
"product_id":1,
"product_name": "Product A",
"historyable_type":"App\\Transfer",
"historyable":{
"id":1,
"date":"0202\/0404\/2020",
"for":"First Balance ****",
"created_at":"2020-04-02T07:30:45.000000Z",
}
},
{
"product_id":11,
"product_name": "Product B",
"historyable_type":"App\\Delivery",
"historyable":{
"id":2,
"date":"0303\/0404\/2020",
"for":"Customer B",
"created_at":"2020-04-02T09:46:48.000000Z",
}
}
]
And i try to get result like this
[
{
"product_id":1,
"product_name": "Product A",
},
{
"product_id":12,
"product_name": "Product C",
},
{
"product_id":11,
"product_name": "Product B",
}
]
Is it possible to run with Nested Lazy Eager Loading Laravel?
Product Model
public function track() {
return $this->hasMany('App\History');
}
History Model
public function historyable(){
return $this->morphTo()->orderBy('date', 'desc');
}
Product Controller
public function json_history(Product $product) {
$data = $product->with('track.historyable')
->where('id', $product->id)
->first();
return $data->track;
}
I Have database like this
Products Table
#id
#name
Histories Table
#product_id
#product_name
#historyable_id
#historyable_type
Deliveries Table
#id
#date
#for
Transfers Table
#id
#date
#for

public function json_history(Product $product) {
$data = Product::with('track.historyable')
->where('id', $product->id)
->first();
$arr = $data->track->toArray();
$date = array();
$create = array();
foreach ($arr as $key => $row)
{
$date[$key] = $row['historyable']['date'];
$create[$key] = $row['historyable']['created_at'];
}
array_multisort($date, SORT_DESC, $arr);
array_multisort($create, SORT_DESC, $arr);
return $arr;
}
I don't know but it works for me.. but i still find the shorter way for this..

Related

PHP Map infinite objects

I have some struggles how to map infinite object in Laravel.
So I have one table Categories that I'm getting in controller like:
$find_parent = Category::where('slug', $slug)->with('childrenRecursive')->first();
childrenRecursive() works fine in that case.
And return of this object would be like (minified):
{
"id": "1cbd459a-ccc0-435b-b9a9-0433e2e9285b",
"parent_id": "f0d29100-d2bc-48c8-89cf-985e0c03b8ac",
"children_recursive": [
{
"id": "30bf23a7-b28c-4s78-b873-1df589eebcb1",
"parent_id": "1cbd459a-ccc0-435b-b9a9-0433e2e9285b",
"children_recursive": [
{
"id": "32312a7-b28c-4s78-b873-1df589eebcb1",
"parent_id": "30bf23a7-b28c-4s78-b873-1df589eebcb1",
}
]
},
{
"id": "32bf23a7-b28c-4s78-b873-1df589eebcb1",
"parent_id": "1cbd459a-ccc0-435b-b9a9-0433e2e9285b",
"children_recursive": []
}
]
}
So from this, I have to get all id's in every object. So I have foreach function in controller that looks like:
$find_parent = Category::where('slug', $slug)->with('childrenRecursive')->first();
$array = [];
foreach($find_parent->childrenRecursive as $l){
array_push($array, $l->id);
if($l->childrenRecursive){
$result = array_merge($array, $this->catTree($l->childrenRecursive));
}
}
return $result;
And catTree would look like:
public function catTree($list){
$tree = [];
foreach($list as $l){
array_push($tree, $l->id);
if($l->childrenRecursive){
array_merge($tree, $this->catTree($l->childrenRecursive));
}
}
return $tree;
}
So this is returning some of the objects, but not everything. What am I doing wrong here?

How to short this code, i'm doing same for each and declare variable

I think my code is ugly for such thing, i'm doing twice foreach.
$peoples;
$container = [];
foreach( $this->media_model->people as $person )
{
$people = Person::whereHas('jobs', function( Builder $query ){
$query->where('job_name', '=', 'Artist');
})->get();
$peoples = $people;
}
$peoples return json
[
{
"person_id": 1,
"first_name": "Suzuki",
"last_name": "Amanda"
},
{
"person_id": 3,
"first_name": "Stephen",
"last_name": null
}
]
i need to do something again with the data to join first name and last name
foreach( $peoples as $person )
{
array_push($container, $person->first_name.' '.$person->last_name);
}
return $container;
In the end the json data will be
[
"Suzuki Amanda",
"Stephen "
]

How to merge elements of a collection in one array using Eloquent

I'm trying the following:
I'm getting all clinic_tests related to my patients using the following function:
public function getPatientsClinicTests(Specialist $id)
{
$patientClinicTests = $id->patients()
->with('PatientClinicTests', 'PatientClinicTests.Patient.User')
->get()
->pluck('PatientClinicTests')
->filter(function ($value) { return !empty($value); });
$result = [];
foreach ($patientClinicTests as $array) {
$result = array_merge($result, $array->toArray());
}
return $result;
}
First group of code:
$patientClinicTests = $id->patients()
->with('PatientClinicTests', 'PatientClinicTests.Patient.User')
->get()
->pluck('PatientClinicTests')
->filter(function ($value) { return !empty($value); });
Brings me a collection of arrays as follows:
[
[
{
"id": 16,
"patient_id": 7,
"medical_condition_id": null,
"patient": {
"id": 7,
"user_id": 7,
"pigment_id": 14,
"id_medical_history": "6219116421",
"user": {
"id": 7,
"name": "Austen Wiegand",
}
}
},
.....
],
[
{
"id": 22,
"patient_id": 1,
"medical_condition_id": null,
"patient": {
"id": 7,
"user_id": 1,
"pigment_id": 14,
"id_medical_history": "6219116421",
"user": {
"id": 7,
"name": "Gregor Wiegand",
}
}
},
.......
]
]
As I need to return one array of elements I combine the arrays I got as follows:
$result = [];
foreach ($patientClinicTests as $array) {
$result = array_merge($result, $array->toArray());
}
return $result;
This returns one array as follows:
[
{
"id": 16,
"patient_id": 7,
"medical_condition_id": null,
"patient": {
"id": 7,
"user_id": 7,
"pigment_id": 14,
"id_medical_history": "6219116421",
"user": {
"id": 7,
"name": "Austen Wiegand",
}
}
},
{
"id": 22,
"patient_id": 1,
"medical_condition_id": null,
"patient": {
"id": 7,
"user_id": 1,
"pigment_id": 14,
"id_medical_history": "6219116421",
"user": {
"id": 7,
"name": "Gregor Wiegand",
}
}
},
.......
]
I would like to know if there is a smarter option to return as one array of elements using Eloquent instead a foreach statement.
Thanks a lot for your help!
you could use all() method to convert your collection to an array:
$patientClinicTests = $id->patients()
->with('PatientClinicTests', 'PatientClinicTests.Patient.User')
->get()
->pluck('PatientClinicTests')
->filter(function ($value) { return !empty($value); })->all();
please note that if you want to iterate over your array you should rebuild the array indexes after filtering ... you can do that using 'values' method:
$patientClinicTests = $id->patients()
->with('PatientClinicTests', 'PatientClinicTests.Patient.User')
->get()
->pluck('PatientClinicTests')
->filter(function ($value) { return !empty($value); })->values()->all();
more details in:
https://laravel.com/docs/7.x/collections#introduction
maybe you can use a collect method over the array to allign it in a single array
https://laravel.com/docs/7.x/collections
the link may be helpful
$collection = collect($patientClinicTests);
$collections = $collection->values()->all();
maybe this will work
Flatten method helps me to give a single array without using foreach statement an array_merge() function:
$patientClinicTests = $id->patients()
->with('PatientClinicTests', 'PatientClinicTests.Patient.User')
->get()
->pluck('PatientClinicTests')
->filter(function ($value) { return !empty($value); })->flatten()->all();
I will test using table joining as it has been recommended

Laravel use function in query

In controller get data from db like this, I want to pass whole of $request to another function in this controller to get price it calculating price based of many things from $request:
$user = Auth::user();
$query = Post::query();
$query
->where('province', '=', $user->province)
->where('city', '=', $user->city);
$customers = $query->get();
$customers['calculator'] = $this->calculator($request); // call function
my problem is it return like this:
{
"0": {
"id": 1,
"hash": "RqH29tkfm1dwGrXp4ZCV",
},
"1": {
"id": 3,
"hash": "RqH29tkfm1dwGsXp4ZCV",
},
"calculator": {
"price": 1
}
}
But I need to use that function for each data, and result should be like this:
{
"0": {
"id": 1,
"hash": "RqH29tkfm1dwGrXp4ZCV",
"calculator": {
"price": 1
}
},
"1": {
"id": 3,
"hash": "RqH29tkfm1dwGsXp4ZCV",
"calculator": {
"price": 1
}
}
}
What you want is to set a calculator key for each item in the $customers collection. So you need to loop over it:
foreach ($customers as $customer) {
$customer->calculator = $this->calculator($request);
}
Notice that since the $customer is a Model you should set the calculator as a property. Internally it will be set to the attributes array.

Add extra key in laravel eloquent result

I have a laravel query builder result that looks like this
{
"data": [
{
"id": "",
"awardID": 2,
"title": "Dummy title",
"status": "active",
"raceStart":"",
"raceEnd:":""
}
]
}
What i want to output is something like this
{
"data": [
{
"id": "",
"awardID": 2,
"title": "Dummy title",
"status": "active",
"period": {
"raceStart":"",
"raceEnd:":""
}
}
]
}
This would have been much easier if the period was a table with a 1 to 1 relationship with parent table but this is not the case here.
How can this be achieved?
Check if this will work. I haven't tried though but according to documentation we can add accessor and mutators. But it will change every response you are doing with the model.
Using Eloquent
// Your Model
class Race extends Model
{
{...}
protected $appends = ['period'];
// accessor
public function getPeriodAttribute($value)
{
$this->attributes['period'] = (object)[];
$this->attributes['period']['raceStart'] = $this->attributes['raceStart'];
$this->attributes['period']['raceEnd'] = $this->attributes['raceEnd'];
unset($this->attributes['raceStart']); = $value;
unset($this->attributes['raceEnd']);
return $this->attributes['period'];
}
}
Now when you will access $race->period will give the raceStart and raceEnd value.
Ref: https://laravel.com/docs/5.4/eloquent-mutators#accessors-and-mutators
else another option is after query, do a map
{...}
->map(function($data) {
$data->period = (object)[];
$data->period['raceStart'] = $data->raceStart;
$data->period['raceEnd'] = $data->raceEnd;
unset($data->raceStart);
unset($data->raceEnd);
return $data;
});
Ref: https://laravel.com/docs/5.4/eloquent-collections#introduction
Using QueryBuilder
$races = DB::table('races')->get();
$races = array_map(function ($data) {
$data->period = (object)[
"raceStart" => $data->raceStart,
"raceEnd" => $data->raceEnd
];
unset($data->raceStart);
unset($data->raceEnd);
return $data;
}, $races->data);

Categories