Laravel - hasManyThrough return only _id - php

I use Laravel MongoDB package by jenssegers and Eloquent Laravel Model.
articles :
_id (ObjectID)
feed_id
title
feeds :
id
user_id
name
users :
id
name
hasManyThrough in User::class model to get all articles by one user.
public function articles()
{
return $this->hasManyThrough(
'App\Article',
'App\Feed',
'user_id', // Foreign key on feeds table...
'feed_id', // Foreign key on articles table...
'_id', // Local key on users table...
'id' // Local key on feeds table...
);
}
I get only _id (ObjectID) with this query:
$user = \App\Models\User::find(1);
dd($user->articles);
Could you help me to search the problem?

You can try this
$user->articles()->find(1);
In place of find() you can use first() if you want the first record and if you want all records you can use get()
also if you want to put constraint use where() rather than find()
$user->articles()->where('_id', 1)->first();

Related

Speed up query through laravel relationships

There are 3 models:
First (first_id)
Connection (connection_id, first_id, product_id)
Second (second_id, product_id)
I would like to connect the three models together using laravel relationships
First->joined to Connection though first_id
Connection->joined to First through first_id, & joined to Second through product_id
Second -> joined to Connection through product_id
So: First joined to Second through Connection first_id, product_id
Is this possible to do using something like HasManyThrough?
Thanks for your time
On your First model:
public function second () {
return $this->hasManyThrough(
Second::class,
Connection::class,
'product_id', // Foreign key on connection table
'product_id', // Foreign key on second table
'first_id', // Local key on first table
'first_id' // Local key on connection table
);
}
Based on your description the column names should work.
In tinker you can validate if it's hooked up correctly by doing something like First::first()->second.
It depends on what type of relationship Your first model and second model shares as well as what type of relation second and third model shares.
if consider your first model First and second model Second shares a one-to-one relation, as well as Second model and Third models shares one-to-one relationships.
It will be $first->second->third; //no has many through relationship requires
If your First model and Second models shares as hasMany-belongs to relation than you need to use hasManyThrough relationship
example from doc
class Country extends Model
{
public function posts()
{
return $this->hasManyThrough(
'App\Post',
'App\User',
'country_id', // Foreign key on users table...
'user_id', // Foreign key on posts table...
'id', // Local key on countries table...
'id' // Local key on users table...
);
}
}
You can try using nested relationships.
Nested Eager Loading
To eager load nested relationships, you may use "dot" syntax. For example, let's eager load all of the book's authors and all of the author's personal contacts in one Eloquent statement:
$books = App\Book::with('author.contacts')->get();
Book Model:
public function author()
{
return $this->hasOne('App\Author');
}
Author Model:
public function contacts()
{
return $this->hasMany('App\Author');
}
Documentation:
https://laravel.com/docs/5.8/eloquent-relationships

Laravel belongsToMany retrieve more then one row

So im creating a booking system where you can create maps and assign them to an event. I have 3 tables to handle this, events, maps, and event_maps
I have after reading the Laravel Documentation i decided to set up a belongsToMany relation.
But when i try to retrieve my maps thru my event model i only get one the first row.
in my controller i do
public function displayForm($id)
{
$event = EventModel::find($id);
print_r($event->maps);
}
The result is a Illuminate\Database\Eloquent\Collection Object with the last out of 2 maps, and i can't for my life figger out how to get them all.
My EventsModel
public function maps()
{
return $this->belongsToMany('App\Models\Booky\MapsModel',
// Table name of the relationship's joining table.
'event_maps',
// Foreign key name of the model on which you are defining the relationship
'map_id',
// Foreign key name of the model that you are joining to
'event_id'
);
}
My MapsModel
public function event()
{
return $this->belongsToMany('App\Models\Booky\EventsModel',
// Table name of the relationship's joining table.
'event_maps',
// Foreign key name of the model on which you are defining the relationship
'event_id',
// Foreign key name of the model that you are joining to
'map_id'
);
}
The database looks something like this
events
- id
- lots of irrelevant data
maps
- id
- lots of irrelevant data
event_maps
- id
- event_id
- map_id
I was thinking that perhaps i should use another relation type, but as far as i understand they don't use a relation table like event_maps.
Everything else work as expected.
Anyone who could clear up this mess? :)
The ids are inverted in the relation. Try this:
public function maps()
{
return $this->belongsToMany('App\Models\Booky\MapsModel',
// Table name of the relationship's joining table.
'event_maps',
// Foreign key name of the model that you are joining to
'event_id'
// Foreign key name of the model on which you are defining the relationship
'map_id',
);
}
And:
public function event()
{
return $this->belongsToMany('App\Models\Booky\EventsModel',
// Table name of the relationship's joining table.
'event_maps',
// Foreign key name of the model that you are joining to
'map_id'
// Foreign key name of the model on which you are defining the relationship
'event_id',
);
}

getting all the data from pivot table in laravel

