I've a relation on a pivot table; how I can expand It?
For example:
shops:
id
name
products:
id
name
product_shop:
product_id
shop_id
field_1
field_2
field_3
table_A_id
table_A:
id
name
The relation Many-to-Many in the Shops Model is:
class Shops extends Model {
public function products()
{
return $this->belongsToMany('Products', 'product_shop', 'product_id', 'shop_id')->withPivot(
'field_1',
'field_3',
'field_3',
'table_A_id'
)
->as('product_shop')
->withTimestamps();
}
}
and the query to retrieve all data is:
class GetData extends Model {
public static function getAll() {
$query = Shops::with(
'products'
)->get();
}
}
This return the product_shop.table_A_id but I'd like to expand the foreign key and retrieve table_A.name; is there a way?
Thank you.
You can use a pivot model:
class ProductShopPivot extends \Illuminate\Database\Eloquent\Relations\Pivot
{
public function tableA()
{
return $this->belongsTo(TableA::class);
}
}
class Shops extends Model
{
public function products()
{
return $this->belongsToMany('Products', 'product_shop', 'product_id', 'shop_id')
->withPivot(
'field_1',
'field_3',
'field_3',
'table_A_id'
)
->as('product_shop')
->withTimestamps()
->using(ProductShopPivot::class);
}
}
Then access it like this:
$shop->product_shop->tableA->name
Unfortunately, there is no way to eager load the tableA relation.
Related
I am trying to make 3 tables relationship like this,
users
id
name
roles
id
name
companies
id
name
company_role_user
user_id
role_id
company_id
Relationships in User.php model
public function companies() {
return $this->belongsToMany(Company::class, 'company_role_user', 'user_id', 'company_id');
}
public function roles() {
return $this->belongsToMany(Role::class, 'company_role_user', 'user_id', 'role_id');
}
public function role() {
// relationship to get role of specific company
}
Relationships in Company.php model
public function users() {
return $this->belongsToMany(User::class, 'company_role_user', 'company_id', 'user_id');
}
public function roles() {
return $this->belongsToMany(Role::class, 'company_role_user', 'company_id', 'role_id');
}
public function role() {
// relationship to get role of specific user
}
I want to get user role for specific company like this
User::find(1)->companies[0]->role->name
or
Company::find(1)->users[0]->role->name
If you have users
users
– id
– name
and you want them to have many to many relation with companies, you should do:
companies
– id
– name
user_companies
– user_id
– company_id
And for your roles, (many to many) you can do the same:
roles
- id
- name
user_roles
- user_id
- role_id
You are trying to make many to many 3 tables, when you should be doing it with 2 tables.
Even if you manage, it would be very complicated and confusing.
You should consider which tables should be related to roles, companies should have roles, or users should have roles, you dont need them both to have roles
Your schema looks correct but your model definitions/relations can use a junction/pivot model CompanyRoleUser which will relate these 3 relations as many-to-one/belongsTo and one-to-many/hasMany from Company/Role/User.
class Company extends Model
{
public function companyRoleUser()
{
return $this->hasMany(CompanyRoleUser::class, 'id', 'company_id');
}
}
class Role extends Model
{
public function companyRoleUser()
{
return $this->hasMany(CompanyRoleUser::class, 'id', 'role_id');
}
}
class User extends Model
{
public function companyRoleUser()
{
return $this->hasMany(CompanyRoleUser::class, 'id', 'user_id');
}
}
class CompanyRoleUser extends Model
{
public function company()
{
return $this->belongsTo(Discipline::class, 'id', 'company_id');
}
public function role()
{
return $this->belongsTo(Speciality::class, 'id', 'role_id');
}
public function user()
{
return $this->belongsTo(User::class ,'id','user_id');
}
}
Now you can apply different type of filters for your data like
Fetch users for company A id = 1 with admin role id = 2
User::whereHas('companyRoleUser.company', function ($query) use ($company_id) {
$query->where('id', $company_id);
})->whereHas('companyRoleUser.role', function ($query) use ($role_id) {
$query->where('id', $role_id);
});
Or
User::whereHas('companyRoleUser', function ($query) use ($company_id) {
$query->where('company_id', $company_id)
->where('role_id', $role_id);
});
Fetch companies with $user_id and $role_id
Company::whereHas('companyRoleUser', function ($query) use ($user_id) {
$query->where('user_id', $user_id)
->where('role_id', $role_id);
});
I have 3 tables with this order:
School it has -> id
SchoolSemester it has -> school_id
SemesterClass it has -> semester_id
Now I am trying to make relation between School and SemesterClass in order to get list of classes of each school as well as name of schools in each class.
based on documentation i have this relationships:
school model
class School extends Model
{
public function semesters() {
return $this->hasMany(SchoolSemester::class);
}
public function classes() {
return $this->hasManyThrough(SemesterClass::class, SchoolSemester::class);
}
}
SchoolSemester model
class SchoolSemester extends Model
{
public function school() {
return $this->belongsTo(School::class);
}
public function classes() {
return $this->hasMany(SemesterClass::class, 'semester_id', 'id');
}
}
SemesterClass model
class SemesterClass extends Model
{
public function school() {
return $this->hasOneThrough(School::class, SchoolSemester::class, 'school_id', 'id');
}
public function semester() {
return $this->belongsTo(SchoolSemester::class, 'semester_id', 'id');
}
}
Controller
public function show($id)
{
$class = SemesterClass::with(['school', 'teacher', 'teacher.user', 'students'])->findOrFail($id);
dd($class);
//return view('admin.Classes.show', compact('class'));
}
Results
Any idea?
Your intermediate table is school_semester, laravel will find the foreign_key school_semester_id by default, however, your foreign_key is semester_id, so you need to specify the foreign_key in hasManyThrough:
public function classes() {
return $this->hasManyThrough(
SemesterClass::class,
SchoolSemester::class
'school_id', // Foreign key on school_semesters table...
'semester_id', // Foreign key on classes table...
'id', // Local key on schools table...
'id' // Local key on school_semesters table...
);
}
And change your hasOneThrough code like this:
public function school() {
return $this->hasOneThrough(
School::class,
SchoolSemester::class,
'id',
'id',
'semester_id',
'school_id' );
}
Another Solution:
Because the reverse is just the concatenation of two BelongsTo relationships, so you can just put the belongsTo in SchoolSemester and School Model.
And get the relationship like this:
SemesterClass::with(['semester.school'])
Or you can define a mutator in SemesterClass Model:
protected $appends = ['school'];
public function getSchoolAttribute() {
return $this->semester->school;
}
I have 5 tables.
Users
Categories
Products
Product_categories
Order Details
A user purchases an an item and in my order details table I store the quantities etc.
I wanted to return all items that are of the main category = 'Testing' via the user.
$user = Auth::user();
return $user->items();
I have the following relationship on my user model.
public function items()
{
return $this->hasMany('App\OrderDetail','user_id')->selectRaw('item_description,count(quantity) as count')->where('item_description','<>','Carriage')->groupBy('item_id')->get();
}
I know I've not associated the the categories table here but I'm wondering how I would pull all the users order details where item category is "testing". The item can be related to many categories hence the product_categories table.
I'm not after someone writing the answer I'd like to know where I start to look at linking these via the model?
Would I be right in saying I have to do a function within my model relation?
According to your requirements & structure, your table should be structured like this:
users
id
name
...
categories
id
name
...
products
id
name
cost
...
category_product
id
category_id
product_id
order_details
id
user_id
cost
...
product_order_detail
id
product_id
order_detail_id
Your models should be structured like this:
class User extends Model
{
public function orderDetails()
{
return $this->hasMany(OrderDetail::class);
}
}
class Product extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class, 'category_product');
}
public function orderDetails()
{
return $this->belongsToMany(Order::class, 'product_order_detail');
}
}
class Category extends Model
{
public function product()
{
return $this->belongsToMany(Product::class, 'category_product');
}
}
class OrderDetail extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
public function products()
{
return $this->belongsToMany(Product::class, 'product_order_detail');
}
}
and to fetch all the items / products who belongs to the category named Testing and belongs to the user, who've ordered it:
$items = Product::whereHas('categories', function($q) {
$q->where('name', '=', 'Testing');
})->whereHas('orderDetails', function($q) use($user) {
$q->whereHas('user', function($q) use($user) {
$q->where('id', $user->id);
});
})->get();
Hope this helps!
I have the following tables:
Customer
id
Order
id
customer_id
Order_notes
order_id
note_id
Notes
id
If I want to get all order notes for a customer so I can do the following, how can I do it? Is there way to define a relationship in my model that goes through multiple pivot tables to join a customer to order notes?
#if($customer->order_notes->count() > 0)
#foreach($customer->order_notes as $note)
// output note
#endforeach
#endif
Create these relationships on your models.
class Customer extends Model
{
public function orders()
{
return $this->hasMany(Order::class);
}
public function order_notes()
{
// have not tried this yet
// but I believe this is what you wanted
return $this->hasManyThrough(Note::class, Order::class, 'customer_id', 'id');
}
}
class Order extends Model
{
public function notes()
{
return $this->belongsToMany(Note::class, 'order_notes', 'order_id', 'note_id');
}
}
class Note extends Model
{
}
You can get the relationships using this query:
$customer = Customer::with('orders.notes')->find(1);
What about 'belongsToMany' ?
E.g. something like
$customer->belongsToMany('OrderNote', 'orders', 'customer_id', 'id');
Of course, it'll not work directly, if you want to get order object also (but maybe you can use withPivot)
In the end I just did the following:
class Customer extends Model
{
public function order_notes()
{
return $this->hasManyThrough('App\Order_note', 'App\Order');
}
}
class Order_note extends Model
{
public function order()
{
return $this->belongsTo('App\Order');
}
public function note()
{
return $this->belongsTo('App\Note')->orderBy('notes.id','desc');
}
}
Then access the notes like so:
#foreach($customer->order_notes as $note)
echo $note->note->text;
#endforeach
I have three tables: users, items and user_items. A user has many items and a item belongs to many users.
**Users**
id
username
password
**Items**
id
name
**User_items**
id
user_id
item_id
Models:
class User extends Eloquent {
public function items()
{
return $this->belongsToMany('Item', 'user_items', 'item_id', 'user_id');
}
}
class Item extends Eloquent {
public function users()
{
return $this->belongsToMany('User', 'user_items', 'user_id', 'item_id');
}
}
I need to select all items table, print it and highlight rows which belongs to specific user id=1.
Selection highlighted output:
What is the right way to do it (in laravel style)?
You can use it like this
public function user_items()
{
return $this->belongsToMany('User', 'user_items', 'user_id', 'item_id')->withPivot('id');
}
Like this you can access values of third table.
Some useful links-
http://www.developed.be/2013/08/30/laravel-4-pivot-table-example-attach-and-detach/
http://vegibit.com/many-to-many-relationships-in-laravel/
http://laravel.com/docs/4.2/eloquent
You can do it like this way...
class User extends Eloquent {
public function items()
{
return $this->belongsToMany('Item', 'user_items', 'item_id', 'user_id')->withPivot('id');
}
}
class Item extends Eloquent {
public function users()
{
return $this->belongsToMany('User', 'user_items', 'user_id', 'item_id')->withPivot('id');
}
}
From controller..
$user_id = 2;
Item::with(['users'=>function($q) use ($user_id){$q->where('user_id',$user_id);}])->get();
In view at the time of listing a row you can highlight the row just use a condition as each item->users is blank or not.