Eloquent hasManyThrough also get pivot table record - php

I have the following relation in my Users model
public function events($user_id)
{
return $this->find($user_id)->hasManyThrough('Event', 'Event_Member', 'user_id', 'id');
}
And the three tables
User
id|name|...
1 |bob |
2 |mike|
Event
id|name |location
1 |meeting|office
Event_Member
user_id|event_id|status
1 |1 |Owner
2 |1 |Guest
The hasManyThrough relationship gives me the information from the Event table, but I also need the status information from the pivot table, how can this be done?

What you have looks like a many-to-many relation rather than a has-many-through one. You have two tables connected through a pivot, not three parent-child-grandchild tables.
I would strongly suggest changing the relationship in both models. In the user model, it would look like this:
public function events()
{
return $this->belongsToMany('Event', 'event_members');
}
Note that a pivot table is typically called model1_model2 in alphabetical order - that is, event_user in this case. I assumed your pivot table is called event_members, if not just change it. Also note that I removed the user_id since the user model already knows which user it's using.
Then you can access pivot data easily, e.g. like this:
foreach ($user->events as $event) {
echo $event->pivot->status;
}

Related

In laravel how can i get data in one query from 3 tables

I have 3 tables
first table : language
2nd table : user_language
3rd table : user
in user_language table i have stored language_id of all users it can be multiple.
user_language Table
user language_id
9 5
13 10
17 8
17 3
language_table
id language
5 english
10 hindi
8 Tamil
3 Gujrati
user table
id name
9 amit
3 john
17 aman
My question is in laravel how can i get all user language in one query. query should be in laravel.
In this case, all you should do is to write something like the following::
User model snippet:
public function languages() {
return $this->belongsToMany(Language::class);
}
Language model snippet
public function users() {
return $this->belongsToMany(User::class);
}
you need to import class at the top
and you can fetch user languages like
for specific user
User::with('languages')->where('id', $userId)->first();
and for all users
User::with('languages')->get();
Use many to many relation.
In user model:
public function languages()
{
return $this->belongsToMany('Language_Model', 'user_language', 'user', 'language_id');
}
The you can access the language using:
$user->languages
Do give a look at laravel many-to-many documentation, as it has clear information about many to many relationship.
Additionally you can look here for basic usages of many to many relationship.
Use Pivot Relationship.
Pivot relationship is very useful for two table connection using foreign keys.
Refer below link.
Pivot Relationship

Laravel - Additional relationship on a pivot table

I have a regular pivot table with 2 keys. However, I also have a 3rd column where I want to store a different key with a one to many relationship. Is this possible to have?
Example:
Pivot table:
Organization 1 | Organization 2 | Relation type
1 | 2 | 1
1 | 3 | 2
In this case organization number 1 has a relation with organization number 2 with the relation type being number 1. Organization number 1 also has a relation with organization number 3 with relation type 2.
Now is my question, how do I set up that additional one to many relationship on the pivot table?
What you have here is a ternary relationship. You are saying that an organisation A relates with an organisation B and a relationship type. This is a very uncommon use case because in the vast majority of cases ternary relationships can be simplified to binary ones. You need a very deep inspection of your data model to determine whether your case can be simplified, but assuming that it can't here's my suggestions.
It's worth checking the eloquent docs in particular under Defining Custom Intermediate Table Models for this. Note that this requires Laravel 5.4+ to work.
The following should work:
class OrganisationOrganisationLink extends Pivot {
public relationType() {
return $this->belongsTo(RelationType::class); //You need to specify the foreign key correctly as a 2nd parameter
}
}
Then in your original model:
class Organisation extends Model {
public relatedOrganisation() {
return $this->belongsToMany(self::class)->using(OrganisationOrganisationLink::class);
}
}
Then when making practical use of this you can e.g. do:
$organisation = Organisation::with('relatedOrganisation')->first();
echo "Got ".$organisation->name." which relates to "
.$organisation->relatedOrganisation->first()->name
." with relationship type "
$organisation->relatedOrganisation->first()->pivot->relationshipType()->value('name');
Of course the fields I've assumed may not exist but hopefully you get the idea.

Delete rows in pivot table in Laravel

