Laravel add variable for nested collections - laravel

I want to add variable to each object of collection inside collection. Here JSON response like this:
{
"id": 16,
"survey_id": "8",
"title": "How are you?",
"created_at": "2020-02-06 04:21:44",
"updated_at": "2020-02-06 04:21:44",
"answers": [
Here I want to add variable to each answer
{
"id": 52,
"question_id": "16",
"text": "VERY GOOD",
"created_at": "2020-02-06 04:21:44",
"updated_at": "2020-02-06 04:21:44",
"reports_count": "4",
"responded": 2
},
{
"id": 53,
"question_id": "16",
"text": "OK",
"created_at": "2020-02-06 04:21:44",
"updated_at": "2020-02-06 04:21:44",
"reports_count": "4",
"responded": 2
},
{
"id": 54,
"question_id": "16",
"text": "BAD",
"created_at": "2020-02-06 04:21:44",
"updated_at": "2020-02-06 04:21:44",
"reports_count": "2",
"responded": 2
}
]
},
Overall, I want to add for every answers variable like $respond = $answer->reports()->count(); Help PLease!!

You could do something like this, if you want to calculate it in the collection directly.
$yourCollection->transform(function($collectionItem) {
$collectionItem['responded'] = $collectionItem->answers->count();
return $collectionItem;
});
But you could do this also on the sql side. I think it should be also the better way ;)

I would fetch the answers from the database before assigning that array to a new question-object-property.
public function get() {
// fetch parent question
$question = Question::where('title', $title)->get();
// fetch answers
$answers = Answers::where('parent_id', $question->id)->get();
// create property called "answers"
$question->answers = $answers;
return response()->json($question);
}

Related

Laravel, get relation row instead of id

I want to get author row instead of author_id. I could this with add collection and change one by one but has Laravel any function for this? Well, I want make this one line
Can i use something like this
Book::where('id',$bid)->with('author')->first('author_id AS author'); //Changes only coulmn name :(
model
public function author()
{
return $this->hasOne(Author::class,'id','author_id');
}
query
Book::where('id',$bid)->with('author')->first()
Output
{
"id": 1,
"name": "Book 1",
"author_id": 3,
"category_id": 2,
"level_id": 1,
"book_language_id": 1,
"book_length": 0,
"img": "book1.png",
"summary": "Summary 1",
"rate_avg": "2.75",
"created_at": "2022-03-04T18:46:32.000000Z",
"updated_at": "2022-03-04T18:52:28.000000Z",
"author": {
"id": 3,
"name": "Author 3",
"created_at": "2022-03-04T18:46:32.000000Z",
"updated_at": "2022-03-04T18:46:32.000000Z"
}
}
Want
{
"id": 1,
"name": "Book 1",
"author": {
"id": 3,
"name": "Author 3",
"created_at": "2022-03-04T18:46:32.000000Z",
"updated_at": "2022-03-04T18:46:32.000000Z"
},
"category_id": 2,
"level_id": 1,
"book_language_id": 1,
"book_length": 0,
"img": "book1.png",
"summary": "Summary 1",
"rate_avg": "2.75",
"created_at": "2022-03-04T18:46:32.000000Z",
"updated_at": "2022-03-04T18:52:28.000000Z",
}
in your query
Book::where('id',$bid)->with('author')->first()
you are getting the book that has that id and you are eager loading the author relation, so in order to get the author you have to access the author field:
Book::where('id',$bid)->with('author')->first()->author
As I said I can this with collection like this:
$b=Book::where('id',$bid)->with('author')->first();
$book=collect([
'id'=>$b->id,
'name'=>$b->name,
'author'=>$b->author,
'category_id'=>$b->category_id,
'level_id'=>$b->level_id,
'book_language_id'=>$b->book_language_id,
'book_length'=>$b->book_length,
'summary'=>$b->summary,
'rate_avg'=>$b->rate_avg,
]);
But this method seems unnecessary
In your example the only difference between the output and what you want is "author_id": 3, as been deleted.
So if you don't want a column or rename a column, you need to use ->select and take all the field you want. And you can also rename with something like that
-> select(DB::raw('author_id as auhtor'), 'books.*')

How to merge two collections with a specific condition in laravel?

