2

In my User model i have 2 relationships

 public function role()
{
    return $this->belongsTo(Role::class, 'role_id');
}

public function city()
{
    return $this->belongsTo(City::class, 'city_id');
}

The second City doesnt work when i use

$user = App\User::findorfail(1)->with('city')->first(); 

for example. It gives the message

Illuminate/Database/Eloquent/RelationNotFoundException with message 'Call to undefined relationship [city] on model [App/User].

Class City is

<?php
 namespace App;

 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\SoftDeletes;


 class City extends Model
 {
 use SoftDeletes;

 protected $fillable = ['name', 'nomos_id','user_id'];
 protected $table = 'cities';


 public function setNomosIdAttribute($input)
 {
    $this->attributes['nomos_id'] = $input ? $input : null;
 }

 public function nomos()
 {
    return $this->belongsTo(Nomoi::class, 'nomos_id')->withTrashed();
 }

 }

What is the problem? Why one relationship works and the other doesnt.

gasprice admin
  • 143
  • 2
  • 11
  • Stupid question but city() is a method in App\User, right? `$user = App\User::findorfail(1)->with('city')->first(); ` is a very strange call, why wouldn't you just do `User::with('city')->findOrFail(1);`? Eager loading relationships has very limited advantages when loading only one model though. – Devon Bessemer Jul 20 '18 at 16:55
  • Its the same thing. The problem is that it doesnt find the model – gasprice admin Jul 20 '18 at 16:58
  • Probably not related to the error, but drop `first()`. `findOrFail` will always return the first record, or fail if none is found. – aynber Jul 20 '18 at 17:03
  • You can also try switching things around a bit: `User::with('city')->findOrFail(1);`. – aynber Jul 20 '18 at 17:04
  • Yes City is a method like all the methods that declare in model classes. Also its the same App\User::findorfail(1)->with('city')->first(); and User::with('city')->findOrFail(1)->first(); – gasprice admin Jul 20 '18 at 17:06
  • Both of those run two queries, drop the first() if you're using findOrFail. findOrFail returns the model instance, running first again will query the database again for the first result. – Devon Bessemer Jul 20 '18 at 17:07
  • with('role') works fine this is the strange thing – gasprice admin Jul 20 '18 at 17:07
  • Drop the eager load for debugging. `$user = User::findOrFail($id); dd($user->city, $user->city()->first()`; – Devon Bessemer Jul 20 '18 at 17:09

2 Answers2

0

Looking at the code $this->belongsTo(City::class, 'city_id') as an inverse of hasOne relationship that eventually would be looking at a city that the "user belongs to"?

Is this the intended purpose of this relation structure? If it is the inverse of it where as, we are looking for a city that "belongs to the user" we should be using $this->hasOne(City::class, 'city_id') of $this->hasMany(City::class, 'city_id') if it's a one-to-many relation.

Jerric Calosor
  • 95
  • 1
  • 1
  • 11
  • no way, a user has one city, a city can have many users! thanks for trying – gasprice admin Jul 20 '18 at 20:13
  • In all other models the same relationship with city i mean works fine except Users. I believe the system is confusing with another User class that is bild by the laravel. Though i dont know how can i solve that – gasprice admin Jul 21 '18 at 14:38
  • 1
    I see point taken, that's also the reason why I'm confirming with it's use case, anyway are you somehow using laravel passport for authentication? Or might have been using it, and just recently decided to decommission it? You might need to do a composer dump-autoload to reload the class, or you can test if there are namespace conflict by adding a namespace to User model, hope it helps. – Jerric Calosor Jul 23 '18 at 13:55
0

with() calls should come before find(), first(), findOrFail, firstOrFail(), or get()

This should be all you need to eager load the City with the User.

$user = App\User::with('city')->findOrFail(1); 

But if you need to explicitly call first() on City then you should be using:

$user = App\User::with(['city'->function($query){ 
    return $query->first();
})->findOrFail(1);
Azeame
  • 2,322
  • 2
  • 14
  • 30
  • Thanks for your answer but it isnt syntax problem. Normally it doesnt even add with-> to get attributes from relationship method. I tested your queries but it didnt work. It worked in my earlier versions of my project. I believe now that i messed something in configuration but i dont know what. I think i will make a fresh installation and try again. – gasprice admin Jul 21 '18 at 16:37
  • 1
    I created a new Laravel app and wrote a test with all 3 queries (your original + my two solutions) and they all seem to work fine. Check to see if `App\User::class` is actually returning an instance of the user class that you are expecting. – Azeame Jul 21 '18 at 17:06