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

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.

Related

How to get data from three models that are related to each other in Laravel 5.8

So I have this model Order which has one to many relation with ProductOrder model. And also Product model which has the same one to many relation with ProductOrder model. I can get the PorductOrder data with Product or with Order. Like this:
Order::with('product_orders')->get();
Now this is returning my orders with the associated ProductOrder data. How can I include the Products of each ProductOrder data in this collection?
Make changes of function name, field name, model name as per you requirements
Step 1:
In you ProductOrder Model use this function:
public function products()
{
return $this->hasOne('App\Product', 'id', 'product_id');
}
Step 2:
After this in you query you can use as:
Order::with('product_orders.products')->get();
It sounds like ProductOrder is just a joining table/model, is that right? If that is the case, you should change to a ManyToMany relationship to of the Products model to
public function orders()
{
return $this->belongsToMany('App\Orders', 'product_order');
}
and the Orders to
public function products()
{
return $this->belongsToMany('App\Products', 'product_order');
}
Then you can access like
Order::find(1)->products()->get();

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

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

Resources