Design a specific situation in laravel ( many to many relationship) - laravel

I want to ask about a specific situation..
I have 3 models :
Store
Price
Product
I have to set a specific price for a store on a specific product..
for example :
if I have product A that costs 100$ , I want to set it as 50$ for store A , 80$ for Store B ...etc
what I did is I created many-many relationship between Store and Price
and I stored product_id in pivot table...
like below
Store.php
<?php
namespace App\Modules\Store\Models;
use App\Modules\Store\Models\Price;
class Store extends Model
{
public function prices()
{
return $this->belongsToMany(Price::class,'store_prices');
}
}
Price.php
<?php
namespace App\Modules\Store\Models;
use App\Modules\Store\Models\Store;
use Illuminate\Database\Eloquent\Model;
class Price extends Model
{
protected $fillable = ['price'];
public function stores()
{
return $this->belongsToMany(Store::class, 'store_prices');
}
}
StorePrice.php
<?php
namespace App\Modules\Store\Models;
use App\Modules\Product\Models\Product;
use App\Modules\Store\Models\Price;
use App\Modules\Store\Models\Store;
use Illuminate\Database\Eloquent\Model;
class StorePrice extends Model
{
protected $fillable = ['store_id', 'price_id', 'product_id'];
protected $table = 'store_prices';
public function store()
{
return $this->belongsTo(Store::class, 'store_id');
}
public function price()
{
return $this->belongsTo(Price::class, 'price_id');
}
public function product()
{
return $this->belongsTo(Product::class, 'product_id');
}
}
is this logically true ?
if it is , how can I group a price by product and show the related stores ?
otherwise I hope u can give maybe better propositions
Thanks in advance

You don't need StorePrice Model. You just modify one of two models and add withPivot('product_id') like this
return $this->belongsToMany(Store::class, 'store_prices')->witPivot('product_id');
Regard to grouping, you can make if as a normal query which joins three tables ( store, pice and pivot) then group results based on product_id

Related

Cannot establish relationship between two tables in Laravel

I want to create a relation between lising and attribute table in laravel for that i have used following code to establish relationship between them but the data in my view is not coming from both the tables. I'm getting following error:
Call to undefined relationship [adListAttributes] on model
[App\Models\AdListing].
Here listing can have as many attribute associated with and attributes
can be associated to many listings
ad_listings:
id
title
name
date
ad_list_attributes table :
id
listing_id
name
namespace App\Models;
use Eloquent;
use Illuminate\Database\Eloquent\Model;
class AdListAttribute extends Model
{
protected $table = "ad_list_attributes";
public function Listings()
{
return $this->belongsToMany('AdListing', 'id', 'listing_id');
}
}
namespace App\Models;
use Eloquent;
use Illuminate\Database\Eloquent\Model;
class AdListing extends Model
{
protected $table = "ad_listings";
public function Attributes()
{
return $this->belongsToMany('AdListAttribute', 'listing_id', 'id');
}
}
Problem is that you are using belongsToMany in both the models.This will cause a problem.
In AdListAttribute model,
public function listing_information()
{
return $this->belongsTo('App\AdListing', 'id', 'listing_id');
}
In AdListing model,
public function adlisting_attributes()
{
return $this->hasMany('App\AdListAttribute', 'listing_id', 'id');
}
You can get the results using,
$response = AdListing::get();
if($response->adlisting_attributes)
{
foreach($response->adlisting_attributes as $attribute)
{
echo $attribute->name;
}
}
Problem is that ur not calling the relationship with the right name i assume
$listings = AdListing::with('Attributes')->get();
Update :
Try this :
use App\Models\AdListAttribute;
//
return $this->belongsToMany(AdListAttribute::class, 'listing_id', 'id');
Same for other model, then try

How to add additional column relationship in pivot table in Laravel

