How can i Get Laravel relationship with its relationship values? - laravel

I have a laravel database design where every result has belongsToMany relationship with question and every question has belogsTo relationship with subject. i want to fetch subject names from results with single statement on laravel
I have tried this https://laravel.com/docs/5.6/eloquent-relationships#has-many-through from laravel documentation
here is my code from Result model
public function questions(){
return $this->belongsToMany('App\questions', 'results_questions', 'result_id', 'questions_id');
}
the code from question model
public function subject(){
return $this->belongsTo('App\Subject','subject_id');
}
and this is what i tried from documentation (doesnot work)
public function subjects(){
return $this->hasManyThrough(
'App\Subject',
'App\questions',
'subject_id', // Foreign key on question table...
'questions_id', // Foreign key on result table...
'id', // Local key on question table...
'id' // Local key on result table...
);
}**strong text**

Try to remove 5th and 6th parameters from your relation, since they are optional. Also, should your Questions model be lowercase?
public function subjects(){
return $this->hasManyThrough(
'App\Subject',
'App\questions', //*Should this be lowercase?*
'subject_id', // Foreign key on question table...
'questions_id', // Foreign key on result table...
);
}

Related

How to delete record with composite primary keys using Eloquent?

I'm trying to delete a record with two primary keys, using Eloquent - Laravel.
This is my model
class Like extends Model
{
//protected $primaryKey = ['crdid', 'usrid'];
public $timestamps = false;
use HasFactory;
}
Controller
try{
$dellike = Like::where('crdid', '=', $like->crdid, 'and')
->where('usrid', '=', $like->usrid)->first();
$dellike->delete();
}
catch(Exception $e){
return $e->getMessage();
}
Table definition
Schema::create('likes', function (Blueprint $table) {
$table->biginteger('crdid');
$table->biginteger('usrid');
$keys = array('crdid', 'usrid');
$table->primary($keys);
});
However, it gives me the below error;
Column not found: 1054 Unknown column 'id' in 'where clause' (SQL: delete from `likes` where `id` is null)
I believe the 'id' is the default primary key used by Eloquent, but I'm not using it.
How should I define that, I'm not using the default primary key? or what is the correct way to delete the record with composite primary keys? Any help would be highly appreciated.
As Laravel Eloquent Docs says:
Eloquent requires each model to have at least one uniquely identifying "ID" that can serve as its primary key. "Composite" primary keys are not supported by Eloquent models. However, you are free to add additional multi-column, unique indexes to your database tables in addition to the table's uniquely identifying primary key.
So you can't use some methods of eloquent.
But seeing your code, looks like you are trying to create a model for a relationship pivot table (many to many between user and crd (what is crd?! no reason to abreviatte here.)
Try defining a many to many relationship on your user and crd model.
Also laravel naming convention for key columns is: model_name_id for a model named ModelName
But, just to delete, you can skip the first in your query:
Like::where('crdid', '=', $like->crdid, 'and')
->where('usrid', '=', $like->usrid)->delete();
This happens because when you delete a model (your attempt) laravel uses the primary key field (defaults to id) as where condition. But manually querying, you are defining the where clauses of the delete.
Just create additionnal column named id in the table as unique with auto-increment option. Eloquent will use it to delete each row with delete function.
Example with Laravel 5.5 :
$logement = Logement::findOrFail($id);
$commodites = Commodites_logement::all()->where('logement_id','=',$logement->id);
foreach ($commodites as $commodite) {
$commodite->delete();
}

best way to retrive a collection from -many to many- connected to -one to many- relation (laravel7)

you can see a part of my database in the image below:
the goal of this design was to able the admins send alerts to users filtered by center and field(dynamically). if you think this is a bad design tell me (please say why and how should I improve my design).
now if I want to get the alerts for a user I should do this:
$userAlerts = collect();
auth()->user()->branch()->first()->groups()->get()->each(function ($item, $key) use ($userAlerts) {
$item->alerts()->get()->each(function ($item, $key) use ($userAlerts) {
$userAlerts->push($item);
});
});
this code is ridiculous and I don't want to do it in this way.
instead i want to do something like this:
$alerts = auth()->user()->branch()->groups()->alerts() // i want this // method 1
or
$alerts = auth()->user()->alerts() //or maybe this // method 2
can I do something like this without changing the database? (method 1 or 2).
You can use laravel's default Has Many Through on branch model to pick associated alerts
class Branch extends Model
{
public function alerts()
{
return $this->hasManyThrough(
'App\Models\Alert',
'App\Models\Group',
'branch_id', // Foreign key on alert table...
'group_id', // Foreign key on group table...
'id', // Local key on branch table...
'id' // Local key on group table...
);
}
}
Uisng this way you can query user alerts as
$alerts = auth()->user()->branch()->alerts()
Or you can use third party package eloquent-has-many-deep which provides an ease to extend hasManyThrough on multiple related models
class User extends Model
{
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function alerts()
{
return $this->hasManyDeep(
'App\Models\Alert',
['App\Models\Branch', 'App\Models\Group'], // Intermediate models, beginning at the far parent (User).
[
'user_id', // Foreign key on the "branch" table.
'branch_id', // Foreign key on the "group" table.
'group_id' // Foreign key on the "alert" table.
],
[
'id', // Local key on the "user" table.
'id', // Local key on the "branch" table.
'id' // Local key on the "group" table.
]
);
}
}
And you can directly get user alerts as
$alerts = auth()->user()->alerts()
Lastly you can define alerts relation in user model by adding some joins to directly pull related alerts
class User extends Model
{
public function alerts()
{
return $this->belongsTO('App\Branch', 'branch_id')
->join('branch_group', 'branches.id', '=', 'branch_group.branch_id')
->join('alerts', 'branch_group.group_id', '=', 'alerts.group_id')
->select('alerts.*');
}
}

Seeding a table that has multiple relationships?

I have a comments table that belongsTo both a user table and an article table.
How can the table be seeded so that both the user and article foreign key is complete?
After looking through various examples, I found that you could seed the user then attach/save other models...
factory(User::class, 100)->create()->each(function ($user) {
$articles = factory(Article::class, 5)->make();
$user->article()->saveMany($articles);
But how can the same be done for comments with two foreign keys?
Not tested, but it should work, or at least give you the idea.
In the case of comments, you can create a factory like this one, where you will assign the foreign keys taking a random User and Article:
$factory->define(Comment::class, function (Generator $faker) {
return [
'content' => $faker->paragraph,
'user_id' => User::inRandomOrder()->select('id')->first()->id,
'article_id' => Article::inRandomOrder()->select('id')->first()->id
];
});
Note that both User and Article records must exist for you to assign their ids to foreign keys. So to use the factory in the seeder, you will have call it after the users and articles be inserted:
// do the inserts of users and articles, I left this as you show it in the question
factory(User::class, 100)->create()->each(function ($user) {
$articles = factory(Article::class, 5)->make();
$user->article()->saveMany($articles);
});
factory(Comment::class, 50)->create();

Laravel hasManyThrough returning empty array

I need some help regarding hasManyThrough()
user_duty
id
user_id
date
duty_hours
sales_duty
id
user_id
date
total_sales
total_orders
income_table
id
sales_id (this is same as 'id' of sales_duty)
date (same as 'date' of sales_duty)
total_income
total_collection
I can relate sales_duty with income_table using (sales_id,date) these two keys.
I can also connect to sales_duty from user_duty based on (user_id,date)
Now I want to connect to user_duty to income_table
public function user_income()
{
return $this->hasManyThrough('App\IncomeTable','App\SalesTable','id','sales_id','id','id');
}
But its returning empty
According to the details you have provided it should be like this.
public function user_income()
{
return $this->hasManyThrough(
'App\IncomeTable',
'App\SalesTable',
'user_id', // Foreign key on sales_duty table...
'sales_id', // Foreign key on income_table...
'id', // Local key on user_duty table...
'id' // Local key on sales_duty table...
);
}

Laravel - Many to Many Polymorphic Relation with Extra Fields

How can I define a many to many polymorphic relation with extra fields?
I have three (or more, as it is a polymorphic relation) tables.
tags table: id, name
tagged table: id, tag_id, taggable_id, taggable_type, user_id
posts table: id, record, timestamps
users table: id, name, email
The user_id on the tagged table referes to the users table on column id.
In my Post model I have:
public function tags()
{
return $this->morphToMany('App\Tag', 'taggable','tagged');
}
and in my Tag model I have:
public function posts()
{
return $this->morphedByMany('App\Post', 'taggable','tagged');
}
Then when I am try this in my controller:
$tag = new \App\Tag(
array(
'tag'=>"someTag"
));
$tag->save()
$post = \App\Post::find($id);
$post->tags()->save($tag);
I get Integrity Constraint Violation for not having a user_id:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (hb.tagged, CONSTRAINT tagged_user_id_foreign FOREIGN KEY (user_id) REFERENCES users (id)) (SQL: insert into tagged (tag_id, taggable_id, taggable_type) values (26, 2, App\Resource)).
Which is somewhat expected, as I have never had the chance to define or declare the user_id field.
Also, I have tried withPivot() on tags relation as follows, to no avail:
public function tags()
{
return $this->morphToMany('App\Tag', 'taggable','tagged')->withPivot('user_id');
}
Like in the comment: withPivot has nothing to do with saving/creating. If you want to pass additional pivot data when saving, do this:
$post->tags()->save($tag, ['user_id' => $userId]);

Resources