Getting multiple related models together - laravel

In my Laravel app, I have three models, User, Course and CourseScore. I want to get all courses for an specific user with his score. something like:
{
id: 1,
name: first_name,
corses: [
{
id: 1,
name: 'course one',
score: 17, // this is what i need for every course,
},
{
id: 2,
name: 'course two',
score: 19, // this is what i need for every course,
},
]
}
Here are my Models:
User
<?php
class User extends Authenticatable
{
public function courseScores()
{
return $this->hasMany(CourseScore::class);
}
public function courses()
{
return $this->belongsToMany(Course::class);
}
}
Course
<?php
class Course extends Model
{
public function courseScores()
{
return $this->hasMany(CourseScore::class);
}
public function users()
{
return $this->belongsToMany(User::class);
}
}
CourseScore
<?php
class CourseScore extends Model
{
protected $table = 'course_scores';
public function course()
{
return $this->belongsTo(Course::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
And of course, please let me know if the relations are incorrect.

If I understand it correctly, you can do something like this,
in your User model
public function courses(){
return $this->hasMany(Course::class); // changed belongsToMany to hasMany
}
in your Course model
public function users(){
return $this->belongsTo(User::class); // changed belongsToMany to belongsTo
}
In your controller
$usersData = User::with('courses.courseScores')->get();
dd($usersData);
I dont fully understand your table structure so Im assuming you have multiple row of Scores for single Course (One to Many).
If the relationship is one is to one then add in your Course Model
public function courseScores(){
return $this->hasOne(CourseScore::class); //changed hasMany to hasOne
}

You can try using this
$val = DB::table('course as c')
->join('user as u', 'u.id','c.id')
-join('courseScore as cs','u.id','cs.id')
->get();
Then just dd($val) to see what value it shown

Related

Laravel Eloquent HasManyThrough through 3 tables with pivot tables

I need to make a list of scopes from my positions->areas->scopes on my Booking Model.
My tables look like that:
Booking
id
...
Position
id
booking_id
...
Area
id
..
Position_areas
id
area_id
position_id
Scope
id
...
Area_Scopes
id
area_id
scope_id
And this are my relations:
class Booking extends Model
{
...
public function positions()
{
return $this->hasMany(BookingPosition::class);
}
public function areas()
{
return $this->hasManyThrough(Area::class, PositionsAreas::class, 'area_id', 'id', 'position_id', 'area_id');
}
...
}
class BookingPosition extends Model
{
...
public function booking()
{
return $this->belongsTo(Booking::class);
}
public function areas()
{
return $this->belongsToMany(Area::class, 'position_areas', 'position_id', 'area_id')
->using(PositionsAreas::class);
}
...
}
class PositionsAreas extends Pivot
{
...
protected $table = 'position_areas';
public function positions(){
return $this->belongsTo(BookingPosition::class);
}
public function areas(){
return $this->belongsTo(Area::class);
}
...
}
class Area extends Model
{
...
public function bookingPositions()
{
return $this->belongsToMany(
BookingPosition::class
)->using(PositionsAreas::class);
}
public function scopes()
{
return $this->belongsToMany(Scope::class, table: 'scope_areas');
}
...
}
class Scope extends Model
{
...
public function areas(){
return $this->belongsToMany(Area::class, table: 'scope_areas');
}
...
}
And I want to have a list of all areas on my booking model, but I don't know how to achieve that.
So that I can do something like that
...
$booking->load('scopes');
[
id
date
...
scopes => [
{...},
{...}
]
]
I tried to create pivot models for position_areas but i cant even get a list of areas on my booking model.
I couldn't figure out how to solve this with a relation like hasManyThrough but as workaround I make all scopes available in my $bookings like that.
$booking = Booking::find($booking->id);
$booking->scopes = $booking->positions
->pluck('areas')
->flatten()
->pluck('scopes')
->flatten()
->pluck('name')
->unique()
->values()
->all();

Adding and saving fields in a related belongsToMany table

The tables category, category_description and descriptions are related:
public function descriptions(): BelongsToMany
{
return $this->belongsToMany(Description::class);
}
public function categories(): BelongsTo {
return $this->belongsTo(Category::class);
}
public function descriptions(): BelongsTo {
return $this->belongsTo(Description::class);
}
public function descriptions(): BelongsToMany
{
return $this->belongsToMany(Category::class);
}
in Model respectively. When saving or updating:
public function createOrUpdate(Category $category, Request $request)
{
$category->fill($request->get('category'))->save();
$category->descriptions()->syncWithoutDetaching(
$request->input('category.descriptions', [])
);
}
An error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'description' in 'field list' (SQL: insert into `category_description` (`category_id`, `description`, `description_id`, `is_active`, `meta-description`, `meta-h1`, `meta-keyword`, `meta-title`, `name`, `slug`) values (1, 41231231, 0, 1, 23, 124, 12, 12, 12333312, 74))
Perhaps I missed something somewhere, since there is not so much experience.
UPDATE:
a category can have multiple entries, but the description has only one parent. Rewrote — One To Many (Polymorphic):
public function descriptions()
{
return $this->morphMany(Description::class, 'descriptable');
}
public function descriptable()
{
return $this->morphTo();
}
There are no problems with saving 1 record, but how to update several records at the same time?
How about?
// Category Model.
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
public function descriptions()
{
return $this->belongsToMany(Description::class)
->using(CategoryDescription::class);
}
}
// Description Model.
use Illuminate\Database\Eloquent\Model;
class Description extends Model
{
protected $fillable = [
"name",
"description",
"meta-title",
"meta-description",
"meta-keyword",
"meta-h1",
"slug",
"is_active",
];
public function categories()
{
return $this->belongsToMany(Category::class)
->using(CategoryDescription::class);
}
}
// Intermediate Model.
use Illuminate\Database\Eloquent\Relations\Pivot;
class CategoryDescription extends Pivot
{
protected $table = "category_description";
public $incrementing = true;
public function category()
{
return $this->belongsTo(Category::class, "category_id", "id");
}
public function description()
{
return $this->belongsTo(Description::class, "description_id", "id");
}
}
// createOrUpdate method.
public function createOrUpdate(Category $category, Request $request)
{
$category->fill($request->get('category'))->save();
$description = Description::create(
Arr::collapse($request->input('category.descriptions', []))
);
$category->descriptions()->syncWithoutDetaching(
$description->id
);
}
Notes:
Much as this may work for you, I personally think that you don't have a many-to-many relationship here. I believe a one-to-many relationship is sufficient.
The problem is you send data to be inserted in columns that are not found
You should send only the data that you need to insert in the table
so in your case, you should write your function as
$category->descriptions()->syncWithoutDetaching($description_id); // the id of the description you want to attach with this category
If you still don't have the description yet in the database and you are creating it with the same request you can do something like this
Description::create(['columnName'=>$request->get('columnName'),'columnName2'=>$request->get('columnName2')])->id

Laravel eloquent - one to one relation with different table

I have three tables,
1. user (id, name)
2. state (id, stateName, code)
3. user_relations(id, user_id, state_id)
3 models,
1. User
2. State
3. UserRelation
By logic, User has one UserRelation and UserRelation has one State
I can get user state by
User::first()->relation->state
What I want is call this by User::with('state')->first().
If you would like to keep the current db schema like it is, you may use Laravel accessors
Accessors and mutators allow you to format Eloquent attribute values
when you retrieve or set them on model instances.
class User
public function getStateAttribute($value) {
return $this->relation->state;
}
Usage
User::findOrFail($id)->state;
Edit
User Model
class User extends Authenticatable
{
//...
public function state() {
return $this->relation()->with('state');
}
public function relation() {
return $this->hasOne('App\UserRelation', 'user_id');
}
}
UserRelation Model
class UserRelation extends Model
{
protected $table = 'user_relations';
public function state() {
return $this->belongsTo('App\State'); // must be belongsTo instead of hasOne
}
}
State Model
class State extends Model
{
protected $table = 'states';
}
Controller
App\User::with('state')->find(1);
{
"id": 1,
"name": "Test",
"email": "test#test.com",
"email_verified_at": "2020-02-13 00:00:00",
"created_at": "2020-02-20 00:00:00",
"updated_at": null,
"state": {
"id": 2,
"state_id": 2,
"user_id": 1,
"state": {
"id": 2,
"stateName": "state 2",
"code": "code 2"
}
}
}
If user can only have one state,
add a state_id in the user table and get rid of the third table user_relations
class User extends Model
{
public function state()
{
return $this->hasOne('App\State');
}
}
class State extends Model
{
public function user()
{
return $this->belongsTo('App\User');
}
}
In this way, you can
$state = User::find(1)->state;
$user = State::find(1)->user;
First way:
You have to define state_id in users table for one to one relation.
class User extends Model
{
public function state()
{
return $this->hasOne('App\State');
}
}
Or if you need same database structure, then
Second Way:
Basically it's Many to Many relations between User and State.
So better way is to define many to many relation function in Models of User and State considering UserRelation a middle(pivot) table.
class User extends Model
{
public function states()
{
return $this->belongsToMany('App\State', 'user_relations');
}
}
class State extends Model
{
public function users()
{
return $this->belongsToMany('App\User', 'user_relations');
}
}
and then to access states of user, you can call:
$user->states->first();
It's ok that you need one to one relation, you can call first() method to fetch first record od state.
Simillery to access user of state
$state->users->first();
And if you need to access user_relations (one to one) only, you have to define methods in both user and state model:
class User extends Model
{
public function user_relation()
{
return $this->hasOne('App\UserRelation');
}
}
class State extends Model
{
public function user_relation()
{
return $this->hasOne('App\UserRelation');
}
}
Since user and state are many to many, you can user belongsToMany function inside User model.
public function states(){
return $this->belongsToMany(State::class, 'user_relations', 'user_id', 'state_id');
}
You can get Eager Loading by retrieving both models related to the user like:
$user = User::with('states')->first();
And now to retrieve states, you can loop through the states like:
foreach($user->states as $state){
//Retrieved state model variable
....
}
If you are doing one-to-one relationship you won't need a pivot table, in your case the user_relations table. Pivot tables are used to express many-to-many relations.
And for the solution you want. You will have to store the user_id in the state table.
so your state table should look like the following:
state (id, user_id, stateName, code)
Relations should be like:
User model:
public function state()
{
return $this->hasOne('App\State');
}
State model:
public function user()
{
return $this->belongsTo('App\User');
}

Laravel how to define 3 relationships with one model?

I have a Model which is called Championship. Championship may have 3 judges which are called Main Judge, Main Secretary and Judge Operator.
All of them linked to User Model and stored in the database as user ID.
My relationships looks like this
class Championship extends Model
{
protected $table = 'championships';
public function mainJudge()
{
return $this->hasOne('App\User', 'id', 'main_judge');
}
public function mainSecretary()
{
return $this->hasOne('App\User', 'id', 'main_secretary');
}
public function judgeOperator()
{
return $this->hasOne('App\User', 'id','judge_operator');
}
}
But I can't undertand how to define inverse relationship in User model
class User extends Authenticatable
{
public function sex()
{
return $this->belongsTo('App\Models\Sex');
}
public function player()
{
return $this->hasOne('App\Models\Player', 'user_id');
}
public function championship()
{
????
}
You just have to add it like you are adding other relations :
public function championship()
{
return $this->belongsTo('App\Championship');
}
When you do :
$championship = Championship::find($id);
$mainJudge = $championship->mainJudge;
$mainSecretary = $championship->mainSecretary;
// All objects will be exactly same
dd($mainJudge->championship,$mainSecretary->championship,$championship);
I assume all the user records have a foreign key to championships table championship_id
When you call the $user->championship relation it will return you the championship wrt to its foreign key championship_id
No need to worry you are just confusing the inverse relations:
See it this way:
Your mainJudge, mainSecretary, judgeOperators are of type App\User and every user have a championship_id when you will call the (App\User)->championship it will always return you its respective championship or null if the championship_id is empty.
Its just matter of perspective.
Just try the above code it will clear out your confusion.

Laravel Eloquent many to many relationship with translation

I have a problem with a many to many relationship and the translations of the terms.
I have 4 tables:
products
- id, price, whatever
products_lang
- id, product_id, lang, product_name
accessori
- id, active
accessori_lang
- id, accessori_id, lang, accessori_name
I'm trying to assign accessories to products with an intermediate table named:
accessori_products
this is the model for Product:
class Product extends Model {
protected $table = 'products';
public function productsLang () {
return $this->hasMany('App\ProductLng', 'products_id')->where('lang','=',App::getLocale());
}
public function productsLangAll() {
return $this->hasMany('App\ProductLng', 'products_id');
}
public function accessori() {
return $this->belongsToMany('App\Accessori', 'accessori_products');
}
}
this is the model for productLng:
class ProductLng extends Model {
protected $table = 'products_lng';
public function products() {
return $this->belongsTo('App\Product', 'products_id', 'id');
}
}
Then I have the model for Accessori:
class Accessori extends Model {
protected $table = 'accessori';
public function accessoriLang() {
return $this->hasMany('App\AccessoriLng')->where('lang','=',App::getLocale());
}
public function accessoriLangAll() {
return $this->hasMany('App\AccessoriLng');
}
public function accessoriProducts() {
return $this->belongsToMany('App\Products', 'accessori_products', 'accessori_id', 'products_id');
}
}
And the model for AccessoriLng:
class accessoriLng extends Model {
protected $table = 'accessori_lng';
public function accessori() {
return $this->belongsTo('App\Accessori', 'accessori_id', 'id');
}
}
the last model is for the relationship between the two tables above:
class ProductAccessori extends Model {
protected $table = 'accessori_products';
public function accessoriProducts() {
return $this->belongsTo('App\Product', 'accessori_id', 'products_id');
}
}
I'm trying to get the accessories of each product and to get also the translation but I'm having a lot of problem with this.
It's my first time with a many to many relation with translations too.
Can anyone put me on the right direction?
controller
$products = Product::has('accessori')->with([
'productsLang ',
'accessori' => function ($accessori){
$accessori->with([
'accessoriLang'
]);
}
])->get();
return $products;
you'll get products with accessori that has accessoriLang.

Resources