Multiple options to questions using eloquent - laravel

Im creating a survey app, and basically when a user selects a input type of "select" it appears a option input that can be dynamiclly increase, but that im having some issues in inserting these options in my database, im sugin the sync method to insert these options in my table, but is giving me a error of
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'toufarto.question_id' doesn't exist (SQL: select `option_question_id` from `question_id` where `id` = 11)
Here is my code:
Tables:
questions:
- id;
- input_type;
option_question
- id;
- label_option;
- question_id
My controller:
public function store(Request $request)
{
$this->validate($request, array(
'label_option' => 'max:255',
'input_type' => 'required|integer'
));
$question = new Question();
$question->input_type = $request->input_type;
$question->save();
$question->options()->sync($request->option, false);
Session::flash('success', 'success');
return back();
}
My Question Model:
public function options()
{
return $this->belongsToMany(OptionQuestion::class,'question_id','id');
}
My OptionQuestion Model:
class OptionQuestion extends Model
{
protected $table = "option_question";
}
Note: How i could add the label column to the "sync" method, since i need to insert the label from the option field of the form

As mentioned in the docs of Laravel you need to define your parameters as follows:
$this->belongsToMany(Model,table_name);
or
$this->belongsToMany(Model, table_name, table_1_key, table_2_key);
Looking at your DB schematic however it seems you should make a small adjustment.
questions
- id
- input_type;
options
- id
- label_option
option_question
- id
- question_id
- option_id
Question model
public function options()
{
return $this->belongsToMany(OptionQuestion::class);
}
Options model
public function questions()
{
return $this->belongsToMany(Question::class);
}

Related

Laravel - Dynamically add field to model and prevent its save

I need to add a field to a model, and this field is not a real column, for example:
function calculateDiscount(Order $order)
{
// some logic
$order->discount = 20; // It's just an example
return $order
}
The field discount is not a real column to database. I need to add this "dynamic" field to use later.
If I perform a save like:
$order->save();
I get the error:
Column not found: 1054 Unknown column 'discount' in 'field list' (SQL: update `orders` set `discount` = 20, where `id` = 67586)
There is a way to add a "dynamic" field and prevent Laravel save it ?
use appends
Models/Order.php
class Order extends Model {
protected $appends = [
'discount'
];
public function getDiscountAttribute() {
// your logic of how to get discount value
return $discount;
}
}
or you can load the discount attribute only when you need
// controller
$order->append('discount'); // load the value
// model
class Order extends Model {
public function getDiscountAttribute() {}
}
// add the getDiscountAttribute function only

Polymorphic model only working on one model

I currently have a polymorphic relationship using a model like so:
The model is called Productable
In the model I have:
public function productable()
{
return $this->morphTo();
}
I have another model called Product that has access to the Productable model like so:
public function productDetails()
{
return $this->morphMany(Productable::class, 'productable');
}
This works as expected and I can create a record in the Productable table like so:
$p = new Product;
$p->product_name = $request->product_name;
$p->product_type = $request->product_type;
$p->category_id = $request->product_category;
$p->description = $request->product_description;
$p->save();
$p->productDetails()->create([
'product_id' => $p->id,
]);
However the issue is I have another model called Media
which also has:
public function productDetails()
{
return $this->morphMany(Productable::class, 'productable');
}
On that model I attempt to write a record like so:
$pMedia = new Media;
$pMedia->productDetails()->create([
'product_id' => $p->id,
'productable_id' => $value,
]);
The error I get is:
Integrity constraint violation: 1048 Column 'productable_id' cannot be null (SQL: insert into `productables` (`product_id`, `productable_id`, `productable_type`, `updated_at`, `created_at`) values (38, ?, App\Models\Media, 2021-03-04 18:46:51, 2021-03-04 18:46:51))
What am I doing wrong here? Shouldn't I be to write to Media in the same way? I'm wondering what I'm missing.

Eloquent relationship: return just one value not entire row

