简体   繁体   中英

Can't eager-load a One-to-One relation in Laravel

In Laravel 5.2 I'm trying to eager load a User along with its Usersettings with this piece of code: App\\User::with('usersettings')->get() , but it fails, and I can't seem to figure out why. This is the given error.

BadMethodCallException with message 'Call to undefined method Illuminate\Database\Query\Builder::usersettings()'

I've read the laravel docs and I've watched a lot of Laracasts , and this worked before, so I get the idea I'm missing something really small and probably obvious.

User.php

<?php

namespace App;

/* User with fields: id, email */
class User extends Illuminate\Database\Eloquent\Model {
    protected $table = 'users';

    public function usersettings() {
        return $this->hasOne("App\Usersettings", "userid");
    }
}

Usersettings.php

<?php

namespace App;

/* Settings with fields: id, userid, textcolor */
class Usersettings extends Illuminate\Database\Eloquent\Model {
    protected $table = 'usersettings';

    public function user() {
        return $this->belongsTo('App\User', 'userid');
    }
}

//Edit: I already tried lowercasing the s. This typo might have snuck in copying it to SO, but the error was there, and still is there, even after fixing it.

//Edit:

<?php

namespace App;

use App\UserSettings;

class User extends Illuminate\Database\Eloquent\Model {
    protected $table = 'users';

    public function settings() {
        return $this->hasOne(UserSettings::class, "userid");
    }
}

If I run php artisan tinker >>> App\\User::with('settings')->get() , it works as expected, but below

<?php

namespace App;

use App\UserSettings;

class User extends Illuminate\Database\Eloquent\Model {
    protected $table = 'users';

    public function usersettings() {
        return $this->hasOne(UserSettings::class, "userid");
    }
}

gives BadMethodCallException with message 'Call to undefined method Illuminate\\Database\\Query\\Builder::usersettings()' when I run php artisan tinker >>> App\\User::with('usersettings')->get() . Likewise when I rename the method to abc and run php artisan tinker >>> App\\User::with('abc')->get() (that fails as well)

You mistyped when defining the relation on the User model:

public function usersettings() {
    return $this->hasOne("App\Usersettings", "userid");
}

I would suggest some cleanup: name the tables 'users' and 'user_settings', rename the field 'userid' to 'user_id', rename the 'Usersettings' model to 'UserSettings'.

That way you dont need to explicitly define table names and foreign keys, because you follow the conventions and Laravel can "guess" those.

You can also rename the the relation 'usersettings()' to 'settings()', since its obvious that they're the users' settings. Then you can fetch it like: 'User::with('settings')->get()'.

Did you try running composer dump-autoload after you changed your model relationships?

Just to make sure you're aware of this: you don't actually need to define the relationship in your UserSettings model to achieve what you want, only define the relationship in the User model. This is because you'd only need to get the settings in the context of the User, not the other way around.

Code for the User model:

<?php

namespace App;

use App\UserSettings;

class User extends Illuminate\Database\Eloquent\Model {

    public function userSettings() {
        return $this->hasOne(UserSettings::class);
    }
}

UserSettings model: make sure it's camel case and that userid is present in your migration (the convention in your case would be to have user_id , so I would rename that column in your migration because then Eloquent will pick it up automatically and you don't need the second parameter in your User model's hasOne() definition). Also, rename your table to user_settings if you can. That's another Eloquent convention, this one being that the model name UserSettings translates the camel case S letter in the middle of the classname to _ (and as a matter of fact, you shouldn't even need to explicitly state the table name if you've used the name user_settings ).

Code for the UserSettings model:

<?php

namespace App;

/* Settings with fields: id, userid, textcolor */
class UserSettings extends Illuminate\Database\Eloquent\Model {
    protected $table = 'user_settings';
}

Now, you should be able to do the below action. Note that the with parameter needs to be the relation function name from the User model.

$usersThatHaveSettingsIncludedInTheResults = User::with('userSettings')->get();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM