Laravel getting data from a deep relationship - laravel

I have 3 tables:
Users
Baskets
Items
id
id
id
user_id
basket_id
price
I'm trying setup a relationship in eloquent by which I can get all the all the Items and the corresponding Baskets where the price of items is X. I want it so that I can simply use $user->items(x) and get the results.
I'm unsure if this can be done using Relationships alone or will I have to resort to writing custom queries.
Any, and all, help and guidance will be appreciated!

The relationship you are looking for is hasManyThrough
https://laravel.com/docs/7.x/eloquent-relationships#has-many-through
User Modal
public function items()
{
return $this->hasManyThrough(Item::class, Bucket::class);
}
The way you want to use is not possible to achieve I think.
Possible Usage
$user->items()->where('price', x);
of if you define custom scopes
Item Modal
public function scopeWherePrice($query, $value)
{
return $query->where('price', $value);
}
Usage
$user->items()->wherePrice(x);
EDIT
If you really want to write a code like $user->items(x) you can define a method on the User Modal.
Note that this is not a relationship, just another method which fetch the result.
User Modal
public function items($price)
{
return this->items()->where('price', $price)->get();
}

Using hasManyThrough Define the relationship in your models:
User Model
/**
* Get all of the items & baskets for the user.
*/
public function items($price)
{
return $this->hasManyThrough('App\Items', 'App\Baskets')
->with('basket')
->where('price',$price);
}
Basket Model
/**
* Get the Items's Basket.
*/
public function basket()
{
return $this->belongsTo('App\Basket','basket_id');
}
And then call it like this:
$user->items(x);
This will return all user items with their corresponding baskets in a specific price.

Related

Custom hasMany relationship query with select()

Each company on my app can store its own events.
A company and its events are related though the following hasMany relationship:
/**
* The events that belong to the company.
*/
public function events()
{
return $this->hasMany('App\Event');
}
To list a company's events, I use:
Auth::user()->company->events
Since each event stores, a lot of data that I don't need when I query the hasMany, I would like to customize the relationship to only select the id and name columns instead of the whole row.
My hasMany relationship query would be something like
DB::table('events')->where('company_id', Auth::id())->select('id', 'name')->get();
How do I take the collection returned from this result and use it as the query for my hasMany relationship, which will then correctly return a collection of event instances?
Add the filter inside your events method like :
public function events()
{
return $this->hasMany('App\Event')->select('id', 'company_id', 'name');
}
Then call it like:
Auth::user()->company->events
Important update: 'company_id' is necessary for company->events link, otherwise 'events' relationship always returns empty array
How about
Auth::user()->company()->with('events:id,name')->get();
https://laravel.com/docs/5.8/eloquent-relationships#eager-loading
Go to Eager Loading Specific Columns

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

Laravel 5 Eloquent Realtionship has one through

I have the following database structure
products quesionnaires questionnaire_results
-------- -------------- ----------------------
id id id
questionnaire_id questionnaire_id
product_id
A Questionnaire can be used for multiple products, and store results for each product, apart, in questionnaire_results table.
A product can have only one questionnaire and only one result of its questionnaire.
I need a way to get from Product Model the result of its Questionnaire.
If you do not have a QuestionnaireResult model then there is no straightforward Eloquent relationship for this, as all of the default relationships rely on the existence of an Eloquent model. However, there is a fairly clean way to accomplish this by treating it as a Many to Many relationship between Product and Questionnaire and treating questionnaire_results as your pivot table (even thought you really know that a product will only ever belong to one Questionnaire).
Product Model:
public function questionnaire() {
return $this->belongsToMany('App\Questionnaire', 'questionnaire_results');
}
Questionnaire Model:
public function products() {
return $this->belongsToMany('App\Product', 'questionnaire_results');
}
As this relation will return a collection, you need to either access the first array with [0] or use the first() method.
$product->questionnaire()->first();
However, if you do have a QuestionnaireResult model then you have a very straightforward One to One relationship with no need to go through another model. You have some questionnaire results that belong to a product, while a product can only have one set of questionnaire results (according to your post info).
Product Model:
public function questionnaireResult() {
return $this->hasOne('App\QuestionnaireResult');
}
Questionnaire Result Model:
public function product() {
return $this->belongsTo('App\Product');
}
// Product Model
public function quesionnaire() {
return $this->hasOne("App\Quesionnaire");
}
// Quesionnaire Model
public function questionnaire_result() {
return $this->hasOne("App\Questionnaire_result");
}
$product->quesionnaire->questionnaire_result

Laravel - Pivot table for three models - how to insert related models?

I have three models with Many to Many relationships: User, Activity, Product.
The tables look like id, name. And in the each model there are functions, for example, in User model:
public function activities()
{
return $this->belongsToMany('Activity');
}
public function products()
{
return $this->belongsToMany('Product');
}
The pivot table User_activity_product is:
id, user_id, activity_id, product_id. The goal is to get data like: User->activity->products.
Is it possible to organize such relations in this way? And how to update this pivot table?
First I suggest you rename the pivot table to activity_product_user so it complies with Eloquent naming convention what makes the life easier (and my example will use that name).
You need to define the relations like this:
// User model
public function activities()
{
return $this->belongsToMany('Activity', 'activity_product_user');
}
public function products()
{
return $this->belongsToMany('Product', 'activity_product_user');
}
Then you can fetch related models:
$user->activities; // collection of Activity models
$user->activities->find($id); // Activity model fetched from the collection
$user->activities()->find($id); // Activity model fetched from the db
$user->activities->find($id)->products; // collection of Product models related to given Activity
// but not necessarily related in any way to the User
$user->activities->find($id)->products()->wherePivot('user_id', $user->id)->get();
// collection of Product models related to both Activity and User
You can simplify working with such relation by setting up custom Pivot model, helper relation for the last line etc.
For attaching the easiest way should be passing the 3rd key as a parameter like this:
$user->activities()->attach($activityIdOrModel, ['product_id' => $productId]);
So it requires some additional code to make it perfect, but it's feasible.
The solution was found with some changes.
In the models relationships look like:
// User model
public function activities()
{
return $this->belongsToMany('Activity', 'user_activity_product', 'user_id', 'activity_id')->withPivot('product_id');
}
public function products()
{
return $this->belongsToMany('Product', 'user_activity_product', 'user_id', 'product_id')->withPivot('activity_id');
}
To update pivot table:
$user->products()->save($product, array('activity_id' => $activity->id));
- where product and activity ids I get from Input.
And, for example, to check if "user -> some activity -> some product is already exists":
if ($company->activities->find($activity_id)->products()->where('product_id', '=', $product_id)->wherePivot('company_id', $company_id)->get()->count() > 0) {
// code...
}
I think it needs improvements but it works for me now.

Resources