access relation inside hasMany relation - laravel

I have a model request.php has this relation :
public function requestItems(): HasMany
{
return $this->hasMany(RequestItemd::class, 'request_id', 'id');
}
inside this relation there is another relation
public function item()
{
return $this->belongsTo(Item::class, 'item_id', 'id');
}
how to reach to belongsTo relation and retrieve data through the original hasMany relation?

You will need to loop over your items or get the individual item, something like this:
$requestItemsQuery->each(function($reqestItmId) {
$item = $reqestItmId->item;
});
there are a few other ways of doing this though, so if you share how you are planning to use the reference i might be able to give a better answer

Related

Laravel nested `hasOne` relationship with `where` clause

I have Shop model which has multiple Content entries:
public function contents(): HasMany
{
return $this->hasMany(Content::class);
}
And I had hasOne relationship with one specific type of content like this:
public function widgetContent(): HasOne
{
return $this->hasOne(Content::class)->where('type', Content::WIDGET);
}
It was working fine but I moved Content's type into a new model called ContentType, and removed the type field from Content model, but instead added another hasOne relationship via content_type_id field.
Now, I'm trying to achieve the same widgetContent relationship but I can't. Here's my code:
public function widgetContent(): HasOne
{
return $this
->hasOne(Content::class)
->whereHas('contentType', fn ($q) => $q->where('type', ContentType::WIDGET));
}
What should I do to achieve this? Also, if this is not the best practice (that's how I feel), what is the best practice?
You could create a closure and use that in stead. So you would still have the relationship like this:
public function content(): HasOne
{
return $this
->hasOne(Content::class);
}
But then you add a closure in your model:
public function getWidgetContent()
{
return $this->content()->whereHas('contentType', function(Builder $q){
$q->where('type', ContentType::WIDGET)
})->get();
}
And then you just call the closure function when you need the results.

Eloquent Relationship on the same model

I am using the User model and want to reference other users on a One to Many relationship.
With two models, this would be done by a Many to Many but this attempt at it is obviously wrong:
public function relatedUsers()
{
return $this->belongsToMany(User::class, 'related_user', 'user_id', 'user_id');
}
Is there a better way I can achieve my goal? I don't need an inverse method.
You can use hasMany() or belongsTo() (according to your need) relation for same model relationship
Define hasMany relationship in User model:
public function relatedUsers() {
return $this->hasMany('User','user_id');
}
Example:
Consider you have one User object
$user = User::where('id',$id)->first();
If you want to access related records
$related_users = $user->relatedUsers; // this will return all related users for particular object

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 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

I can't make some Eloquent relations to work

Let me first explain the relations of my table, and then I will explain what I cannot do.
So, I have an entity called "Company" it has many "Incomes" which has many "IncomeUnitSale" which has one "IncomeUnitSaleUnitPrice"
Company 1->* Income 1->* IncomeUnitSale 1->1 IncomeUnitSaleUnitPrice
Models:
Company Model
public function Income(){
return $this->hasMany('App\Income');
}
Income Model (table has "company_id")
public function Company(){
return $this->belongsTo('App\Company');
}
public function IncomeUnitSale(){
return $this->hasMany('App\IncomeUnitSale');
}
IncomeUnitSale Model (table has "income_id")
public function Income(){
return $this->belongsTo('App\Income');
}
public function IncomeUnitSaleUnitPrice(){
return $this->hasOne('App\IncomeUnitSaleUnitPrice');
}
IncomeUnitSaleUnitPrice (table has "income_unit_sale_id")
public function IncomeUnitSale(){
return $this->belongsTo('App\IncomeUnitSale');
}
What I am trying to do is the following:
$company = Company::where("id","=",1)->first();
$company->Income->IncomeUnitSale->IncomeUnitSaleUnitPrice
But It says its null, it works till $company->Income->IncomeUnitSale but after that doest't show any relation.
Can somebody please tell me what I am doing wrong?
Thank you!
hasMany relationships will always return an Eloquent Collection object. If there are no related records, it will just be an empty Collection. hasOne and belongsTo relationships will always return either the related Model, or null if there is no related model.
Because some of your relationships are hasMany, you have to iterate the returned Collection to be able to go further. So, instead of $company->Income->IncomeUnitSale->IncomeUnitSaleUnitPrice, you have to:
foreach($company->Income as $income) {
foreach($income->IncomeUnitSale as $sale) {
echo $sale->IncomeUnitSaleUnitPrice->price;
}
}

Resources