Prevent accidental recursive nesting in hasMany/belongsTo

Posted 2 years ago by zakkolar

On my site, I have two models with a hasMany/belongsTo relationship: User hasMany Applications, and therefore an Application belongsTo a User. I've got these set up and they seem to be working correctly, and now I'm trying to optimize them. I've found several places where I can cut down on queries using eager loading, but I have a couple of scenarios where I have redundant database calls that I can't seem to get rid of. Essentially, my problem is this:

$user = App\User::find(1)
$user->applications->first()->user == $user
//returns false

$user and $user->applications->first()->user are the same User in the database, so I should be able to return the original $user that made the call instead of re-querying the database.

For those wondering, my "real life" scenario is more complicated than those two lines. The status of an Application is partially determined by whether or not a User has a complete profile (amongst other things). Because of this, there are methods inside of Application that need to access the corresponding User. This is fine by itself, but it gets redundant when I start with a User, retrieve its Applications, and call one of the methods I described. The database then is re-queried to find the User I began with.

I've experimented with throwing in eager loading, and I can get that to somewhat reduce the number of queries, but that still seems wrong because it leads to weird "inception" type relationships. If I call `$user = App\User::find(1)->with('applications', 'applications.user')->applications->first(), the returned object's structure is basically:

$user={
    someKey: someVal,
    ...
    applications:[
        {
            anotherKey:anotherVal,
            ...
            user:{
                //now this User is its own grandchild,
                //and every Application in this array will have a copy of this same User
            }
        },
        ...
    ]
}

I'm pretty new to Laravel so I don't have a firm grasp of everything that happens under the hood, but is there some way to extend with() to something like this:

$user = App\User::find(1)
$application = $user->applications->with(['user'=>$user])->first()

Where passing a key-object pair tells the internal Eloquent "magic" that I already have the specified key so it should return the existing object instead of retrieving it from the database?

Or, is there something that already exists that I can use to get around this?

Please sign in or create an account to participate in this conversation.

Reply to

Use Markdown with GitHub-flavored code blocks.