Laravel Pivot Tables - accessing from inverse relation-table - php

UPDATE: Apparently $problem->userRatings()->count(); returns 1, so a record does exist, but the script still doesn't enter the foreach loop for some reason...
UPDATE 2/Solution: I feel incredibly foolish, but the reason it isn't working, is that I was calling foreach($problem->userRatings() as $rating){ when it should be foreach($problem->userRatings as $rating){ (dynamic property)
In my database I have problem_ratings, problems, and users. I have models for users and problems, and problems_ratings is a pivot table between problems and users with an extra 'content' column that stores the numeric rating value (1-5).
The many-to-many relation in my Problem model:
public function userRatings(){
return $this->belongsToMany('User', 'problem_ratings', 'author_id', 'problem_id')->withPivot('content');
}
The many-to-many relation in my User model:
public function problemRatings(){
return $this->belongsToMany('Problem', 'problem_ratings', 'author_id', 'problem_id')->withPivot('content');
}
When creating a problem_ratings element, I attach it to my user model like so:
$user->problemRatings()->attach($problem->id, array('content' => $val));
I can access the pivot table through the user, but when I try this:
foreach($problem->userRatings() as $rating){
echo "In average loop";
$newAverage = ($rating->pivot->content) + $newAverage;
}
it doesn't find any records, even though some exist in the database. Am I using these relations correctly?
Thanks in advance!

In the Problem model I think your relationship should looks something like :
public function userRatings(){
return $this->belongsToMany('User', 'problem_ratings', 'problem_id', 'author_id')->withPivot('content');
}