Version: Laravel 5.4
I have 3 Models
Model: Employee
protected $fillable = ['name'];
public function emails(){
return $this->belongsToMany('App\Email')->using('App\EmailEmployee');
}
Model: Email
protected $fillable = ['username'];
public function employees(){
return $this->belongsToMany('App\Employee')->using('App\EmailEmployee');
}
Every Employee has many email access and emails allocates to many employees. But I have another column in email_employee table
email_id (emails table)
employee_id (employees table)
assigned_by (employees table)
how to make relation of assigned_by column with employees table
Pivot Model
use \Illuminate\Database\Eloquent\Relations\Pivot;
class EmailEmployee extends Pivot{
public function assignedBy(){
return $this->belongsTo('App\Employee');
}
}
I tried
$email = Email::find(1);
dd($email->employee[0]->pivot->assignedBy);
But not working
Custom Intermediate Table Model
To solve your problem, you should look to use the ->using() method on the belongsToMany method.
The subsection "Defining Custom Intermediate Table Models" in this link briefly describes this. eloquent-relationships#many-to-many
You basically create a model for the pivot table so that you can define additional relations to it.
You can still access data from Blade and Controllers the way you are now as Laravel will still deal with the relationship for you. However, you can access the pivot table with ->pivot and as you have told laravel to use a model for the pivot table, you can also access all the relationship defined functions from that model.
Example:
Employee
class Employee extends Model
{
protected $fillable = ['name'];
public function emails(){
return $this->belongsToMany('App\Email')
->using('App\PivotModel');
}
}
Email
class Email extends Model
{
protected $fillable = ['username'];
public function employees(){
return $this->belongsToMany('App\Employee')
->using('App\PivotModel');
}
}
PivotModel
class EmailEmployee extends Pivot
{
public function assignedBy(){
return $this->belongsTo('App\Employee','assigned_by');
}
}
Be Sure to extend Pivot on the pivot model and not Model
Now you can just do:
$user->emails()->first()->pivot->assignedBy
The reason for the ->first() is that you have a many to many, meaning that you will be getting a collection of emails assigned to the user. You would normally loop through them but for this example, simply selecting the first will do the same.
If you just want the column value and not the relationship value, then add ->withPivot('assigned_by') which will allow you to access the value directly.
If you are wanting to audit when the assignment was made, then you may also want to add ->withTimestamps() if your pivot table has timestamps included, so that you can access those too.
Changes in Pivot model
Pivot Model
use \Illuminate\Database\Eloquent\Relations\Pivot;
class EmailEmployee extends Pivot{
public function assignedBy(){
return $this->belongsTo('App\Employee','assigned_by');
}
}
You can use an custom pivot model
EmailEmployee
class EmailEmployee extends Pivot
{
public function giver()
{
return $this->belongsTo('App\Employee');
}
}
Employee
class Employee extends Model
{
public function emails(){
return $this->belongsToMany('App\Email')->using('App\EmailEmployee');
}
}
Email
class Email extends Model
{
public function employees()
{
return $this->belongsToMany('App\Employee')->using('App\EmailEmployee');
}
}
So you can access giver by $email->pivot->giver;

Eloquent one to many relationship not working

I'm stuck for hours with one of those issues where a fresh set of eyes might help. I just can't understand what's missing.
I'm connecting a model called User_ativo and defining two one-to-many relations to models Instituicao and Tipo_Ativo.
My database is simple.
Table user_ativo has columns "tipo_ativo_id" and "instituicao_id". I have a test row where both are set to 1. Both my tables instituicoes and tipo_ativos have only "id" and a string field "nome" (name). Both have a record with id == 1.
User_ativo.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User_ativo extends Model
{
public function tipo(){
return $this->belongsTo('App\Tipo_ativo');
}
public function instituicao(){
return $this->belongsTo('App\Instituicao');
}
}
Instituicao.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Instituicao extends Model
{
protected $table = 'instituicoes';
public function user_ativos(){
return $this->hasMany('App\User_ativo');
}
}
Tipo_ativo.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tipo_ativo extends Model
{
protected $table = 'tipo_ativos';
public function user_ativos(){
return $this->hasMany('App\User_ativo');
}
}
My controller method that fetches the date goes as follow:
public function index()
{
$ativos = User_ativo::with('tipo', 'instituicao')->get();
return view('ativos.index', compact('ativos'));
}
Now here's where it gets interesting, for some reason I can't figure out, when I echo the $ativos variable in my view I get this:
[{"id":1,"user_id":1,"instituicao_id":1,"tipo_ativo_id":1,"tipo":null,"instituicao":{"id":1,"nome":"Banco do Brasil"}}]
So, weirdly my relationship with the Instituicao model works, but the one with Tipo_ativo returns null.
I'm pretty confident someone will point out some dumb and obvious mistake in all of this, but I can't for the life of me understand why one works and the other doesn't since they're pretty much the same thing.
Your relationships names are not according to laravel convention.
Read below function and provide foreign_key and local_key/owner_key to your relationships then it will work
public function belongsTo($related, $foreignKey = null, $ownerKey = null, $relation = null){}
If we do not follow laravel convention while creating relationships then we have to tell it that these are the foreign and local keys that should be used.
Read more here
class User_ativo extends Model{
public function tipo(){
return $this->belongsTo('App\Tipo_ativo','user_ativo_id'); //second parameter is foreign_key_of_User_avito_table_here
}
public function instituicao(){
return $this->belongsTo('App\Instituicao','user_ativo_id'); //second parameter is foreign_key_of_User_avito_table_here
}
}
class Instituicao extends Model
{
protected $table = 'instituicoes';
public function user_ativos(){
return $this->hasMany('App\User_ativo','instituicao_id'); //second parameter is foreign key of Instituicao model
}
}
class Tipo_ativo extends Model
{
protected $table = 'tipo_ativos';
public function user_ativos(){
return $this->hasMany('App\User_ativo','tipo_ativo_id'); //second parameter is foreign key of Tipo_ativo model.
}
}

