Laravel Object queries - 3 tables - php

I have three tables like this:
**Users**
id
**Posts**
id
user_id
**Favorites**
id
user_id
post_id
Currently, I made it so when I query my posts for display, it pulls all the related user data who created the post with that row which is great! But what I'm trying to do now is also add to see if the user Authorized (Logged in) has favorited the post (row) so I can display to that they already favorited it. I don't want to re-query for every post (i think its called the N+1 problem?). I'm using Laravel4
Post model
class Post extends Eloquent{
public function user(){
return $this->belongsTo('User');
}
User model
public function posts(){
return $this->hasMany('Post');
}
PostsController
public function index()
{
$posts = Post::with('user')->paginate(25);
return View::make('index', compact('posts'));
}

Step 1. Add favorites relationship in Post model.
public function favorites() {
return $this->hasMany('Favorite');
}
When querying the Model.
$auth_user_id = Auth::user()->id;
$posts = Post::with(array('user', 'favorites' => function($query) use ($auth_user_id){
$query->where('user_id', '=', $auth_user_id);
}))->get();
For more information refer to the eager load constraints,
http://laravel.com/docs/eloquent#eager-loading

Adding a many-to-many relationship using the favorites table as pivot would be one approach.
Add favorites relationship in User model:
public function favorites() {
return $this->belongsToMany('Post', 'favorites');
}
You should then be able to get all favorites by simply accessing
Auth::user()->favorites
To find whether the current post is a favorite, use
$isFavorite = Auth::user()->favorites->has($post->id);

Related

Can I somehow also get the usernames of the people who have commented on an image if I only have their ids in my comments table

My comments table has the following columns:
id, user_id, image_id, comment
Currently I'm getting all comments that belong to a specific image like this:
$comments = Comment::where('image_id', $id)->get();
And then I can easily display the comments on the view to which I pass the $comments variable. However, I can only display the id of the user who has posted the comment but that wouldn't make much sense so I'm trying to display the username instead.
Since I don't save the username of the user who has posted a comment in the comments table, I can't access it from $comments as of now. Is there a way to somehow add an extra key-value pair to $comments that would contain the username of the user based on his id?
Comment model:
class Comment extends Model
{
public function images(){
return $this->belongsTo('App\Image');
}
public function users(){
return $this->belongsTo('App\User');
}
}
User model:
class User extends Model implements Authenticatable
{
public function comments(){
return $this->hasMany('App\Comment');
}
}
I guess that you should have a table/model for the User objects.
If so, you can Eager Load the relationship. To accomplish this, define the relationship in your model:
app/Comment.php
public function users()
{
return $this->belongsTo(User::class);
}
Note: given that this is the reverse of a hasMany relationship (belongsTo), you should name this functions in singular: a Comment belongs to a unique User.
Then in your controller:
$comments = Comment::with('users')->where('image_id', $id)->get();
This will include the user object inside every comment. Of course, you can limit the user attributes returned to the view but you get te idea.
To know more about this, check the documentation.
Make a Join similar to connect both tables!
$comments = DB::table('comment')
->join('user', 'comment.user_id', '=', 'user.id')
->select('comment.*', 'user.name')
->where(image_id, $id)
->get();
A related question with eloquent specifics
How to join three table by laravel eloquent model

Fetch multiple tables through hasManyThrough Laravel Eloquent

Database
I'm kind of new to databases and I made this small database, but I have problems fetching data from it.
Im trying to get all the racers from the logged in user, and it works properly, but if I enter $pigeons = $user->racer I only get back the racer table. I would like to know the attributes of the racers from the pigeons table aswell. I've made it work with query builder left joining the tables but I'm not sure why I set up this relationship if I can't use Laravel inner method.
In the User model I have these relationships:
public function pigeons(){
return $this->hasMany('App\Pigeon');
}
public function racers(){
return $this->hasManyThrough('App\Racer', 'App\Pigeon');
}
This is the Pigeon model:
public function user(){
return $this->belongsTo('App\User');
}
public function racer(){
return $this->hasMany('App\Racer');
}
}
And this is the Event model:
public function race(){
return $this->hasOne('App\Race');
}
public function racers(){
return $this->hasMany('App\Racer');
}
And this is what my EventsController looks like with the working alternative method and the commented not working.
public function upcoming(){
$id = auth()->user()->id;
$user = User::find($id);
$pigeons = DB::table('racers')->leftJoin('pigeons', 'racers.pigeon_id', '=', 'pigeons.id')->where('pigeons.user_id', '=', $id)->get();
//$pigeons = $user->racers;
return view('events.upcoming')->with('pigeons', $pigeons);
}
This is what I get with $user->racers or $user->racers()->get():
[{"id":1,"pigeon_id":14,"user_id":4,"event_id":1,"position":0,"created_at":null,"updated_at":null},{"id":2,"pigeon_id":15,"user_id":4,"event_id":1,"position":0,"created_at":null,"updated_at":null},{"id":3,"pigeon_id":16,"user_id":4,"event_id":1,"position":0,"created_at":null,"updated_at":null}]
And this is what I want to get, its not correct either since I should get id:1 but I want to pass to view these additional datas aswell like gender, color, ability (but they are in pigeons table not in racers).
[{"id":14,"pigeon_id":14,"user_id":4,"event_id":1,"position":0,"created_at":"2018-09-27 10:01:04","updated_at":"2018-09-27
10:01:04","gender":"hen","color":"blue","ability":38},{"id":15,"pigeon_id":15,"user_id":4,"event_id":1,"position":0,"created_at":"2018-09-27 10:01:04","updated_at":"2018-09-27
10:01:04","gender":"hen","color":"blue","ability":48},{"id":16,"pigeon_id":16,"user_id":4,"event_id":1,"position":0,"created_at":"2018-09-27 10:01:04","updated_at":"2018-09-27
10:01:04","gender":"cock","color":"blue","ability":11}]
To get the pigeons, what you would have to do is $pigeons = $user->racers()->get();. You can see an example of this in Laravel's official documentation https://laravel.com/docs/5.5/eloquent-relationships#introduction.

Using hasManyThrough in Relationship query

I have the following tables :
users
id|name|username
Areas
id|name
user_area
id|user_id|area_id
Buildings
id|name|area_id
In User models i want to call query that every users have his assigned areas and his assigned areas has many buildings, so i created a method in User model that query the user assigned buildings.
In App\User Model:
public function areas()
{
return $this->belongsToMany('App\Area','area_user');
}
public function UserBuildings(){
return $this>hasManyThrough('App\Building','App\Area','user_id','area_id');
}
In App\Area Model:
public function users(){
return $this->belongsToMany('App\User','area_user','area_id','user_id');
}
public function buildings(){
return $this->hasMany('App\Building');
}
In App\Building Model:
public function areas(){
$this->belongsTo('App\Area');
}
How can i structure a relationship method in User Model that get the user assigned buildings.
Thanks
You can't use hasManyThrough here, but you can use nested whereHas() to get all buildings assigned to authenticated user:
Building::whereHas('area', function ($q) {
$q->whereHas('users', function ($q) {
$q->where('id', auth()->id());
});
})->get();
Also, you should rename areas relationship to area in Building model, since each building belongs to only one area.

Laravel - How to chain Eloquent relationship - Eager Loading

I'm using Laravel 5.4, Laravel Roles from here and Eloquent relationships.
I'm trying to retrieve the users of a company along with their roles.
User::find(1)->roles gets me the user's roles whose id =1
Company::find(1)->users gets me all the users that belongs to the company whose id =1 (without the roles of users).
Company::find(1)->users->roles returns an error Property [roles] does not exist on this collection instance.
Questions
Is it possible to do what I want to do ?
If so, how should I do it ?
User.php
class User extends Authenticatable
{
use HasRoleAndPermission;
public function company()
{
return $this->belongsTo('App\Company');
}
public function user()
{
return $this->belongsTo(User::class);
}
}
HasRoleAndPermission.php
trait HasRoleAndPermission
{
public function roles()
{
return $this->belongsToMany(config('roles.models.role'));
}
}
Company.php
class Company extends Model
{
public function users() {
return $this->hasMany('App\User');
}
}
$company = Company::with('users.roles')->find(1);
Will load all the users, and all the roles for each user.
Update
According to your comment, you don't want the company data. Just users and roles Using eager loading and relationship existence.
$users = User::with('roles')
->whereHas('company' => function($query){
$query->where('name', '=', 'company'); //If you don't have the company ID
})->get();
Without relationship existence
$users = User::where('company_id', 1)->with('roles')->get();
1 company has many users.
1 users has many roles.
You are trying to get the roles of a collection of users (the property only exists for one user) thus, the property doesn't exists for the collection.
If you want to get all the roles of all users in the company, you might try the above code:
$roles = [];
Company::find(1)->users->foreach(function($user) {
$roles = array_merge($roles, $user->roles);
});
--------- edit ---------
For eager loading the roles of users, you must use with, as suggested by #Ohgodwhy, but I'd refactor a little:
$users = User::with('roles')->where('company_id', $companyId)->get();
Now you have the array of users eager loading their roles. You still can't access directly $users->roles, you must first get a user, only then get its roles.

Models relate in laravel 4

I hope you are well, I need your help, I am working with Laravel and I need to relate information, I have the User, TypeCost and CostCenter models where relationships are:
user:
hasMany ('TypeCost');
belongsTo ('CostCenter', 'id');
TypeCost:
belongsTo ('User');
CostCenter:
hasMany ('User');
I have my view index in the TypeCost module, there are loads information from the cost of each user, I need is that if the user logged belongs to CostCenter one simply show records of users who belong in CostCenter 1 and so CostCenter for the 2, 3, etc.
This is my Index method that is responsible for displaying the list of expenses:
public function index ()
{
$ type_costs = TypeCost :: paginate ();
return View :: make ('type_costs.index' compact ('type_costs'));
}
//for user model
public function costcenter()
{
$this->belongsTo('CostCenter');
}
//for costcenter model
public function users()
{
$this->hasMany('User');
}
//controller function
public function index ()
{
$cost_centers = Auth::user()->costcenter;
$cost_users = $cost_centers->users;
return View::make ('type_costs.index', compact ('cost_users'));
}
it will return list of users that belongs to CostCenter of logged user.
If the field of costcenter_id in user table is nullable, u can add some validation on controller.

Categories