i'm trying to get all the lead_id inside my pivot table but i can't make it work.
controller:
$levels = Level::all();
$levels->lead()->attach('lead_id');
return $levels;
Model Level:
public function lead(){
return $this->belongsToMany(Lead::class, 'level_students')->withPivot('level_id', 'lead_id');
}
Model Lead:
public function level(){
return $this->belongsToMany(Level::class, 'level_students')->withPivot( 'lead_id', 'level_id');
}
If you mean all lead_id of a Level, then you can use pluck().
$level->lead->pluck('lead_id');
I'm not really sure what you are trying to achieve because it seems that you want to retrieve all lead_id associated with any Level. But if that is the case, then you can create a model for the pivot table (e.g. LevelLead) and use distinct() or with Query Builder:
$leadIds = DB::table('level_students')->select('lead_id')->distinct()->get();
If you want to get the referenced table's column (e.g. leads table's name column) then you can use JOIN. Check Laravel's doc for more options. For example, assuming the table name for Lead is leads, then:
$leads = DB::table('level_students')->join('leads', 'level_students.lead_id', '=', 'leads.lead_id')->select('level_students.lead_id', 'leads.name')->distinct()->get();

Laravel updateExistingPivot with multiple primary keys

Problem
I want to update a row in a pivot table that have 2 primary keys. But updateExistingPivot want only a single primary key.
$user = App\User::find(1);
$user->roles()->updateExistingPivot($roleId, $attributes);
My DB-tables
Campaign
User
Campaign_user (primary keys are user_id and campaign_id)
My Question
Should I change my pivot table so it only have 1 primary key called id. Or can I keep it with 2 primary keys, and still update it, with Eloquent?
I think for best practice you should add a key id in your Campaign_user table, structure should:
Campaign_user
id|user_id|campaign_id
In User Model
public function campaign()
{
return $this->belongsToMany('Campaign', 'Campaign_user','user_id','campaign_id')->withPivot('extra attribute if any');
}
In Campaign Model
public function users()
{
return $this->belongsToMany('User', 'Campaign_user','campaign_id','user_id')->withPivot('extra attribute if any');
}
Now your code is:
$user = App\User::find($userId);
$user->campaign()->updateExistingPivot($campaignId, array('any attribute'=>$value));

Laravel belongsToMany relationship defining local key on both tables

So the belongsToMany relationship is a many-to-many relationship so a pivot table is required
Example we have a users table and a roles table and a user_roles pivot table.
The pivot table has two columns, user_id, foo_id... foo_id referring to the id in roles table.
So to do this we write the following in the user eloquent model:
return $this->belongsToMany('Role', 'user_roles', 'user_id', 'foo_id');
Now this looks for an id field in users table and joins it with the user_id field in the user_roles table.
Issue is I want to specify a different field, other than id to join on in the users table. For example I have bar_id in the users table that I want to use as the local key to join with user_id
From laravel's documentation, it is not clear on how to do this. In other relationships like hasMany and belongsTo we can specify local key and foriegn key but not in here for some reason.
I want the local key on the users table to be bar_id instead of just id.
How can I do this?
Update:
as of Laravel 5.5 onwards it is possible with generic relation method, as mentioned by #cyberfly below:
public function categories()
{
return $this->belongsToMany(
Category::class,
'service_categories',
'service_id',
'category_id',
'uuid', // new in 5.5
'uuid' // new in 5.5
);
}
for reference, previous method:
I assume id is the primary key on your User model, so there is no way to do this with Eloquent methods, because belongsToMany uses $model->getKey() to get that key.
So you need to create custom relation extending belongsToMany that will do what you need.
A quick guess you could try: (not tested, but won't work with eager loading for sure)
// User model
protected function setPrimaryKey($key)
{
$this->primaryKey = $key;
}
public function roles()
{
$this->setPrimaryKey('desiredUserColumn');
$relation = $this->belongsToMany('Role', 'user_roles', 'user_id', 'foo_id');
$this->setPrimaryKey('id');
return $relation;
}
On Laravel 5.5 and above,
public function categories()
{
return $this->belongsToMany(Category::class,'service_categories','service_id','category_id', 'uuid', 'uuid');
}
From the source code:
public function belongsToMany($related, $table = null, $foreignPivotKey = null, $relatedPivotKey = null,
$parentKey = null, $relatedKey = null, $relation = null)
{}
This is a recently added feature. I had to upgrade to 4.1 because I was also looking for this.
From the API documentation:
public BelongsToMany belongsToMany(string $related, string $table = null, string $foreignKey = null, string $otherKey = null, string $relation = null)
The $otherKey and $relation parameters were added in 4.1. Using the $foreignKey and $otherKey parameters allows you to specify the keys on both sides of the relation.
The best way is set the primary key.
class Table extends Eloquent {
protected $table = 'table_name';
protected $primaryKey = 'local_key';
belongsToMany allows to define the name of the fields that are going to store che keys in the pivot table but the method insert always the primary key values into these fields.
You have to:
define in the method belongsToMany the table and the columns;
then using protected $primaryKey = 'local_key'; you can choose which value store.
I recently went through the same problem where I needed to have an associated table that used ID's to link two tables together that were not Primary Keys. Basically what I did was create a copy of my model that models the pivot table and set the Primary Key to the value that I wanted it to use. I tried creating a model instance, settings the primary key and then passing that to the relation but Laravel was not respecting the primary key I had set ( using the ->setPrimaryKey() method above ).
Making a copy of the model and setting the primary key feels a little bit 'hackish' but in the end it works as it should and since Pivot table models are generally very small I don't see it causing any problems in the future.
Would love to see a third key option available in the next release of Laravel that lets you get more specific with your linking.

Categories