I have Two collections competences and coCompetences those collections look like :
competence :
...
{
"id": 6,
"category_id": 17,
"user_id": 1,
"objective_level": 4,
"current_level": 4,
"target_date": "2021-11-28",
"obtained_date": "2022-10-14",
"comment": "",
"created_at": "2020-01-08 10:06:28",
"updated_at": "2020-01-08 10:06:28",
"name": null,
"competenceName": "Hierarchy Building & BOM (Bill of Material)",
"category": {
"id": 17,
"competence": "Hierarchy Building & BOM (Bill of Material)",
"created_at": "2020-01-08 09:53:55",
"updated_at": "2020-01-08 09:53:55",
"wheel_id": 10
}
},
{
...
coCompetences :
{
"category": {
"id": 12,
"competence": "Criticality Analysis",
"created_at": "2020-01-08 09:53:55",
"updated_at": "2020-01-08 09:53:55",
"wheel_id": 10
},
"user_id": 1,
"competenceName": "Criticality Analysis",
"category_id": 12,
"objective_level": 0,
"current_level": 0,
"target_date": "2020-01-14",
"obtained_date": "2020-01-14",
"comment": ""
},
I would like to push only coCompetences elements into competences where coCompetences.category_id are not exist in competences.category_id
in another way : add all coCompetences elements to competences except those where coCompetences.category_id already exists in coCompetences.
I don't want to write code instead of you, algorithm will be enough, I hope.
simplest way
Take array Ids from first array, for example by pluck()
Filter second and return items that don't exist in first
push filtered data to first

How to map Laravel API resources for Non-Related Models

Hi I'm creating non related model resources. Inventories and Categories. They have child relationship models but they are not connected directly.
Sample:
{
"data": {
"inventories": [
{
"id": 1,
"user_id": 1,
"sub_category_id": 6,
"created_at": "2019-03-08 03:00:00",
"updated_at": "2019-03-08 03:00:00",
"deleted_at": null,
"get_inventory_details": {
"id": 1,
"inventory_id": 1,
"image_path": "Pahiram-Drone1-1.png",
"name": "Drone i1",
"description": "Drone i1 The Best Drone yet!",
"quantity": 10,
"cost_per_day": 1000,
"cost_per_hour": 100,
"status": "0",
"created_at": "2019-03-08 03:00:00",
"updated_at": "2019-03-08 03:00:00",
"deleted_at": null
}
}
],"categories": [
{
"id": 1,
"category_id": 1,
"parent_id": null,
"created_at": "2019-03-08 03:00:00",
"updated_at": "2019-03-08 03:00:00",
"deleted_at": null,
"get_sub_category_details": {
"id": 1,
"sub_category_id": 1,
"category_type_id": 1,
"name": "Drone DJI 1",
"description": "Drone DJI 1",
"created_at": "2019-03-08 03:34:23",
"updated_at": "2019-03-08 03:34:23",
"deleted_at": null
}
}
]
}
}
This is my sample data
It works with:
public function toArray($request)
{
return parent::toArray($request);
}
But not:
public function toArray($request)
{
return [
'inventory_ids' => $this->inventories->id,
'category_ids' => $this->categories->id
];
}
My expected result is to be able to map my response.
You Don't access direct id from categories and inventories, because its an array not object.
This should be usefull for you.
$categoryIds = Collection::make($this->categories)->pluck('id')->toArray();
$inventoryIds = Collection::make($this->inventories)->pluck('id')->toArray();
return [
'category_ids' => $categoryIds,
'inventory_ids' => $inventoryIds
];

Laravel, appending an attribute to a returned json appends the entire object

I have 2 tables Customer(Parent) and jobCode(Child) with one to many relationships
I want to retrieve a child record but with one extra field from the parent (customerGuid) as well. My code:
$jobCodes=JobCode::all();
foreach ($jobCodes as $jobCode) {
$jobCode['customerGuid']=$jobCode->customer->guid;
// I also tried $jobCode->setAttribute('customerGuid',$jobCode->customer->guid);
}
return $jobCodes;
I was expecting just the parent's guid field to be appended to each jobCode object and returned. However the ENTIRE customer parent object is returned!
[{
"id": 137,
"customerId": 1,
"jobCode": "Journeyman Plumber",
"jobDescription": "Journeyman Plumber",
"created_at": null,
"updated_at": "2017-01-27 12:20:27",
"guid": "28f35e94-e483-11e6-98e9-e0db55883624",
"customerGuid": "8d48931d-dc61-11e6-8927-e0db55883624",
"customer": {
"id": 1,
"name": "ACME",
"address1": "",
"address2": "",
"city": "San Jose",
"zip": "",
"phone": "",
"fax": "",
"email": "",
"guid": "8d48931d-dc61-11e6-8927-e0db55883624",
"stateName": "California",
"created_at": null,
"updated_at": "2017-01-20 07:10:59"
}
}, {
"id": 138,
"customerId": 1,
"jobCode": "JRP PreFab",
"jobDescription": "JRP",
......,
Its because your return statement returns $jobCodes; which is the entire table you retrieve here: $jobCodes=JobCode::all();
try putting this inside your loop
echo '$jobCode' to see what is the output every time it loops
Reaching for the relationship customer on $jobCode you automatically lazy load the relationship object, which is stored in $jobCode->customer attribute.
Try this instead just returning the collection:
// return $jobCodes;
return $jobCodes->map(function($jobCode){
$jobCode = $jobCode->toArray();
unset($jobCode['customer']);
return $jobCode;
});

Duplicate ID in PUT url when editing Restangular model in ui-router custom path

currently I'm setting up restangular to edit my model. Formerly it was ok when I'm not using custom url to show the form, like
http://example.com/admin/clients (I just load the form there).
But, then I use ui-router to setup the URL like this
http://example.com/admin/clients/{clientId}/edit
When I do model.put() or model.save(), the resulting PUT url is wrong. It become like this
PUT http://referral.dev/admin/clients/f2aa1490-5a8f-11e5-b936-b3a54e0c9925/f2aa1490-5a8f-11e5-b936-b3a54e0c9925
It should be like this:
PUT http://referral.dev/admin/clients/f2aa1490-5a8f-11e5-b936-b3a54e0c9925
What I do wrong?
For convenience, here is debug from restangular object:
{
"restangularCollection": false,
"$object": {
"id": "f2aa1490-5a8f-11e5-b936-b3a54e0c9925",
"referrer_id": "f1529d80-5a8f-11e5-8ca1-21124a5fa590",
"email": "Claudia.Kertzmann#hotmail.com",
"first_name": "Isabelle",
"last_name": "Herzog",
"mobile": "450.357.8579x621",
"stage": "member",
"stage_at": "2015-09-09 00:00:00",
"previous_stages": [
{
"stage": "lead",
"stage_at": "2015-08-30 00:00:00"
}
],
"total_investment": 190000,
"email_token": "caf34dddfe00f36b180d459236830934",
"confirmed": false,
"unsubscribed": false,
"transfered_at": null,
"previous_referrers": [],
"created_at": "2015-09-14 03:23:20",
"updated_at": "2015-09-14 03:23:20",
"referrer": {
"id": "f1529d80-5a8f-11e5-8ca1-21124a5fa590",
"email": "Eulalia.Pacocha#Dickens.biz",
"name": "Esperanza Aufderhar Sr.",
"mobile": "658.549.0277",
"role": "referrer",
"organization_id": "f0577b10-5a8f-11e5-984f-f120de15e3c1",
"last_login_at": "0000-00-00 00:00:00",
"suspended": 0
},
"route": "f2aa1490-5a8f-11e5-b936-b3a54e0c9925",
"reqParams": null,
"restangularized": true,
"fromServer": true,
"parentResource": {
"route": "admin/clients",
"parentResource": null
},
"restangularCollection": false
}
}
And, here is the restangular object if don't use custom URL (which working):
{
"id": "f2aa1490-5a8f-11e5-b936-b3a54e0c9925",
"referrer_id": "f1529d80-5a8f-11e5-8ca1-21124a5fa590",
"email": "Claudia.Kertzmann#hotmail.com",
"first_name": "Isabelle",
"last_name": "Herzog",
"mobile": "450.357.8579x621",
"stage": "member",
"stage_at": "2015-09-09 00:00:00",
"previous_stages": [
{
"stage": "lead",
"stage_at": "2015-08-30 00:00:00"
}
],
"total_investment": 190000,
"email_token": "caf34dddfe00f36b180d459236830934",
"confirmed": false,
"unsubscribed": false,
"transfered_at": null,
"previous_referrers": [],
"created_at": "2015-09-14 03:23:20",
"updated_at": "2015-09-14 03:23:20",
"referrer": {
"id": "f1529d80-5a8f-11e5-8ca1-21124a5fa590",
"email": "Eulalia.Pacocha#Dickens.biz",
"name": "Esperanza Aufderhar Sr.",
"mobile": "658.549.0277",
"role": "referrer",
"organization_id": "f0577b10-5a8f-11e5-984f-f120de15e3c1",
"last_login_at": "0000-00-00 00:00:00",
"suspended": 0
},
"route": "admin/clients",
"reqParams": null,
"restangularized": true,
"fromServer": true,
"parentResource": null,
"restangularCollection": false
}
I've tried manually set $object.route to "admin/clients" but the PUT url is still the same.
Thanks.. :)
I've solved it. Formerly I was using:
var models = Restangular.all('admin/clients');
Then use
models.one($stateParams.clientId).get()
to get the model.
The correct way, is use Restangular.one to load model, eg. like this:
vm.model = Restangular.one('admin/clients', $stateParams.clientId).get();

Resources