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;
Related
I'm using Laravel Filament.
I got a projects and responsibles tables in a many-to-many relationship. But also another table of responsabilityTypes
projects
id
title
responsibles
id
name
responsabilityTypes
id
name
project_responsible
project_id
responsible_id
responsibilityType_id
And here are my relationships setup:
Responsible.php
public function projects() {
return $this->belongsToMany(Project::class,'rel_project_responsible','responsible_id','project_id')
->withPivot('responsibilityType_id')
->withTimestamps()
->using(AcademicoProyecto::class);
}
Project.php
public function responsibles() {
return $this->belongsToMany(Responsible::class,'rel_project_responsible','project_id','responsible_id')
->withPivot('responsibilityType_id','sort')
->withTimestamps()
->using(AcademicoProyecto::class);
}
I have set up a class for the pivot table like so:
ProjectResponsible.php
use Illuminate\Database\Eloquent\Relations\Pivot;
class AcademicoProyecto extends Pivot
{
}
ResponsibilityType.php
//Don't know how to set up
My question is, when the user is in a Project Edit page and clicks on the "attach" button, in order to add a Responsible record, a Modal pops up to select a Responsible, but I also implemented a Select list to display the different types of responsibilities.
What am I missing to set up in order to access and display the types of responsibilities in the select list and attach it to the pivot table?
Your question asks about "access and display" but you have no controller or view code. But for the model, it's just a simple relationship between two tables, so define it as such:
class AcademicoProyecto extends Pivot
{
use SoftDeletes;
public function responsibilityType() {
return $this->belongsTo(ResponsibilityType::class);
}
}
class ResponsibilityType extends Model
{
protected $fillable = ["name"];
}
Now you simply update the other models to access the relationship in the withPivot() call.
class Responsible extends Model {
public function projects() {
return $this->belongsToMany(Project::class,'rel_project_responsible','responsible_id','project_id')
->withPivot('responsibilityType')
->withTimestamps()
->using(AcademicoProyecto::class);
}
}
class Project extends Model {
public function responsibles() {
return $this->belongsToMany(Responsible::class,'rel_project_responsible','project_id','responsible_id')
->withPivot('responsibilityType', 'sort')
->withTimestamps()
->using(AcademicoProyecto::class);
}
}
Now you should be able to do, for example:
$foo = Responsible::with("projects")->first();
foreach ($foo->projects as $project) {
echo $project->pivot->responsibilityType?->name;
}
In restaurant table, foreign key do not get value of user table. I make relation one to many in user and restaurant tables. user can have many restaurants.
class Restaurant extends Model
{
protected $guarded=['user_id'];
protected $table ="rest_info";
public function menus() {
return $this->hasMany('App\Menu');
}
public function dishes(){
return $this->morphMany('App\Dish','dishable');
}
public function user(){
return $this->belongsTo('App\User','id','user_id');
}
}
If you wish to access these relationship with in your controller function you can use with keyword of laravel you have to something like this:-
If you wish to get the menus you can use something like this in your contoller Function
$getResturantdata = Resturant::with('menus')->get();
dd($getResturantdata);
If you wish to get the menus and users both you can use something like this in your contoller Function:-
$getResturantdata = Resturant::with('menus','users')->get();
dd($getResturantdata);
I've got some troubles with an eloquent query.
Users have many feeds and feeds have many items.
I need to get all the items that belongs to the feeds of the user order by date.
I've got a pivot table:
feed_user
----------
- id
- feed_id
- user_id
and relationships are defined like this in my models:
class UsersController extends BaseController {
public function feeds() {
return $this->hasMany('feed');
}
class Feed extends \Eloquent {
protected $fillable = [];
public function users() {
return $this->belongsToMany('User');
}
public function items() {
return $this->hasMany('Item');
}
class Item extends \Eloquent {
protected $fillable = [];
public function feed() {
return $this->belongsTo('Feed');
}
But when I do this query...
Auth::user()->feeds->items->orderBy('date', 'DESC')->get();
It returns this error:
Cannot access protected property Illuminate\Database\Eloquent\Collection::$items
There are a couple issues here.
First, the relationship on User model is not correct. A hasMany relationship is one half a one-to-many relationship. This would assume that a feed belongs to one user, and that the feed table has the user_id field. A many-to-many relationship is defined by adding a belongsToMany relationship on both models. So, a user belongsToMany feeds, and a feed belongsToMany users.
class User extends \Eloquent {
public function feeds() {
return $this->belongsToMany('feed');
}
}
Next, the error you're seeing is because Auth::user()->feeds returns a Illuminate\Database\Eloquent\Collection object. You're then trying to access the items attribute on the Collection, which is protected and throws the error you're seeing.
Finally, since Laravel does not use joins for relationships, you cannot order a query by a field on a related table without manually doing the join yourself.
Try using eager loading:
Auth::user()->with('feeds.items')->orderBy('date', 'DESC')->get();
I have three tables: users, ideas, and ideas_likes. The ideas_likes table looks like:
ideas_likes
------------
id primary key
user_id foreign key
idea_id foreign key
liked boolean
There's already a one-to-many relationship set up between users and ideas. It looks something like this:
class User extends Ardent implements UserInterface, RemindableInterface {
use UserTrait, RemindableTrait;
protected $table = 'users';
public function ideas()
{
return $this->hasMany('Idea');
}
}
Similarly, the idea model looks like this:
class Idea extends Ardent {
protected $table = 'ideas';
public function user()
{
return $this->belongsTo('User');
}
}
My first question is: How do I create the IdeaLike model? And once that is finished, using Eloquent, how do I retrieve all liked ideas for a user?
===========================================================================
Lucasgeiter's updated solution worked great.
First, there's no need to create an IdeaLike model. You just need a many-to-many relationship
User
public function ideas(){
return $this->belongsToMany('Idea', 'ideas_likes')->withPivot('liked');
}
Idea
public function users(){
return $this->belongsToMany('User', 'ideas_likes')->withPivot('liked');
}
(By adding withPivot I tell Laravel that I want to have the liked column from the pivot table included in the result)
Usage
$user = User::find(1);
$likedIdeas = $user->ideas()->where('liked', true)->get();
By the way: You don't need to specify the $table if it is the plural of the model name.
Update
It looks like you actually really do need both, a one-to-many and a many-to-many relation.
So your final relations would look like this:
User
public function ideas(){
return $this->hasMany('Idea');
}
public function liked(){
return $this->belongsToMany('Idea', 'ideas_likes')->withPivot('liked');
}
Idea
public function likes(){
return $this->belongsToMany('User', 'ideas_likes')->withPivot('liked');
}
public function user(){
return $this->belongsTo('User');
}
(I just chose names for the relations that made kind of sense to me. You can obviously change them)
Usage
Liked ideas by a certain user: (id = 1)
$ideas = Idea::where('user_id', 1)->whereHas('likes', function($q){
$q->where('liked', true);
})->get();
I have been able to set up a m:m relationship in eloquent outside laravel and retrieve records but I have no idea how to add a new record as you dont create the pivot table in the code.
If these are my classes, how would i add a new instance to the M:M relationship between author and publisher?
<?php
include 'eloquent_database.php';
class Publisher extends Illuminate\Database\Eloquent\Model {
public $timestamps = false;
protected $table = 'publisher';
protected $primaryKey = 'publisher_id';
public function authors (){
return $this->belongsToMany('Author', 'author_publisher', 'publisher_id', 'author_id');
}
}
class Book extends Illuminate\Database\Eloquent\Model {
public $timestamps = false;
protected $table = 'book';
protected $primaryKey = 'book_id';
public function author() {
//related table name, pk in current table,
return $this->belongsTo('Author', 'author_id');
}
}
// Create the company model
class Author extends Illuminate\Database\Eloquent\Model {
public $timestamps = false;
protected $table = 'author';
protected $primaryKey = 'author_id';
public function books()
{
//related table, fk IN related table,
return $this->hasMany('Book', 'author_id');
}
public function publishers (){
return $this->belongsToMany('Publisher', 'author_publisher', 'author_id', 'publisher_id');
}
}
I would also need to know how to delete one too. I have seen this documentation http://laravel.com/docs/4.2/eloquent#working-with-pivot-tables but i dont really follow it
Id really appreicate an exxample of how to add and delete a new instance. Also onine there seeems to be so many different versions its hard to find which docs to follow as the code i have works but i didnt get it from the docs - just trial and error
Thanks a lot in advance
edit:
in repsonse to Rays comment i do have a pivot table in the database called author_publisher with author id and publisher id but i have no idea how to work with this pivot table. Do i have to create a class for it? I dont really understand
Here is a reference to said table in the code above
return $this->belongsToMany('Author', 'author_publisher', 'publisher_id', 'author_id');
When having a M:M relationship, make sure you have a table that translates the relationship between author and publisher. An example table could be composed of entries including both author_id and publisher_id. From what you have provided, you lack such a table.
There's another case if you do not have such a table. In order for such a M:M relationship to work, the author table must contain a column called "publisher_id" for simplicity. Likewise the publisher table must contain a column called "author_id". Then in the author model, return $this->hasMany('Publisher', 'author_id') and in the publisher model, return $this->hasMany('Author', 'publisher_id'). You should get the correct answer.