Query using two different relation laravel - laravel

I have relations like : a secteur has many sections, a section has many users, so a user belongs to a section and a section belongs to a secteur.
In Secteur model
public function sections()
{
return $this->hasMany(Section::class,'secteur_id');
}
In Section model
public function users()
{
return $this->hasMany(User::class,'section_id');
}
public function secteur()
{
return $this->belongsTo(Secteur::class,'secteur_id');
}
In User model
public function section()
{
return $this->belongsTo(Section::class,'section_id');
}
Now i'm trying to get all the users who belongs to a secteur, for that i need to retrieve all sections from the secteur and all users who belongs to all sections i've got.
I don't know how to do that.
ps:Sorry for my english i'm french

Eloquent has a hasManyThrough relationship which may be what you want.
On secteur, you can add this:
public function users()
{
return $this->hasManyThrough(User::class, Section::class);
}
As the docs state:
"The first argument passed to the hasManyThrough method is the name of
the final model we wish to access, while the second argument is the
name of the intermediate model."
You can also pass keys as additional arguments if you need to, but the ones you're using above look like the defaults and if they are you can omit them.

Related

How to define multiple belongsTo in laravel

My table has many foreign key for example prefecture_id, gender_id and status_id.
And I made model for those table.
So I want to define multiple belongsTo method like following for get all data with query builder..
But In fact belongsTo can't use like this.
public function foreign(){
return $this->belongsTo([
'App/Prefecture',
'App/Gender',
'App/Status',
]
}
And if the only way is defining multiple method for belongs to.
How do I get all belongstos data in querybuilder.
Please give me advice.
As far as I am aware, there's not a way to get multiple belongsTo from a single method. What you have to do is make one method for each relationship and when you want to load the relationships you can do the following.
Model
public function prefecture()
{
return $this->belongsTo(\App\Prefecture::class);
}
public function gender()
{
return $this->belongsTo(\App\Gender::class);
}
public function status()
{
return $this->belongsTo(\App\Status::class);
}
Query
// This will get your model with all of the belongs to relationships.
$results = Model::query()->with(['prefecture', 'gender', 'status'])->get();

laravel hide result for all relations if column has specific value

Lets assume I have a table posts with the fields id and content and published.
A User can have multiple posts, and a post can belong to multiple pages and there might be a lot more relations to a post.
Lets say we have an admin that wants to moderate the posts, the posts should only be visible if approved. So I add the boolean published where posts that are not published 0 should never be visible (only in specific cases e.g. to moderate the post).
Is it possible to set something in the Post model to restrict the related models from loading non published posts.
I want to avoid that I have to filter in the relation, e.g. if I call $user->posts I do not want to check if the posts are published, the non published results should not be available only if i do a search like. Post::where('published','0'). Basically something like softdeletes but than with a custom field.
An example, where the opposite relations are also defined, to make it easier to understand would be:
class Post extends Model
{
use SoftDeletes;
protected $table = 'posts';
public function collection()
{
return $this->belongsTo('App\Collection');
}
public function style()
{
return $this->belongsTo('App\Style');
}
public function pictures()
{
return $this->hasMany('App\Picture')->orderBy('priority', 'asc');
}
public function user()
{
return $this->belongsTo('App\User');
}
}
You can use global query scope in the Model as below to add your desired filters to each query, like below:
// Post.php
class Post extend Model
{
protected static function booted()
{
static::addGlobalScope('published', function (Builder $builder) {
$builder->where('published', true);
});
}
// ...
}
Whenever you don't want to apply the global query scope, use withoutGlobalScope with the name of the query scope, like below:
Post::withoutGlobalScope('published')->get();

Laravel hasManyThrough with ManyToMany pivot

I am making a game and I have users which have facilities and for this I use ManyToMany
user_facilities
-user_id
-facility_id
But each relation must have a facility level, so I've added facility_levels table and each of this levels must be connected to the ManyToMany relation. So user_facilities now looks like this
user_facilities
-user_id
-facility_id
-level_id
level_id is the connections between the facility which the user owns and which level it is.
My question is how do I connect this in the models?
The User model now has this
public function facilities()
{
return $this->belongsToMany('App\Facility', 'user_facilities');
}
And Facility
public function users()
{
return $this->belongsToMany('App\User', 'user_facilities');
}
So how do I get the level of the facility which the user owns?
In blade I hope there is a way I can use something like
{{ $user->facility->level->property }}
level is part of the user_facilities table not of facility
Therefore, you should be able to access the level_id from the many to many relationship of user and facility
One thing you can do is to access the immediate table (also called pivot table).
First, edit your relationship to include the extra attributes.
public function facilities()
{
return $this->belongsToMany('App\Facility', 'user_facilities')
->withPivot('level_id');
}
public function users()
{ // if you omit this EDIT/UPDATE, you cannot do this:
// $facility->users()->first()->pivot->level_id;
return $this->belongsToMany('App\User', 'user_facilities')
->withPivot('level_id');
}
Take note that when accessing a many to many relationship, Laravel will immediately assign a pivot attribute onto the result which contains details about the pivot table of the two models
Now try accessing the extra column:
$facility = $user->facilities->first();
$level_id = $facility->pivot->level_id;
// now you can use $level_id for finding the level.
$level = Level::find($level_id);
Now, since you can do that, you can also create a model for the many to many relationship of user and facility that will have that property of level_id
Let's create a new model called UserFacility that will extend Pivot.
This will be your Pivot model for many to many relationship of user and facilities.
use Illuminate\Database\Eloquent\Relations\Pivot;
class UserFacility extends Pivot
{
}
Then update your users and facilities relationships as follows.
public function facilities()
{
return $this->belongsToMany('App\Facility', 'user_facilities')
->using('App\UserFacility');
}
public function users()
{
return $this->belongsToMany('App\User', 'user_facilities')
->using('App\UserFacility');
}
Notice that using method.
$userfac = $users->facilities->pivot; // <-- pivot will now be an instance of App\UserFacility
echo $userfac->level_id;
Lastly,
If you don't want the pivot attribute name, you can change it using the as method, chain it after the belongsToMany method, like this:
public function users()
{
return $this->belongsToMany('App\User', 'user_facilities')
->as('UFac')
->using('App\UserFacility');
}
$userfac = $users->facilities->UFac; // <-- you can now access the pivot table using the property `UFac`
echo $userfac->level_id;
It may also be possible that your pivot table has a relationship with a level since it has a level_id. Don't worry, it's possible, just add this function in your UserFacility model.
public function level()
{
return $this->belongsTo('App\Level');
}
Now you can do this!
$user->facilities->first()->UFac->level; // <-- this will be an instance of App\Level
source: https://laravel.com/docs/5.5/eloquent-relationships#many-to-many

user_id in other table does not get value in one to many relation in laravel

In restaurant table, foreign key do not get value of user table. I make relation one to many in user and restaurant tables. user can have many restaurants.
class Restaurant extends Model
{
protected $guarded=['user_id'];
protected $table ="rest_info";
public function menus() {
return $this->hasMany('App\Menu');
}
public function dishes(){
return $this->morphMany('App\Dish','dishable');
}
public function user(){
return $this->belongsTo('App\User','id','user_id');
}
}
If you wish to access these relationship with in your controller function you can use with keyword of laravel you have to something like this:-
If you wish to get the menus you can use something like this in your contoller Function
$getResturantdata = Resturant::with('menus')->get();
dd($getResturantdata);
If you wish to get the menus and users both you can use something like this in your contoller Function:-
$getResturantdata = Resturant::with('menus','users')->get();
dd($getResturantdata);

Returning counts of a relationship model in Laravel

I have a model for user and annotations along with a pivot table user_like for storing annotations liked by user. The annotation table is also associated with another model (ranges) through hasMany relationship. I am trying to return all annotations along with its user, ranges and total number of likes.
The code below works for user, ranges and even likes. But, I am only interested in returning the count of likes and not the actual values (i.e. list of users liking the annotation). Is there a way to include just the counts for one of the models from the relations?
Eloquent query:
$annotations = Annotation::with('ranges')
->with('likes')
->with('author')
->where('document_id', $docid)->get()->toArray();
The model:
class Annotation extends Eloquent {
public function ranges()
{
return $this->hasMany('Range');
}
public function author()
{
return $this->belongsTo('User', 'user_id');
}
public function likes()
{
return $this->belongsToMany('User', 'annotation_like');
}
public function countOfLikes()
{
return $this->likes()->count();
}
}
If you want to retrieve count for multiple annotations using eager loading then you need the following 'helper' relation setup:
public function countLikesRelation()
{
return $this->belongsTo('User','annonation_like')->selectRaw('annotation_like, count(*) as count')->groupBy('annotation_like');
}
// then you can access it as such:
$annotations= Annotation::with('countLikesRelation')->get();
$annotations->first()->countLikesRelation->count;
// to make it easier, we create an accessor to the count attribute
public function getLikesCountAttribute()
{
return $this->countLikesRelation->count;
}
//And then, simply use
$annotations->first()->sectionsCount;

Resources