Laravel - insert multiple rows with pivot table data - laravel

I have 3 tables:
Questions
Answers
question_answers
Question Model:
public function answer()
{
return $this->belongsToMany(Answer::class);
}
I created a page where I type a question and 4 answers, and I insert them to my database.
$question = new Question;
$question->title = $request->question_title;
$question->save();
$answers = $request->answers;
$answer = Answer::insert($answers);
How I can insert the question_answers for each question too?
question_answers looks like this:
I couldn't find a clue how to do it with the insert method

Since you're using many-to-many relationship, you should use attach() method. For example:
$question = Question::create($request->question); // Save question.
$answersIds = [];
foreach ($request->answers as $answer) {
$answersIds [] = Answer::create($answer)->id; // Save each answer.
}
$question->answers()->attach($answersIds); // Attach answers to the question.
Also you can't use insert() to bulk insert answers, because you need to get answer IDs to attach answers to the question.

Related

Laravel Eloquent Query containing pivots and relations

I want to make graphs based on values i get from my questionnaire. This is how my database looks like (Only showing the ones I need):
questionnaires
id
client_id
questionnaire_answers
id
questionnaire_id
questionnaire_question_id
answer
questionnaire_questions
id
question
What I want is basically get all the answers of question 1 (of all their questionnaires) from a specific client.
The idea is that they answer a question that is based on severity, so 1 - 5 basically.
I've tried this in the controller:
$questionnaires = JsonResource::collection(
Questionnaire::where('client_id', '=', 2)
->with([
'clients',
'questionnaire_answers',
'questionnaire_answers.questionnaire_question',
'questionnaire_answers.questionnaire_question.questionnaire_question_type'
])
->get()
);
dd($questionnaires);
All relations work.
What I want is basically get all the answers of question 1 (of all their questionnaires) from a specific client. The idea is that they answer a question that is based on severity, so 1 - 5 basically.
I'd redo the query so it starts from the Question model.
Assuming the following relationships:
Question belongsToMany Questionnaire (using Answer as the pivot model)
// Question model
public function questionnaires()
{
return $this->belongsToMany(Questionnaire::class)
->withPivot('answer')
->as('answer')
->using(Answer::class);
}
$client_id = ...;
$question = Question::query()
->whereHas('questionnaires', function ($questionnaire) use ($client_id) {
$questionnaire->where('client_id', $client_id);
})
->with([
'questionnaires' => function ($questionnaire) use ($client_id) {
$questionnaire->where('client_id', $client_id)
->with('client');
},
'question_type',
])
->find(1);
foreach ($question->questionnaires as $questionnaire) {
$questionnaire->client->... // client attributes
$question->.... // question attributes
$questionnaire->answer->... // answer attributes.
$questionnaire->question_type->... // question_type attributes
}

How can I link 2 existing models in my laravel code?

I have two models customer and orders. They are already fecthed separately
$customers = customer::all();
$orders = orders::all();
customerID=1 has orderID : 1, 2,4 customerID=2 has orderID : 3,5,9
They are related (hasMany, belongsTo) but the problem is inside my for a certain reason they are separated but I want to send them as response in API using toJson or ToArray as one data having the orders nested to their correct customers.
How can I achieve that linking to have at the end one variable $customersWithOrders that should be transformed to JSON ?
I am using laravel 5.5
I don't know what the context is. Defining relationships as other answers mentioned is a good solution.
In addition, I recently read a pretty good article about this specific scenario.
So you can also do something like this, if you have already retrieved customers and orders:
$customers = Customer::all();
$orders = Order::all();
return $customers->each(function ($customers) use ($orders) {
$customer->setRelation('orders', $orders->where('customer_id', $customer->id));
});
If you already have a relation you just use it. For example, in model Customer.php:
public function orders()
{
return $this->hasMany(Order::class);
}
Then you'd get customer orders by calling $customer->orders
If you already have defined relations, you can simply fetch data with eager loading
// in customer model
public function orders()
{
return $this->hasMany(orders::class, 'orderID');
}
// in controller
$customersWithOrders = customer::with('orders')->get();
return response()->json(['customersWithOrders' => $customersWithOrders]);
// in js
for (let customer in response.customersWithOrders){
let orders = customer.orders
}

Deleting nested comments and related data from laravel controller

