I have the following table layout:
deals: - id - price products: - id - name deal_product: - id - deal_id - product_id metrics: - id - name metric_product: - id - metric_id - product_id - value
products
and metrics
have a many-to-many relationship with a pivot column of value.
deals
and products
also have a many-to-many relationship.
I can get metrics for a product with $product->metrics
, but I want to be able to get all metrics for all products related to a deal, so I could do something like this: $deal->metrics
.
I currently have the following in my Deal
model:
public function metrics() { $products = $this->products()->pluck('products.id')->all(); return Metric::whereHas('products', function (Builder $query) use ($products) { $query->whereIn('products.id', $products); }); }
But this doesn't return a relationship, so I cannot eager load it or get related models from it.
It needs to be in relationship format, because they need to be eager loaded for my use case.
Thanks for your help!
To avoid this problem, you can break the many-to-many relationship into two one-to-many relationships by using a third table, called a join table. Each record in a join table includes a match field that contains the value of the primary keys of the two tables it joins.
with() function is used to eager load in Laravel. Unless of using 2 or more separate queries to fetch data from the database , we can use it with() method after the first command. It provides a better user experience as we do not have to wait for a longer period of time in fetching data from the database.
A one-to-one polymorphic relationship is a situation where one model can belong to more than one type of model but on only one association. A typical example of this is featured images on a post and an avatar for a user. The only thing that changes however is how we get the associated model by using morphOne instead.
BelongsTo relationship in laravel is used to create the relation between two tables. belongsTo means create the relation one to one in inverse direction or its opposite of hasOne. For example if a user has a profile and we wanted to get profile with the user details then we can use belongsTo relationship.
If you want to have a custom relation, you can create your own extends to Relation abstract class. For example: BelongsToManyThought
.
But if you don't want to implement a Relation, I think that it can fulfill your needs :
In App\Deal.php, you can combine the solution of @thomas-van-der-veen
public function metrics() { return Metric ::join('metric_product', 'metric.id', '=', 'metric_product.metric_id') ->join('products', 'metric_product.product_id', '=', 'products.id') ->join('deal_product', 'products.id', '=', 'deal_product.product_id') ->join('deals', 'deal_product.deal_id', '=', 'deal.id') ->where('deal.id', $this->id); } // you can access to $deal->metrics and use eager loading public function getMetricsAttribute() { if (!$this->relationLoaded('products') || !$this->products->first()->relationLoaded('metrics')) { $this->load('products.metrics'); } return collect($this->products->lists('metrics'))->collapse()->unique(); }
You can refer to this post to see how you can simply use nested relations.
This solution can do the trick for querying relation with method and access to metrics attribute.
There is a Laravel 5.5 composer package that can perform multi-level relationships (deep)
Package: https://github.com/staudenmeir/eloquent-has-many-deep
Example:
User
→ belongs to many → Role
→ belongs to many → Permission
class User extends Model { use \Staudenmeir\EloquentHasManyDeep\HasRelationships; public function permissions() { return $this->hasManyDeep( 'App\Permission', ['role_user', 'App\Role', 'permission_role'], // Pivot tables/models starting from the Parent, which is the User ); } }
Example if foreign keys need to be defined:
https://github.com/staudenmeir/eloquent-has-many-deep/issues/7#issuecomment-431477943
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With