working with m:m relationships in eloquent outside laravel - laravel-4

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.

Related

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;

Laravel 5.0 Selective Append or MorphThrough Relation

I know the subject is a little bit confusing. Let me explain.
For a medical software that I am currently developing, I have a data structure as below:
Patients has Protocols. Protocols has Examinations, Prescriptions or Reports, all polymorphic.
In some cases, I have to directly access to the Examinations of Patients. However, since this includes a polymorphic relation between Examination and Protocol, I cannot directly setup a relation method in my Patient model.
As a work around, I can set a custom getExaminationsAttribute and append this with $appends in Patient model. But this causes a whole load of data fetching when I try to get ,for example, only the name of a Patient.
Any help is appreciated.
Patient model:
class Patient extends Model{
protected $table = 'patients';
public function protocols(){
return $this->hasMany('App\Protocol', 'patients_id', 'id');
}
protected $appends = ['examinations'];
public function getExaminationsAttribute()
{
$examinations = array();
$this->protocols->each(function($protocol) use (&$examinations){
$protocol->examinations->each(function($examination) use (&$examinations){
$examinations[] = $examination->toArray();
});
});
return $examinations;
}
Protocol model:
class Protocol extends Model{
protected $table = 'protocols';
public function patient(){
return $this->belongsTo('App\Patient', 'patients_id', 'id');
}
public function examinations()
{
return $this->morphedByMany('App\Examination', 'protocolable');
}
Examination model:
class Examination extends Model{
protected $table = 'examinations';
public function protocols()
{
return $this->morphToMany('App\Protocol', 'protocolable');
}
As a workaround, patients_id column added to submodels of Protocol table (Examinations, Prescriptions etc.) and will be fetched via hasMany relationship.

Laravel Eloquent, filtering from pivot table column

I need to filter the active clients from a route using Eloquent.
I'm working with a third party database that I can't modify. In my project I have two models: Cliente(client) and Ruta(route), which have a many to many relationship, so I added the belongsToMany relationship in my models.
The only column I'm interested from the pivot table is called DESACTIV, which tells me if a Client is deactivated for a Route.
Ruta model:
class Ruta extends Model
{
protected $connection = 'mysql2';
protected $table = 'truta';
protected $primaryKey = 'CODIRUTA';
public function clientes(){
return $this->belongsToMany(Cliente::class, 'tcpcarut', 'CODIRUTA', 'CODICLIE')->withPivot('DESACTIV');
}
}
Cliente model:
class Cliente extends Model
{
protected $connection = 'mysql2';
protected $table = 'tcpca';
protected $primaryKey = 'CODICLIE';
public function rutas(){
return $this->belongsToMany(Ruta::class, 'tcpcarut', 'CODICLIE', 'CODIRUTA')->withPivot('DESACTIV');
}
}
What I need is to get the active (or non deactivated) Clients given a specific Route.
I have done it on my controller like this:
$miRuta = Ruta::where('CODIRUTA','=',$ruta)->first();
$clientes = array();
foreach ($miRuta->clientes as $cliente){
if ($cliente->DESACTIV == 0){
array_push($clientes, $cliente->NOMBCLIE);
echo end($clientes)."<br/>";
}
}
And it works fine, but I don't think it's elegant. I know this can be archieved through Eloquent, I'm just to noob at it and don't know how to do it.
Maybe I could add the filter on the clientes method on my Ruta model, so it would return only the active Clients.
Or maybe It could be best to add a method on the Cliente model, like isDeactivated
I know it sounds like I know what I'm talking about but I need someone to hold my hand on this, I'm just too noob with Eloquent :/. Examples would be much appreciated.
You can use the wherePivot method to constrain a relationship based on values in the pivot table. You just need to add the following to your Ruta model
public function desactivClientes() {
return $this->clientes()->wherePivot('DESACTIV', 0);
}
And then you just have to modify the rest of your code a bit to use the constrained relationship. I'm also adding a null check because if this function does return null, which can happen if your table doesn't have a record where CODIRUTA matches whatever is in $ruta, then it will likely throw a fatal error trying to call a method on a non-object.
$miRuta = Ruta::where('CODIRUTA','=',$ruta)->first();
$clientes = array();
if ($miRuta !== null) {
$clientes = $miRuta->desactivClientes()->pluck('NOMBCLIE');
}

Eloquent One To Many issue

i have a question related to the title.
so i have this models (i have more code and models behind if u need tell me)
Cliente Model
protected $table = 'cliente';
protected $primaryKey = 'id_cliente';
public $timestamps = false;
public function seguroCarro()
{
return $this->hasMany('App\SeguroCarro', 'id_seguro_carro');
}
SeguroCarro Model
protected $table = 'seguro_carro';
protected $primaryKey = 'id_seguro_carro';
public $timestamps = false;
public function cliente()
{
return $this->belongsTo('App\Cliente', 'id_cliente');
}
Question:
This Cliente::find(1)->seguroCarro get the seguro_carro with id 1 and not with id_cliente 1 but this SeguroCarro::all()->where('id_cliente',Auth::user()->cliente->id_cliente) get the 3 rows seguro_carro i need
i dont get why this happen but i want understand why
Atencion:
this Cliente::find(1)->seguroCarro is a abreviation for you guys for my code Auth::user()->cliente->seguroCarro [my Auth::user()->cliente have the id 1]
img of rows on seguro_carro table
Thank you for the time guys
The relationship on your App\Cliente model is specifying the wrong key. The second parameter to the hasOne/hasMany relationship is the name of the foreign key field on the related object. In this case, the foreign key on the related object (App\SeguroCarro) is id_cliente, not id_seguro_carro.
Your current relationship will get the seguro_carro records where seguro_carro.id_seguro_carro = cliente.id_cliente, which is not what you want.
The relationship should be changed to:
public function seguroCarro()
{
return $this->hasMany('App\SeguroCarro', 'id_cliente');
}
This will get the seguro_carro records where seguro_carro.id_cliente = cliente.id_cliente, which is what you want.
The belongsTo relationship on your App\SeguroCarro is correct.

In Laravel, how to set up a relationship for a "likes" table? Also, how to include that information in a query?

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();

Resources