ive implemented nested comments in laravel with parent_id and there's another table votes where related data's are stored.
I've hasMany relation defined in comments model. Now when i delete a comment, it should delete all its replies and votes as well.
To delete votes i used
$review->votes()->delete();
which works perfectly. but i'm stuck with deleting votes for nested replies.
If i use foreach loop how to loop inside all levels which is dynamic.
public function deletereview($id=null){
$review = Review::find($id);
foreach($review->replies as $reply){
$reply->votes()->delete();
//how to do this for all levels?
$reply = $reply->votes(); // this doesn't work
}
return back();
}
Kindly advise on the proper way of doing it.
Note : i've read through the cascade options from migrations but that doesn't explain anything for nested comments(reply of replies and its related data's).
Thanks
-Vijay
// Review Model
public function deleteRelatedData() {
// Delete all votes of this review
$this->votes()->delete();
// Calling the same method to all of the child of this review
$this->replies->each->deleteRelatedData();
}
// Controller
public function deletereview($id=null){
$review = Review::find($id);
$review->deleteRelatedData();
return back();
}
I would recommend use observer for this.
https://laravel.com/docs/5.8/eloquent#observers
public function deleted(Review $review)
{
foreach($review->replies as $reply){
$votes = $reply->votes;
Votes::destroy($votes)
}
Destroy method allow you to delete multiple models.
For any next level you have to use another foreach loop in this case.
$reply = $reply->votes(); doesn't work since you should use
$votes = $reply->votes;
//or
$votes = $reply->votes()->get();

How to save record in database using belongs to many relation in laravel

I have three tables: restaurant_location, cuisine_restaurant_location and cuisines.
There is a list of all cuisines in my cuisines table. I have all the details of the restaurant in my restaurant_location table. A restaurant can have many cuisines so I made a table cuisine_restaurant_location in which there are two columns cuisine_id and restaurant_id. I have created a belongs to many relation in my restaurant_location model.
restaurant_location model
public function cuisines()
{
return $this->belongsToMany(Cuisine::class, 'cuisine_restaurant_location', 'restaurant_id', 'cuisine_id');
}
I have a form in which all the details of the restaurant along with cuisines is supposed to be added. Right now I am adding all the details of the restaurant. Now the question is how can I insert the cuisines in "cuisine_restaurant_location".
Controller
$rest = new restaurant_location;
$rest->name = $request->input('name');
$rest->description = $request->input('desc');
$rest->save();
$cuisine = new cuisine_restaurant_location
$cuisine_lists = $request->input('cuisines');
foreach ($cuisine_lists as $cuisine_list) {
$cuisine->name = $cuisine_list;
}
You can use the sync and attach methods, described in the Many to many section of the eloquent documentation, for that:
$rest->cuisines()->attach([$cuisineIds])
Where cuisineIds is the list of ids of the cuisines you want to relate.
The difference between sync and attach is that sync will remove all id's not present on the array of ids you are passing.
Try sync() method:
$h = [];
if (isset($input["cuisine_id"])) {
$h = $input["cuisine_id"];
}
$restaurant_location->cuisines()->sync($h);

Attaching a hasOne model to another Laravel/Eloquent model without specifying id

Background
Given we have the following two tables where type_id references a row in questionType:
question
id | type_id | description
---+---------+------------
1 | 1 | A nice question
.. | .. | ..
questionType
id | name
---+----------------
1 | Multiple-choice
.. | ..
with the following Eloquent models:
class Question extends Model {
public function type() {
return $this->hasOne( 'QuestionType', 'id', 'type_id' );
}
}
class QuestionType extends Model {
}
Question 1
How can I add a new question that references an existing question type without manually doing anything with ids? For example the following works but is ugly imo since I have to manually assign the corresponding question type id:
$q = new Question;
$q->type_id = 1; // Multiple-choice
$q->description = 'This is a multiple-choice question';
$q->save();
One would think there was a way to let the ORM handle the id-assignment (isn't the point to avoid stuff like this with ORMs?), something along the lines of (this does not work in Eloquent ORM):
$q = new Question;
$q->type = QuestionType.where('name', '=', 'Multiple-choice');
$q->description = 'This is a multiple-choice question';
$q->save();
Question 2
In relation to question 1, how would I go about adding a new question that references a new question type without manually doing anything with ids? Similarly I imagine something along the lines of:
$t = new QuestionType;
$t->name = 'Another type';
$q = new Question;
$q->type = $t;
$q->description = 'This is a multiple-choice question';
$q->save();
Here I'd like $q->save() to save both the new question type and question (or something similar).
The following works, but again I'm assigning the id myself which I believe the ORM should handle:
$t = new QuestionType;
$t->name = 'Another type';
$t->save();
$q = new Question;
$q->type = $t->id;
$q->description = 'This is a multiple-choice question';
$q->save();
I've tried playing with different combinations of save(), update() methods without luck. I also looked for attach() which exists on the hasMany relationships but seem to be missing in hasOne.
First off, you misunderstood the relation you refer to.
Here's what you need:
// Question model
public function questionType()
{
return $this->belongsTo('QuestionType', 'type_id');
}
// QuestionType model
public function questions()
{
return $this->hasMany('Question', 'type_id');
}
then you can link them together like this:
$questionType = QuestionType::where(..)->first();
$question = new Question;
... // do something with it
// associate
$question->questionType()->associate($questionType);
// or the other way around - save new question and link to the type:
$questionType->questions()->save($question);
You can explicitly pass an id to associate as well:
$question->type_id = $someTypeId;
$question->save();
You can't do this:
$question->questionType = $someQuestionType;
for this way Eloquent handles model attributes, not relations.
Question 2:
$questionType = new QuestionType(['name' => 'multiple']);
$questionType->save();
$question = new Question([ ... some values ... ]);
// then either this way:
$questionType->questions()->save($question);
// or, again, the other way around:
$question->questionType()->associate($questionType);
$question->save();
Answering question 1 for me both methods are good, you don't need to change anything.
Answering question 2 you should do it as you showed. ORM won't create automatically QuestionType until you use manually save method.
For example if you used code:
$t = new QuestionType;
$t->name = 'Another type';
$t2 = new QuestionType;
$t2->name = 'Another type 2';
$q = new Question;
$q->type = $t; // what here - $t2 or $t ?
$q->description = 'This is a multiple-choice question';
$q->save();
what ORM should decide? Question isn't connected to any of $t or $t2 so ORM won't decide it for you. You need to tell ORM what's the type.
I'm not an ORM/Eloquent expert but I think you expect too much from ORM. ORM shouldn't guess what you want to do. It help you manage relations or objects but it won't associate objects if you don't tell it to do so.
You could however try with mutator. You could add to your Question model:
public function setTypeAttribute($value)
{
$value->save();
$this->attributes['type_id'] = $value->id
}
and now it should be possible to use $q->type = $t; (However I haven't tested it)

Resources