Query with join table bringing wrong ID - Laravel - laravel

This is driving me crazy.
I have two tables: Records and Users and a query to bring records of users:
$records = Record::with('user')
->join('users', 'users.id', '=', 'records.user_id')
->orderBy('users.name', 'asc')
->where('schedule_id', $schedule->id)
->get();
The dd($records); brings me this:
Collection {#827 ▼
#items: array:6 [▼
0 => Record {#773 ▼
#connection: "mysql"
#table: null
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:13 [▼
"id" => 26
"user_id" => 26
"schedule_id" => 3
"start_time" => "12:00"
"end_time" => "20:00"
"created_at" => null
"updated_at" => null
"name" => "Ali Fay"
"email" => "twolff#gmail.com"
"password" => ""
"role_id" => 6
"store_id" => 3
"remember_token" => null
]
As you can see, the attributes are ok of both models except the "id", that is the id of the user, not the record. What I'm doing wrong?

The concrete problem is this case, that you have two columns named id in the join, so select the columns you need and only select one of the ids, can probaly easily be solved by this, and if columns of the user is needed you can select them as wanted.
$records = Record::with('user')
->join('users', 'users.id', '=', 'records.user_id')
->orderBy('users.name', 'asc')
->where('schedule_id', $schedule->id)
->select('records.*')
->get();
The best solution is to use relationships, so if the model is something similar to.
public class record
{
public function user() {
return $this->belongsTo('App\User');
}
}
Then you instead can do the same query as. WhereHas checks if the relation with the given condition exists, otherwise if there was no condition, has could have been used.
Record::whereHas('user', function ($query) use($schedule){
$query->where('schedule_id', $schedule->id);
})->get()->sortBy(function($item, $key) {
return $item->user->name;
});

You don't need to use join() here:
$records = $schedule->records()->with('user')->get();
Then sort the collection:
$records->sortBy(function($i) {
return $i->user->name;
});

Related

Eloquent query gets no result, but on database it works

Laravel gets no result for this function:
public function freigabenabruf()
{
DB::connection()->enableQueryLog();
$freigaben=DB::table('freigaben AS fg')
->join('TFI_RECHNUNG AS re', 're.re_nr_intern', 'fg.re_nr_intern')
->select( 'fg.freigabe1', 'fg.freigabe2', 'fg.created_at', 'fg.updated_at')
->orderBy('fg.created_at', 'desc')
->get();
var_dump($freigaben);
dd(DB::getQueryLog());
return $freigaben;
}
QueryLog retrieves:
object(Illuminate\Support\Collection)#293 (1) { ["items":protected]=> array(0) { } }
array:1 [▼
0 => array:3 [▼
"query" => "select "FG"."FREIGABE1", "FG"."FREIGABE2", "FG"."CREATED_AT", "FG"."UPDATED_AT" from "FREIGABEN" fg inner join "TFI_RECHNUNG" re on "RE"."RE_NR_INTERN" = "FG"." ▶"
"bindings" => []
"time" => 7.76
]
]
When I execute the query on database, I get my expected results...
Whats wrong? Any suggestions?
You have used select() two times. Try by using single select()
$freigaben=DB::table('freigaben AS fg')
->join('TFI_RECHNUNG AS re', 're.re_nr_intern', 'fg.re_nr_intern')
->select('re_nr', 'freigabe1', 'freigabe2', 'created_at', 'updated_at','fg.freigabe1', 'fg.freigabe2', 'fg.created_at', 'fg.updated_at')
->orderBy('fg.created_at', 'desc')
->get();

Laravel Eager Loading is Null with Polymorphic Relations

In my model I have:
//UserAddress.php
protected $with = ['address'];
public function address()
{
return $this->morphOne('App\Address', 'addressable');
}
//User.php
public function userAddress()
{
return $this->hasOne(UserAddress::class);
}
//Address.php
public function addressable()
{
return $this->morphTo();
}
But when I call dd(auth()->user()->userAddress)) The address realtionship is not loaded. It is still null.
#attributes: array:4 [
"id" => "1"
"user_id" => "1"
"created_at" => "2018-11-13 10:11:54"
"updated_at" => "2018-11-13 10:11:54"
]
#original: array:4 [
"id" => "1"
"user_id" => "1"
"created_at" => "2018-11-13 10:11:54"
"updated_at" => "2018-11-13 10:11:54"
]
#changes: []
#casts: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: array:1 [
"address" => null
]
#touches: []
+timestamps: true
However, with dd(auth()->user()->userAddress()->get())) the relationship is eager loaded.
What is the problem?
Edit
It is super weird. If I write auth()->user()->userAddress->address I get null (it should not be that). And when I remove protected $with = ['address']; auth()->user()->userAddress->address gets me the correct model.
I have similar issue. It is loading the related models, but under different key.
I got a pivot model called Skillable it has a morphTo relationship to get the related morphed model.
public function morphedModel(): MorphTo
{
return $this->morphTo('skillable');
}
That works fine without eager loading when used like that
echo $skillable->morphedModel->id; // return some id
However when using eager loading, the morphedModel prop is null.
Skillable::with('morphedModel')->get()->first()->morhphedModel; // returns null
Turns out the eager loading is working almost as expected, however the related (morphed) models are loaded under skillable relationship instead.
dump(Skillable::with('morphedModel')->get()->first());
returns
...
#relations: array:2 [▶
"morphedModel" => null
"skillable" => App\Models\Lesson {#2376 ▶
Not sure why though.. something with my relation definition I guess.
I had the same issue with a one-to-one relationship where the id field was a string. Everything worked until I eager-loaded the connecting table (user_address in you case).
In my case I'd forgotten to define public $incrementing = false; in the connecting table, and once I had added this everything worked.

Get relation of relation

I'm trying to get the comments of the links with laravel relationship, the comments of links return normally, but I don't know how to get it in view or dd(), how can I do it?
Controller:
$page = Page::where('friendly_url', $id)
->select('id', 'photo', 'friendly_url', 'name', 'description', 'followers', 'links', 'tag_id', 'links_clicks')
->with('ptag', 'links', 'links.comments', 'links.tag')
->with(['links.comments.user' => function($query) {
$query->select('id', 'name', 'lastname');
}])->with(['links.comments.userProfile' => function($query) {
$query->select('id', 'photo');
}])->first();
dd($page->getRelation('links')
Collection {#301 ▼
#items: array:2 [▼
0 => Link {#307 ▼
#relations: array:2 [▼
"comments" => Collection {#316 ▼
#items: array:1 [▶]
"tag" => Tag {#322 ▶}
]
dd($page->getRelation('links')->getRelation('comments'))
BadMethodCallException
Method getRelation does not exist.
dd($page->getRelation('links')->comments)
Exception
Property [comments] does not exist on this collection instance.
EDIT:
I want to show the attributes of comment and comment.user, how I can do it?
foreach($page->getRelation('links')->pluck('comments') as $comment) {
dd($comment);
}
Collection {#327 ▼
#items: array:1 [▼
0 => Comment {#325 ▼
#attributes: array:5 [▼
"id" => 3
"content" => "teste"
"link_id" => 1
"user_id" => 1
"created_at" => "2018-01-11 00:47:32"
]
#relations: array:2 [▼
"user" => User {#330 ▼
#attributes: array:3 [▼
"id" => 1
"name" => "Halysson"
"lastname" => "Teves dos Santos"
]
}
"userProfile" => UserProfile {#326 ▶}
]
Try this-
foreach($page->links as $link){
$comments = $link->comments;
}
You should define relations first on relevent models and then using 'with' function can load models with relations OR a relation can be called directly by single model see documentation for further details
eg: you have defined a relation for user to phone, as user has a phone, one to one relation. in user model define a relation like
public function phone()
{
return $this->hasOne('App\Phone');
}
now to call this relation on user model instance.
$user = User::find(1);
dd($user->phone);
Because you're using the select() method, you also need to include all the foreign keys in it to allow Eloquent to be able to load these relationships.
But since you just start using Laravel, I'd recommend you to just remove select() method from this complex query.
If you want the links of a page :
$page->links
if you want all the comments of a page :
$page->links->pluck('comments')
that's it :)

Eloquent $appends acts strangely in laravel 5.3

am simply trying to include a new attribute to be available in the json response but for some reason am also getting the object relation as well.
// user model
protected $guarded = ['id'];
protected $appends = ['role_name'];
protected $hidden = ['remember_token', 'password'];
public function getRoleNameAttribute()
{
return $this->role->type;
}
public function role()
{
return $this->belongsTo(Role::class);
}
// role model
public function users()
{
return $this->hasMany(User::class);
}
when i use dd($user); i get
User {#303
#guarded: array:1 [
0 => "id"
]
#appends: array:1 [
0 => "role_name"
]
#hidden: array:2 [
0 => "remember_token"
1 => "password"
]
#connection: null
#table: null
#primaryKey: "id"
#keyType: "int"
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:7 [
"name" => "testing"
"email" => "email#asd.com"
"password" => "$2y$10$fogQXhJZm5eoViM38pge1.BmNxY7IFl515zT83.Ks9Uj26kK9T6Im"
"role_id" => "83eee2e0-8939-48f7-9fbc-1c077e2265e5"
"id" => "a181fb4b-b65a-47b4-9c72-21ea15c6c5a6"
"updated_at" => "2017-01-30 20:23:52"
"created_at" => "2017-01-30 20:23:52"
]
#original: array:7 [
"name" => "testing"
"email" => "email#asd.com"
"password" => "$2y$10$fogQXhJZm5eoViM38pge1.BmNxY7IFl515zT83.Ks9Uj26kK9T6Im"
"role_id" => "83eee2e0-8939-48f7-9fbc-1c077e2265e5"
"id" => "a181fb4b-b65a-47b4-9c72-21ea15c6c5a6"
"updated_at" => "2017-01-30 20:23:52"
"created_at" => "2017-01-30 20:23:52"
]
...
}
and with return response()->json(compact('user')); instead i get
user: {
created_at: "2017-01-30 20:26:12"
email:"email#asd.com"
id:"4b83e031-e8c8-4050-963d-446cb383fb14"
name:"testing"
role:{
created_at:"2016-12-29 10:54:02"
id:"83eee2e0-8939-48f7-9fbc-1c077e2265e5"
type:"user"
updated_at:"2016-12-29 10:54:02"
}
role_id:"83eee2e0-8939-48f7-9fbc-1c077e2265e5"
role_name:"user"
updated_at:"2017-01-30 20:26:12"
}
but what i expect is to only have
user: {
created_at: "2017-01-30 20:26:12"
email:"email#asd.com"
id:"4b83e031-e8c8-4050-963d-446cb383fb14"
name:"testing"
role_id:"83eee2e0-8939-48f7-9fbc-1c077e2265e5"
role_name:"user"
updated_at:"2017-01-30 20:26:12"
}
so am not sure if this is the normal behavior or a bug or maybe am missing something ?
Laravel version 5.3.30
The reason why this is happening is the following
public function getRoleNameAttribute()
{
return $this->role->type;
}
The problem here is the when you say $this->role it will automatically attached the relationship to the model. In order to prevent this, you should simply be able to access the method directly, like $this->role().
public function getRoleNameAttribute()
{
return $this->role()->first()->type;
}

Laravel 5.3 convert query builder to LengthAwarePaginator

I need to use switch cases to add constraints to the query I need to run. I need it to work with pagination, I tried this:
$albums = Album::with(array(
'images' => function ($query) {
$query->orderBy('order', 'asc');
}
))
->where('votes.votable_type','App\Models\Album')
->groupBy('albums.id');
$albums->published()->orderBy('created_at', 'desc')->paginate(30);
dd($albums);
and I get
Builder {#361 ▼
#query: Builder {#350 ▶}
#model: Album {#351 ▶}
#eagerLoad: array:2 [▶]
#macros: array:5 [▶]
#onDelete: Closure {#364 ▶}
#passthru: array:11 [▶]
#scopes: array:1 [▶]
#removedScopes: []
}
If I run
$albums = Album::with(array(
'images' => function ($query) {
$query->orderBy('order', 'asc');
}
))
->where('votes.votable_type','App\Models\Album')
->groupBy('albums.id')
->published()->orderBy('created_at', 'desc')->paginate(30);
dd($albums);
I get
LengthAwarePaginator {#467 ▼
#total: 97
#lastPage: 4
#items: Collection {#872 ▶}
#perPage: 30
#currentPage: 1
#path: "http://images.dev"
#query: []
#fragment: null
#pageName: "page"
}
why is there difference between these two approaches? I need to use first approach to be able to add constraints using switch case, I can't do that using second approach. But with first approach I do not get LengthAwarePaginator, how to fix it so that I get that?
You should redeclare the variable $albums if you wish it to be saved to this variable. Change this:
$albums->published()->orderBy('created_at', 'desc')->paginate(30);
To:
$albums = $albums->published()->orderBy('created_at', 'desc')->paginate(30);

Resources