Skip to content

Commit

Permalink
Fix Type Mismatch in Polymorphic Relationships When Using PostgreSQL
Browse files Browse the repository at this point in the history
fixes #54401

Signed-off-by: Mior Muhammad Zaki <[email protected]>
  • Loading branch information
crynobone committed Jan 31, 2025
1 parent 8509637 commit 55e2c1f
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 6 deletions.
14 changes: 13 additions & 1 deletion src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Schema\Builder as SchemaBuilder;
use Illuminate\Support\Str;

/**
Expand Down Expand Up @@ -58,7 +59,18 @@ public function addConstraints()
if (static::$constraints) {
$this->getRelationQuery()->where($this->morphType, $this->morphClass);

parent::addConstraints();
if (is_null(SchemaBuilder::$defaultMorphKeyType)) {
parent::addConstraints();
} else {
$query = $this->getRelationQuery();

$query->where($this->foreignKey, '=', transform($this->getParentKey(), fn ($key) => match (SchemaBuilder::$defaultMorphKeyType) {
'uuid', 'ulid', 'string' => (string) $key,
default => $key,
}));

$query->whereNotNull($this->foreignKey);
}
}
}

Expand Down
36 changes: 36 additions & 0 deletions src/Illuminate/Database/Schema/Blueprint.php
Original file line number Diff line number Diff line change
Expand Up @@ -1486,6 +1486,8 @@ public function morphs($name, $indexName = null)
$this->uuidMorphs($name, $indexName);
} elseif (Builder::$defaultMorphKeyType === 'ulid') {
$this->ulidMorphs($name, $indexName);
} elseif (Builder::$defaultMorphKeyType === 'string') {
$this->stringableMorphs($name, $indexName);
} else {
$this->numericMorphs($name, $indexName);
}
Expand All @@ -1504,11 +1506,45 @@ public function nullableMorphs($name, $indexName = null)
$this->nullableUuidMorphs($name, $indexName);
} elseif (Builder::$defaultMorphKeyType === 'ulid') {
$this->nullableUlidMorphs($name, $indexName);
} elseif (Builder::$defaultMorphKeyType === 'string') {
$this->nullableStringableMorphs($name, $indexName);
} else {
$this->nullableNumericMorphs($name, $indexName);
}
}

/**
* Add the proper columns for a polymorphic table using string as IDs (mixed of UUID/ULID & incremental integer).
*
* @param string $name
* @param string|null $indexName
* @return void
*/
public function stringableMorphs($name, $indexName = null)
{
$this->string("{$name}_type");

$this->string("{$name}_id");

$this->index(["{$name}_type", "{$name}_id"], $indexName);
}

/**
* Add nullable columns for a polymorphic table using string as IDs (mixed of UUID/ULID & incremental integer).
*
* @param string $name
* @param string|null $indexName
* @return void
*/
public function nullableStringableMorphs($name, $indexName = null)
{
$this->string("{$name}_type")->nullable();

$this->string("{$name}_id")->nullable();

$this->index(["{$name}_type", "{$name}_id"], $indexName);
}

/**
* Add the proper columns for a polymorphic table using numeric IDs (incremental).
*
Expand Down
18 changes: 14 additions & 4 deletions src/Illuminate/Database/Schema/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ class Builder
/**
* The default relationship morph key type.
*
* @var string
* @var string|null
*/
public static $defaultMorphKeyType = 'int';
public static $defaultMorphKeyType = null;

/**
* Create a new database Schema manager.
Expand Down Expand Up @@ -81,8 +81,8 @@ public static function defaultStringLength($length)
*/
public static function defaultMorphKeyType(string $type)
{
if (! in_array($type, ['int', 'uuid', 'ulid'])) {
throw new InvalidArgumentException("Morph key type must be 'int', 'uuid', or 'ulid'.");
if (! in_array($type, ['int', 'uuid', 'ulid', 'string'])) {
throw new InvalidArgumentException("Morph key type must be 'int', 'uuid', 'ulid', or 'string'.");
}

static::$defaultMorphKeyType = $type;
Expand All @@ -108,6 +108,16 @@ public static function morphUsingUlids()
static::defaultMorphKeyType('ulid');
}

/**
* Set the default morph key type for migrations to string as IDs (mixed of UUID/ULID & incremental integer).
*
* @return void
*/
public static function morphUsingString()
{
static::defaultMorphKeyType('string');
}

/**
* Create a database in the schema.
*
Expand Down
2 changes: 1 addition & 1 deletion tests/Database/DatabaseSchemaBlueprintTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class DatabaseSchemaBlueprintTest extends TestCase
protected function tearDown(): void
{
m::close();
Builder::$defaultMorphKeyType = 'int';
Builder::$defaultMorphKeyType = null;
}

public function testToSqlRunsCommandsFromBlueprint()
Expand Down

0 comments on commit 55e2c1f

Please sign in to comment.