Framework: MorphTo when changing db connection

Created on 10 Sep 2019  路  11Comments  路  Source: laravel/framework

  • Laravel Version: 5.8.33
  • PHP Version: 7.2.15
  • Database Driver & Version: pgsql

Description:

MorphTo does not work when changing db connection.

Steps To Reproduce:

  1. Two identical databases - A end B
  2. Default connection - A
  3. The model Model contains:
public function element(): MorphTo
    {
        return $this->morphTo();
    }

4.
$model = Model::with('element')->first();
$model->element contains object.

$model = Model::on('B')->with('element')->first();
$model->element is null
$model = $model -> load('element');
$model->element is null
$element = $model -> element() -> first();
$element is object.

  1. Set default connection to B.
    $model = Model::with('element')->first();
    $model->element contains object.

$model = Model::on('A')->with('element')->first();
$model->element is null

bug

Most helpful comment

I can reproduce this.

All 11 comments

@klimby can you upgrade to 6.0 and see if the problem persists? I know quite some fixes to Eloquent have been made recently.

Updated to 6.0. Unfortunately, the problem is relevant.

I can reproduce this.

It works well with MySQL. Is this issue only occur with Postgres driver?

@adhyapranata The issue affects all databases.

I couldn't reproduce this issue running Laravel 6.4.1 with MariaBD 10.3.16.

@straube can you try mysql or postgres?

@driesvints, @klimby, I traced the issue & found out that at @createModelByType, Eloquent lose track of the connection.

This workaround fixed the issue :

public function createModelByType($type)
{
    $class = Model::getActualClassNameForMorph($type);

    return (new $class)->setConnection($this->getConnection()->getName());
}

but it messes up with @testMorphToRelationsAcrossDatabaseConnections, as the test expects the Morph models to work on different connections (so the MorphTo model should define its connection by its own not using the other model).

This behavior seems totally right, as if we change it, then the ::on() method would override the protected $connection attribute, which probably breaks lots of logics.

Now I'm not sure if it's actually a bug or a planned feature. :thinking:

@staudenmeir can you confirm the above? Is the current behavior correct?

AFAICS, we need to mimic the behavior of all other relationships and only set the connection on the related model if the parent model is _not_ using the default connection.

https://github.com/laravel/framework/blob/005cad6a8e8577cb16c7e54e5d2a1a4df9ba06d4/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php#L716-L723

This fixes the issue for me and doesn't break testMorphToRelationsAcrossDatabaseConnections().

@staudenmeir you're right, that did work for me as well.
I thought getConnectionName would fallback to parent class's property.
I'm making a PR for this.

Was this page helpful?
0 / 5 - 0 ratings