When using a foreach loop over something like this, you need to use dynamic properties (ie. without parentheses):
foreach($problem->userRatings as $rating){ instead of foreach($problem->userRatings() as $rating){

Related

Eloquent nested complex relationship

I have some trouble with chaining relationships. I want to chain three of them, but this is not working properly:
return UserModel::with('cars.pieces.attributes')
I want to retrieve a user with its cars. He chose a car which have pieces and for each pieces he chose an attribute.
With only cars.pieces. I have my user, then the array of cars then the array of pieces for this car. When I add attributes, I have attributes not for pieces of cars of users but attributes for pieces whatever cars it is.
It seems like the relationship is only looking for the previous relation and not the whole packet.
public function cars(){
return $this->belongsToMany(CarsModel::class, 'user_cars', 'id_user','id_cars');
}
Then
public function pieces(){
return $this->belongsToMany(PiecesModel::class, 'cars_pieces', 'id_cars','id_pieces')
}
And finally :
public function attributes(){
return $this->belongsToMany(AttributeModel::class, 'user_cars_pieces_attributes', 'id_attribute', 'id_piece')
}
The last entity is using 4 fields for the primary key :
id_user, id_car, id_attribute, id_piece
What could be a way to retrieve attributes for pieces of cars of the user?
Thank you for helping!
You can pass a function to your eager loading attributes:
return UserModel::with(['cars.pieces.attributes' => function ($query) {
$query->where('id_user', DB::raw('users.id'))->where('id_car', DB::raw('cars.id'));
}]);
I haven't tested this but I think it should work.
Remember to import DB Facade: use Illuminate\Support\Facades\DB;

Laravel Many-To-Many relation returns no results

I am currently learning Laravel and I have an issue which I can't seem to find a solution for. I have a many-to-many relation between two tables that always returns nothing. Let me show you the basic setup:
My posts Model:
// App\Post.php
protected $fillable = [
'name',
'description'
'videopath'
];
public function Tags()
{
return $this->belongsToMany('App\Tag');
}
public function Cats()
{
return $this->belongsToMany('App\Cat');
}
My tags model:
// App\Tag.php
protected $fillable = [
'name',
'description'
];
public function exercises()
{
return $this->belongsToMany('App\Exercise');
}
My posts controller:
// PostController.php
public function show($id)
{
$post = Post::find($id);
return view('posts', ['post'=>$post];
}
The view:
// posts.blade.php
#foreach($post->tags() as $tag)
//do stuff
#endforeach
The intermediate table is called post_tag and contains the post_id and tag_id columns. At first it returned the results as expected but after some while all of my posts didn't return any tags anymore. The cats model looks similar to the tags model. Anyone has an idea?
Check the name of your Tags function. In your view you are calling "tags" instead of "Tags".
Have you created the intermediate table in your database? If so, check the naming convention (alphabetic order) that Laravel uses to find it: in your case it should be tag_post. if not, customize the name of the table when defining the relationship.
Many To Many
Many-to-many relations are slightly more complicated than hasOne and hasMany relationships. An example of such a
relationship is a user with many roles, where the roles are also
shared by other users. For example, many users may have the role of
"Admin". To define this relationship, three database tables are
needed: users, roles, and role_user. The role_user table is derived from the alphabetical order of the related model names, and contains the user_id and role_id columns.
Taking your view:
#foreach($post->tags() as $tag)
//do stuff
#endforeach
$post->tags() will return the relationship instead of the actual collection. You want $post->tags instead or $post->tags()->get().

Laravel get model with relation's pivot condition

I need to get all appeals, that have appeal_stage.expiration_date less than NOW().
Now I have following solution:
public function scopeExpired($query) {
$query->join('appeal_stage', 'appeals.id', 'appeal_stage.appeal_id')
->where('appeal_stage.expiration_date', '<=', new Expression('NOW()'));
}
but resulted model dump shows that joined table is recognized as pivot table:
So, I want to ask - Is there some more convenient way to perform this request?
My suggestions is use Illuminate\Database\Eloquent\Relations\Pivot somehow, bu I do not quiet understand, how Pivot can be used here.
UPD 1
Models has next relations:
public function stages()
{
return $this->belongsToMany(Stage::class)->withPivot('prolongated_count', 'expiration_date')->withTimestamps();
}
public function appeals() {
return $this->belongsToMany(Appeal::class);
}
You should be able to do something like this:
$appeal->stages()->wherePivot('expiration_date', '<', $now)->get()
You should create relationship in appeal model
public function stages()
{
return $this->belongsToMany(Stage::class,'appeal_stage','appeal_id','stage_id')->wherePivot('expiration_date','<',Carbon::now())->withTimestamps();
}
In belongs To Many relationship second argument is your Pivot table name

Laravel relationship with pivot table

I have 3 tables in my database :
users (id);
interests (id);
users_interests (user_id, interests_id);
I want to be able to fetch all the user's interests in this way :
$interests = $user->interests
This is what I wrote in the User.php model, following laravel's doc:
public function interests() {
return $this->hasManyThrough(
'App\Interest', 'App\UserInterest',
'user_id', 'id', 'interest_id'
);
}
but it returns empty even though the user has a game. So there has to be something I'm doing wrong
Anyone to help me ?
I think a belongs to many would do the job:
public function interests() {
return $this->belongsToMany(
'App\Interest',
'users_interests',
'user_id',
'interests_id'
);
}
Quite similar to the example in the docs
If you were to rename users_interests table to interest_user and the column
interests_id to the singular form you would just need the first parameter:
public function interests() {
return $this->belongsToMany(App\Interest::class);
}
From my understanding the hasManyThrough is used to jump forward within a relation (also described in the docs):
The "has-many-through" relationship provides a convenient shortcut for
accessing distant relations via an intermediate relation.

How to return model rows where id is equal to id on other table with relations in laravel?

For example I have:
// Returns all projects
$projects = Projects::all();
To return categories, belonging to project, I use relationships and can do something like:
foreach($projects as $project) { ...show $project->categories... }
I need only specific projects, which are followed by specific user. On my projects_followers table I have user_id and project_id.
To retrieve projects which were followed I have this peace of code:
$projects = Project::rightJoin(DB::raw('(select * from projects_followers group by project_id) projects_followers'),'projects_followers.project_id','=','projects.id')->get();
// Note: This code doesn't include specifuc user_id.
It does retrieve specific rows, but the problem with this code is that laravel relationhips dont work on them. For example $project->categories return empty.
// Relationship
public function categories()
{
return $this->belongsToMany('App\Category');
}
How do I retrieve my model specific rows and make relationships to work?
Actually your question is:
How do I get projects liked/followed by Auth/Logged in User ?
Unfortunately you described it in such a way that it looks something else, anyways. Lets try to find the solution and for this I would like to use something like this:
$projects = Auth::user()->favorite_projects;
So how we can implement this to work, first of all the User Model should contain the method favoriteProjects so lets create it:
public function favoriteProjects()
{
return $this->belongsToMany(
'App\Project',
'projects_followers', // This table already exists as you mentioned
'user_id',
'project_id'
);
}
That's it. You will be able to load the projects followed by the current user and other relationship methods will work on every single project as well.
My workaround:
// I don't know how to create empty collection, so impossible conditions here.
$projects = Project::where('id', 0)->get();
$follows = DB::table('projects_followers')->where('follower_id', Auth::user()->id)->get();
foreach($follows as $follow) {
$project = Project::where('id', $follow->project_id)->first();
$projects = $projects->add($project);
}

Categories