I have two tables. Table reports
report_id | user_id | item_id
and reports_messages
report_id | user_id | item_id | messages
I want when I delete report_id on reports all related rows which matching report_id in reports_messages to be deleted too.
In my ReportMessages Model I have this relation
public function reports(){
return $this->belongsTo('App\Report');
}
public function item(){
return $this->belongsTo('App\Item', 'item_id', 'id');
}
In Report model
public function reportedItem(){
return $this->belongsTo('App\Item');
}
public function user(){
return $this->hasOne('App\User', 'id', 'user_id');
}
So far I've tried this solution founded here on SO
public function destroy($report_id){
Report::destroy($report_id);
ReportMessages::find(1)->reports()->where('report_id',$report_id)->delete();
return redirect()->route('user.ports');
This deletes only in reports.. doesn't delete related report_id's in pivot table.
}
Laravel has the functions detach and attach to deal with pivot tables.
So you can do this to remove the record in the pivot table:
ReportMessages::find(1)->reports()->detach($report_id);
This will however not remove the row in the reports table because it could still be linked to another object.
Update:
So, I just noticed, you don't have pivot tables, you only have two models that are linked.
You don't have to load the reports() relation in your query to remove the ReportMessages, you can just do it like this:
Report::destroy($report_id);
ReportMessages::where('report_id',$report_id)->delete();
This will remove the report, and all corresponding reportmessages.
I'm know I'm late but the best option with this kind of relationship, it is best to define foreign keys to particular linking tables in your table " reports_messages" like below
>
$table->integer('report_id')->unsigned()->index();
$table->foreign('report_id')->references('id')->on('reports')->onDelete('cascade');
$table->integer('message_id')->unsigned()->index();
$table->foreign('message_id')->references('id')->on('messages')->onDelete('cascade');
When you do something like this, the pivot table data will be removed as long as either message or report is deleted from database without a need of detaching methods.
Best option in case message or report has relationship with other data,such that when data is deleted message should be deleted automatically, in this case we do not have to worry about detaching data again
To remove a many-to-many relationship record, use the detach method. The detach method will remove the appropriate record out of the intermediate table; however, both models will remain in the database:
ReportMessages::find(1)->reports()->detach($report_id);
official documentation is here

Why the name convention of Laravel relationships so weird?

I have three tables:
users
columns: id, name
books
columns: id, name
book_user:
columns: user_id, book_id, state(not read yet, reading, read already)
I intended to user book_user as many-to-many relation table, so I follow the name convention from doc:
To define this relationship, three database tables are needed: users, roles, and role_user. The role_user table is derived from the alphabetical order of the related model names, and contains the user_id and role_id columns.
I wrote code:
class User extends Model
{
public function books()
{
return $this->belongsToMany('App\Book');
}
}
, and I can retrieve the books which related to the user by call user->books().
That works well, but when I try to retrieve the state of the book which related to a user, I create model:
class BookUser extends Model
{
//
}
When I use this Model, it claims:
Base table or view not found: 1146 Table 'myapp.book_users' doesn't exist
Conclusion:
the name convention of a table which can be used as many-to-many is <singular_noun>_<singular_noun> (such as book_user).
the name convention of table with multiple words which mapping to a Model is <singular_noun>_<plural_noun> (such as book_users).
I know I can set the table name manually which a model mappings to, but I just wonder:
Does that conflict is a design flaw or just I'm doing wrong in designing tables and models?
You don't need define a model for pivot table,just add withPivot
class User extends Model
{
public function books()
{
return $this->belongsToMany('App\Book')->withPivot('state');
}
}
Then you can retrieve book states from model pivot
Generally you don't need a model for pivot tables. You can define the inverse of the relationship. And if you want to store extra data in pivot table maybe you can check withPivot method. Or explain what are you trying to do.
But if you want to create a model, you need to specify your table name in your model manually. Because Laravel doesn't know if its a pivot table or normal table. It just tries to guess the table name by making it plural.

How to get courses through transactions table Laravel

I want to get all users with courses through transaction table.
Here is my db structure
course
id | name | description | price
transactions
id | course_id | user_id | name | description | expires
users
id | username | email
http://laravel.io/bin/da08n
I have tried with joins but it returns the same user multiple times.
DB::table('transactions')->join('users', 'transactions.user_id', '=', 'users.id')->join('courses', 'transactions.course_id', '=', 'courses.id')->distinct()->get();
How can I achieve this with Eloquent or in an other way?
Well.
you have a table called transactions, and a table of courses. Now, each transaction is related to a course.
Pay Attention: You have one record in one table which is related to another one record in another table, this is called one-to-one relationship.
In laravel, you achieve this by using Model's relationship.
You have one model called 'Transaction', and another model which is called 'Courses".
You get, for example one record from courses table by using Cources::find($myId).
Now, if you want to get a record of transactions by relating it to courses table., you should do this (in Laravel):
In your translation model define a method called course:
public function course ()
{
$this->hasOne("course"); // course is the name of another model which should be related
}
And then you use it like this:
$result = Transaction::find($myCourseId)->course();
Though for your case, you want to get many records through matching one record of a table to the another record of another table. Well:
In Transaction model add the following method:
public function Users()
{
return $this->hasManyThrough('User', 'Course');
}
With the above method you should be able to get the Users through Course method based on transactions.
More on that, please visit:
http://laravel.com/docs/eloquent#relationships

Categories