framework: Breaking change in relationships with additional where clauses due to PR #25240

  • Laravel Version: 5.6.34 and above
  • PHP Version: 7.1.x
  • Database Driver & Version: -

Description:

Our tests started failing after https://github.com/laravel/framework/pull/25240 was merged and tagged. This change was first tagged in 5.6.34

The problem we are having is that we are working with a legacy database that has some tables that have a structure that is similar to composite primary keys. As Laravel does not have support for composite primary keys, we worked around this by providing a where on the relationship that would append the second part of the “composite” primary key, like this:

class TestModel extends Model
{
    protected $primaryKey = 'identifier_1';

    public function relatedModel() {
        return $this->hasOne(RelatedModel::class, 'identifier_1', 'identifier_1')
            ->where(['identifier_2', '=', $this->identifier_2]);
    }
}

Then, somewhere later on we fetch a collection of models and then we need to lazy eager load the relationship on one of the models like this:

$collection = TestModel::where('x', '=', 'value')->get();

// ...

$collection->first()->load('relatedModel');

This has worked up until 5.6.33.

Since the change made in https://github.com/laravel/framework/pull/25240, however, this is not possible anymore because a new instance of the TestModel is created, which loses all attributes that were there before.

The $this->identifier_2 in ->where(['identifier_2', '=', $this->identifier_2]); will therefor be null and will return the wrong related model, or no model at all.

This has been reported (with a PR) before: https://github.com/laravel/framework/pull/25296 but this has been closed by the author, yet the breaking change is still present.

Steps To Reproduce:

See: https://github.com/RikSomers/LaravelRelationBug

Clone the repo then run the unit-test.

As is, they will fail because the composer.json will get the latest tag for laravel\framework: "laravel/framework": "5.6.*"

Now, edit the composer.json to fetch laravel\framework version 5.6.33: "laravel/framework": "5.6.33"

Run the tests again, and the tests will pass, proving the breaking change was introduced with Laravel 5.6.34 and above.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 1
  • Comments: 22 (10 by maintainers)

Commits related to this issue

Most upvoted comments

I just spent the past a few hours diagnosing a bug after a composer update. I have found that we are also having the same issue described above. Specifically, our hasOne composite relationship fails to load when a model is restored within SerializesModels.

Reverting Illuminate/Database/Eloquent/Builder line 546 to

return $this->getModel()->{$name}();

returns normal behavior.

Yes. It’s a shame that this behavior was “supported” and then suddenly dropped.

@devinfd Correct, this is also the line we found in #25252 that needed reverting.

Since Laravel doesn’t (and hasn’t ever afaik) supported composite keys and this issue is quite old I’m closing this. If anyone ever wants to try to tackle implementing support for composite keys feel free to open up an issue on the ideas repo to discuss how we’d best implement it while at the same time not introducing any breaking changes into Eloquent. Thanks for all the feedback here, hopefully someone can make this possible someday.

Does this have something related to #16217 or not?

No, the issue here is that the model data is not exposed when called via load.

I closed the referenced issue (#25296) because I realized you really can’t do eager loading on a relationship defined like that.

See this package’s README where it talks about the problem and then see its linked “Related discussions” for further explanation: https://github.com/topclaudy/compoships