Laravel Polymorphic Many to Many relationship

I am very new to polymorphic relationships and am struggling on my first task. My real life scenario is complicated, so for the purpose of this question, I have simplified it a little.
I have a range of products. Each of these products can be 'tagged' to one or more "Categories", "Brand" and "Consumer". For example:
I figured with this setup, I would need a table for my polymorphic relationships as below:
I have created a new Taggable class which contains the following
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Taggable extends Model
{
public function taggable()
{
return $this->morphTo();
}
}
...and added a method to my Product class:
public function taggedCategories()
{
return $this->morphMany(Taggable::class, 'taggable');
}
Finally, in my ProductController, I am trying to retrieve all products with their relationships as such:
$products = Product::with('taggedCategories')
Whilst this isn't producing an error, there are no categories returned in my results. Looking at the SQL output in LaravelDebugBar, I see the following SQL.
select * from `taggables` where `taggables`.`taggable_id` in (1) and `taggables`.`taggable_type` = 'App\Models\Product'
This clearly is not right, but I cannot for love nor money figure out where I have gone wrong. I feel I am close, but not quite there.
Can anyone explain what is wrong? Also, would I need to do something different for getting the "Brand" as this is a one-to-many relationship, not many-to-many?
Thanks
Your model structure is going to be like:
class Categories extends Model
{
public function products()
{
return $this->morphToMany('App\Tag', 'productable');
}
}
class Brand extends Model
{
public function products()
{
return $this->morphToMany('App\Tag', 'productable');
}
}
// and Consumers, ....
User Model:
class Product extends Model
{
public function categories()
{
return $this->morphedByMany('App\Categories', 'productable');
}
public function brands()
{
return $this->morphedByMany('App\Brunds', 'productable');
}
}
Database schema:
categories
id - integer
...
brands
id - integer
...
consumer
id - integer
...
productable
product_id - integer
productable_id - integer
productable_type - string
Now, you can retrieve the relations:
$categories = App\Categories::find(1);
// retrieve product of a type
foreach ($categories->products as $product) {
//
}
$product = App\Product::find(1);
// retrieve categories of a product
foreach ($product->categories as $categories) {
//
}
Actually, your type product (categories, brands, consumers) are productable.

how to make join query between three tables in laravel

I want to build a query in laravel between three tables (regions, countries, packages) such that table are related together.
regions table contains (id, name, description)
countries table contains (id, region_id, name, description)
packages table contains (id, county_id, pkg_title, pkg_description, price)
I want to select all packages where region_id=1
how can I make query for this situation in laravel query builder. please help me about this question
Set your models as follows.
class Region extends Model
{
}
class Country extends Model
{
public function region()
{
return $this->belongsTo(Region::class);
}
}
class Package extends Model
{
public function country()
{
return $this->belongsTo(Country::class);
}
}
And state following query inside your method.
$region_id = 1;
$PackageWithRegions = Package::with([
'country' => function ($county) use ($region_id) {
return $county->with([
'region' => function ($region) use ($region_id) {
return $region->where('id', $region_id);
}
]);
}
])->get();
// $PackageWithRegions is a collection of packeges with regions where regiion_id = 1
More on eloquent relationships
You can use Eloquent model relationship to prform this, like below
In region controller file
$region = Region::where(['id'=>1])->with(['country'])->get(); ///fetch region with country calls relation declared in region model
In Region.php model
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Region extends Model {
protected $table = 'regions';
public function country(){
return $this->hasOne('App\Models\Country','region_id')->with(['packages']); ///this will fetch country with all pacckages on matching region_id, join of package with country is declared in country model.
}
}
In Country.php model
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Country extends Model {
protected $table = 'countries';
public function packages(){
return $this->hasMany('App\Models\Package','county_id'); //join of country with packages on county_id
}
}
In Package.php model
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Package extends Model {
protected $table = 'packages';
}
You can see in Laravel doc (https://laravel.com/docs/4.2/eloquent) in section Has Many Through that if you have a model like:
countries
id - integer
name - string
users
id - integer
country_id - integer
name - string
posts
id - integer
user_id - integer
title - string
Then you can access to last relation in this way:
class Country extends Eloquent {
public function posts()
{
return $this->hasManyThrough('Post', 'User');
}
}
Or using customs relations IDs:
class Country extends Eloquent {
public function posts()
{
return $this->hasManyThrough('Post', 'User', 'country_id', 'user_id');
}
}
So, you can access to the posts of a country:
$posts = Country::get(2)->posts;
// with where:
$posts = Country::where('name', '=', 'USA')->get()->posts;

Resources