In my laravel project I built a comment section and want to display the names of the people commenting beside their comment.
Initially I have just the userID, so I built a relationship (hasOne) linking the comment table (comment & authorID) to the users table (id (authorID) & username)
Comment.php (model) is:
[..]
public function author()
{
return $this->hasOne(User::class, 'id', 'Author');
}
The User.php model is:
<?php
[..]
public function author()
{
return $this->hasMany(Comment::class, 'Author', 'id');
}
In the controller I get the data with:
$comments= Comments::where('LinkID', (string) $id)->with('author')->orderBy('updated_at', 'ASC')->get()->all();
This works but it gives me the entire row of the user per comment. For security reasons I just want to return the 'name' field of the row (username) without the rest (email, timestamps etc.).
How can I achieve this?
please try:
$comments= Comments::where('LinkID', (string) $id)->with(['author' => function ($q) {
$q = $q->select('name', 'id');
return $q;
}
])->orderBy('updated_at', 'ASC')->get()->all();
or another way:
$comments= Comments::where('LinkID', (string) $id)->with('author:id,name')->orderBy('updated_at', 'ASC')->get()->all();
see eager loading (section Eager Loading Specific Columns)
https://laravel.com/docs/7.x/eloquent-relationships#eager-loading
note that including 'id' is necessary because it 's responsible for the relation

latest() helper function in laravel

I'm building a small application where I'm having many to many relationship between two models something like this:
class Contact extends Model
{
public function company()
{
return $this
->belongsToMany('App\Company', 'company_contact', 'company_id', 'contact_id')->withTimestamps();
}
}
Now while retrieving this I want only the latest model through the pivot table or you may say relational table, for this I'm trying to implement:
public function getData()
{
$allData = Contact::all();
foreach($allData as $data)
{
$getCompany = $data->company()->latest()->first();
$data->company = $getCompany;
}
return response()->json(['model' => $allData], 200);
}
But I'm unable to retrieve the latest table it is showing the same old value or the first value.
Guide me how can I achieve this.
You can try this :
latest() is a function defined in Illuminate\Database\Query\Builder Class.
public function latest($column = 'created_at')
{
return $this->orderBy($column, 'desc');
}
So, It will just orderBy with the column you provide in descending order with the default column will be created_at
OR
public function getData()
{
$allData = Contact::all();
foreach($allData as $data)
{
$getCompany = $data->company()->orderBy('created_at', 'desc')->first();
$data->company = $getCompany;
}
return response()->json(['model' => $allData], 200);
}
So basically idea is if you are finding the relational data from many to many relation like $data->company() in this question and try to sort this with latest it will sort the company table with created_at sorting desc in order to get relational latest data you need to sort through pivot tables i.e.
$getCompany = $data->company()->withPivot('created_at')->orderBy('pivot_cr‌​eated_at', 'desc')->first();
This is how I achieved the latest relational table.
Note: You must have pivot table in your relation, in this answer created_at is the pivot field I'm using.

Relationship hasManyThrough in Laravel?

I have three models: User, Category, Announcement.
User model:
public function categories()
{
return $this->belongsToMany("App\Category");
}
public function announcements()
{
return $this->hasManyThrough('App\Announcement', 'App\Category');
}
Category model:
public function announcements()
{
return $this->belongsToMany('App\Announcement');
}
Announcement model:
public function categories()
{
return $this->belongsToMany('App\Category');
}
I need to select all announcements through user_categories table.
For this I do:
$res = User::where("id", 1)->with("announcements")->get();
dd($res);
In result I get SQL error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'announcements.category_id' in 'on clause' (SQL: select `announcements`.*, `categories`.`user_id` from `announcements` inner join `categories` on `categories`.`id` = `announcements`.`category_id` where `categories`.`user_id` in (1) and `announcements`.`deleted_at` is null)
Why Laravel does try to search ``announcements.category_id` in table?
In conclusion I need to get all announcements on categories which user subscribed.
Table Database structure:
Users
id | name
Announcements
id | name
categories
category_id | announcement_id
users_categories
category_id | user_id
So, I need to get all announcements through table users_categories where there are relation this table with categories that is belong to announcement table.
You cannot eager load this relationship because
To perform this query, Eloquent inspects the foreign key on the intermediate table.
Thus the error
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'announcements.category_id'
Because HasManyThrough() looks for the relationship in the specified model table.
I would suggest you look at this thread:
https://laravel.io/forum/05-21-2014-problem-with-eloquents-hasmanythroughs-query
They show you how to write your own query to do that. An example would be, in the user model do
public function getAnnouncements() {
$announcements = [];
foreach( $this->categories as $category ) {
foreach( $category->announcements as $annoucement ) {
if ( !isset($announcements[$annoucement->id]) ) { //avoid duplicates
$annoucements[$announcement->id] = $announcement;
}
}
}
}
The nested foreach will give all announcement belonging to a category that related to a user.
Improving the function
public function getAnnouncements() {
$announcements = new Collection();
foreach( $this->categories as $category ) {
$announcements->collect($category->announcements);
}
}

Resources