From 55e2c1ff302f56b7eadf76f73ea074f53edfc406 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Thu, 30 Jan 2025 17:31:08 +0800 Subject: [PATCH 01/23] Fix Type Mismatch in Polymorphic Relationships When Using PostgreSQL fixes #54401 Signed-off-by: Mior Muhammad Zaki --- .../Eloquent/Relations/MorphOneOrMany.php | 14 +++++++- src/Illuminate/Database/Schema/Blueprint.php | 36 +++++++++++++++++++ src/Illuminate/Database/Schema/Builder.php | 18 +++++++--- .../Database/DatabaseSchemaBlueprintTest.php | 2 +- 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php index 44531957d5b7..ea8fdf614044 100755 --- a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php @@ -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; /** @@ -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); + } } } diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index ca2eed4eb55b..603b2dedd657 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -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); } @@ -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). * diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 9af11e2e0836..bd1f2dcaab74 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -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. @@ -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; @@ -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. * diff --git a/tests/Database/DatabaseSchemaBlueprintTest.php b/tests/Database/DatabaseSchemaBlueprintTest.php index f92672b2f63e..b5a0facade8f 100755 --- a/tests/Database/DatabaseSchemaBlueprintTest.php +++ b/tests/Database/DatabaseSchemaBlueprintTest.php @@ -19,7 +19,7 @@ class DatabaseSchemaBlueprintTest extends TestCase protected function tearDown(): void { m::close(); - Builder::$defaultMorphKeyType = 'int'; + Builder::$defaultMorphKeyType = null; } public function testToSqlRunsCommandsFromBlueprint() From edbc095bc6678709d5fbe385763b987935a08f80 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Fri, 31 Jan 2025 21:06:08 +0800 Subject: [PATCH 02/23] wip Signed-off-by: Mior Muhammad Zaki --- .../Eloquent/Relations/MorphOneOrMany.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php index ea8fdf614044..f964ff27c615 100755 --- a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php @@ -5,6 +5,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Schema\Builder as SchemaBuilder; +use Illuminate\Support\Collection; use Illuminate\Support\Str; /** @@ -54,6 +55,7 @@ public function __construct(Builder $query, Model $parent, $type, $id, $localKey * * @return void */ + #[\Override] public function addConstraints() { if (static::$constraints) { @@ -75,6 +77,7 @@ public function addConstraints() } /** @inheritDoc */ + #[\Override] public function addEagerConstraints(array $models) { parent::addEagerConstraints($models); @@ -125,6 +128,7 @@ protected function setForeignAttributesForCreate(Model $model) * @param array|null $update * @return int */ + #[\Override] public function upsert(array $values, $uniqueBy, $update = null) { if (! empty($values) && ! is_array(reset($values))) { @@ -139,6 +143,7 @@ public function upsert(array $values, $uniqueBy, $update = null) } /** @inheritDoc */ + #[\Override] public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*']) { return parent::getRelationExistenceQuery($query, $parentQuery, $columns)->where( @@ -188,4 +193,27 @@ protected function getPossibleInverseRelations(): array ...parent::getPossibleInverseRelations(), ]); } + + /** @inheritDoc */ + #[\Override] + protected function getKeys(array $models, $key = null) + { + $castKeyToString = in_array(SchemaBuilder::$defaultMorphKeyType, ['uuid', 'ulid', 'string']); + + return (new Collection(parent::getKeys($models, $key))) + ->transform(function ($key) use ($castKeyToString) { + return $castKeyToString === true ? (string) $key : $key; + })->all(); + } + + /** @inheritDoc */ + #[\Override] + protected function whereInMethod(Model $model, $key) + { + if (! in_array(SchemaBuilder::$defaultMorphKeyType, ['uuid', 'ulid', 'string'])) { + return parent::whereInMethod($model, $key); + } + + return 'whereIn'; + } } From 4a6cf30faa25646ea3dc2c9a7a5f860e9c573434 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Fri, 31 Jan 2025 21:44:56 +0800 Subject: [PATCH 03/23] wip Signed-off-by: Mior Muhammad Zaki --- ...uentPolymorphicWithStringMorphTypeTest.php | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php diff --git a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php new file mode 100644 index 000000000000..94235a7c4ce1 --- /dev/null +++ b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php @@ -0,0 +1,90 @@ +id(); + $table->nullableMorphs('owner'); + $table->string('provider'); + }); + + $user = UserFactory::new()->create([ + 'name' => 'Taylor Otwell', + 'email' => 'taylor@laravel.com', + 'password' => bcrypt('password'), + ]); + + DB::table('integrations')->insert([ + 'owner_type' => User::class, + 'owner_id' => $user->id, + 'provider' => 'dummy_provider' + ]); + } + + public function test_it_can_query_using_load_missing() + { + $user = User::query()->where('email', 'taylor@laravel.com')->first(); + + $user->loadMissing('integrations'); + + Assert::assertArraySubset([ + 'name' => 'Taylor Otwell', + 'integrations' => [ + ['owner_type' => User::class, 'owner_id' => $user->getKey(), 'provider' => 'dummy_provider'], + ], + ], $user->toArray()); + } +} + +class User extends Authenticatable +{ + protected $fillable = ['*']; + + public function integrations() + { + return $this->morphMany(Integration::class, 'owner'); + } +} + +class Integration extends Model +{ + protected $fillable = ['*']; + + public function owner() + { + return $this->morphTo('owner'); + } +} + From 623d9056d84af32c0b4d9da0467a0cf198ce178a Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Fri, 31 Jan 2025 13:45:56 +0000 Subject: [PATCH 04/23] Apply fixes from StyleCI --- .../Database/EloquentPolymorphicWithStringMorphTypeTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php index 94235a7c4ce1..fce6cadf3b2a 100644 --- a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php +++ b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php @@ -49,7 +49,7 @@ protected function afterRefreshingDatabase() DB::table('integrations')->insert([ 'owner_type' => User::class, 'owner_id' => $user->id, - 'provider' => 'dummy_provider' + 'provider' => 'dummy_provider', ]); } @@ -87,4 +87,3 @@ public function owner() return $this->morphTo('owner'); } } - From 3b03f9429df50f98629c3d2af7997c20e14ca839 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Fri, 31 Jan 2025 21:48:55 +0800 Subject: [PATCH 05/23] wip Signed-off-by: Mior Muhammad Zaki --- ...uentPolymorphicWithStringMorphTypeTest.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php index 94235a7c4ce1..58aa2f7cdaf8 100644 --- a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php +++ b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php @@ -53,6 +53,26 @@ protected function afterRefreshingDatabase() ]); } + public function test_it_can_query_from_polymorphic_model() + { + $user = User::first(); + + $user->loadMissing('integrations'); + + Assert::assertArraySubset([ + ['owner_type' => User::class, 'owner_id' => $user->getKey(), 'provider' => 'dummy_provider'], + ], Integration::where('owner_id', $user->id)->where('owner_type', User::class)->get()->toArray()); + } + + public function test_it_can_query_using_relationship() + { + $user = User::first(); + + Assert::assertArraySubset([ + ['owner_type' => User::class, 'owner_id' => $user->getKey(), 'provider' => 'dummy_provider'], + ], $user->integrations()->get()->toArray()); + } + public function test_it_can_query_using_load_missing() { $user = User::query()->where('email', 'taylor@laravel.com')->first(); From a2504e0d44b12847cf0b958e1bc836cc0fc04fb3 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Fri, 31 Jan 2025 21:52:27 +0800 Subject: [PATCH 06/23] wip Signed-off-by: Mior Muhammad Zaki --- ...uentPolymorphicWithStringMorphTypeTest.php | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php index 58aa2f7cdaf8..5d2b0546183d 100644 --- a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php +++ b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php @@ -47,7 +47,7 @@ protected function afterRefreshingDatabase() ]); DB::table('integrations')->insert([ - 'owner_type' => User::class, + 'owner_type' => EloquentPolymorphicWithStringMorphTypeTestUser::class, 'owner_id' => $user->id, 'provider' => 'dummy_provider' ]); @@ -55,52 +55,54 @@ protected function afterRefreshingDatabase() public function test_it_can_query_from_polymorphic_model() { - $user = User::first(); + $user = EloquentPolymorphicWithStringMorphTypeTestUser::first(); $user->loadMissing('integrations'); Assert::assertArraySubset([ - ['owner_type' => User::class, 'owner_id' => $user->getKey(), 'provider' => 'dummy_provider'], - ], Integration::where('owner_id', $user->id)->where('owner_type', User::class)->get()->toArray()); + ['owner_type' => EloquentPolymorphicWithStringMorphTypeTestUser::class, 'owner_id' => $user->getKey(), 'provider' => 'dummy_provider'], + ], EloquentPolymorphicWithStringMorphTypeTestIntegration::where('owner_id', $user->id)->where('owner_type', EloquentPolymorphicWithStringMorphTypeTestUser::class)->get()->toArray()); } public function test_it_can_query_using_relationship() { - $user = User::first(); + $user = EloquentPolymorphicWithStringMorphTypeTestUser::first(); Assert::assertArraySubset([ - ['owner_type' => User::class, 'owner_id' => $user->getKey(), 'provider' => 'dummy_provider'], + ['owner_type' => EloquentPolymorphicWithStringMorphTypeTestUser::class, 'owner_id' => $user->getKey(), 'provider' => 'dummy_provider'], ], $user->integrations()->get()->toArray()); } public function test_it_can_query_using_load_missing() { - $user = User::query()->where('email', 'taylor@laravel.com')->first(); + $user = EloquentPolymorphicWithStringMorphTypeTestUser::query()->where('email', 'taylor@laravel.com')->first(); $user->loadMissing('integrations'); Assert::assertArraySubset([ 'name' => 'Taylor Otwell', 'integrations' => [ - ['owner_type' => User::class, 'owner_id' => $user->getKey(), 'provider' => 'dummy_provider'], + ['owner_type' => EloquentPolymorphicWithStringMorphTypeTestUser::class, 'owner_id' => $user->getKey(), 'provider' => 'dummy_provider'], ], ], $user->toArray()); } } -class User extends Authenticatable +class EloquentPolymorphicWithStringMorphTypeTestUser extends Authenticatable { protected $fillable = ['*']; + protected $table = 'users'; public function integrations() { - return $this->morphMany(Integration::class, 'owner'); + return $this->morphMany(EloquentPolymorphicWithStringMorphTypeTestIntegration::class, 'owner'); } } -class Integration extends Model +class EloquentPolymorphicWithStringMorphTypeTestIntegration extends Model { protected $fillable = ['*']; + protected $table = 'integrations'; public function owner() { From e744b1165f4b516b7b71653de7109bbcb0009d85 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Fri, 31 Jan 2025 21:55:10 +0800 Subject: [PATCH 07/23] wip Signed-off-by: Mior Muhammad Zaki --- .../Database/EloquentPolymorphicWithStringMorphTypeTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php index 118fd306d22a..83bd71c41382 100644 --- a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php +++ b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php @@ -43,7 +43,6 @@ protected function afterRefreshingDatabase() $user = UserFactory::new()->create([ 'name' => 'Taylor Otwell', 'email' => 'taylor@laravel.com', - 'password' => bcrypt('password'), ]); DB::table('integrations')->insert([ From 210096b62b7d69f1f7b55557ab9fc43fb9345f66 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Sat, 1 Feb 2025 14:08:05 +0800 Subject: [PATCH 08/23] Update MorphOneOrMany.php --- .../Database/Eloquent/Relations/MorphOneOrMany.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php index f964ff27c615..36436037e75f 100755 --- a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php @@ -201,9 +201,8 @@ protected function getKeys(array $models, $key = null) $castKeyToString = in_array(SchemaBuilder::$defaultMorphKeyType, ['uuid', 'ulid', 'string']); return (new Collection(parent::getKeys($models, $key))) - ->transform(function ($key) use ($castKeyToString) { - return $castKeyToString === true ? (string) $key : $key; - })->all(); + ->transform(fn ($key) => $castKeyToString === true ? (string) $key : $key) + ->all(); } /** @inheritDoc */ From 7928ee37480f7f4cbd533bbce9e55a3910c68cf4 Mon Sep 17 00:00:00 2001 From: Mathias Grimm Date: Mon, 24 Feb 2025 03:21:57 -0300 Subject: [PATCH 09/23] wip (#54728) * wip * Apply fixes from StyleCI * wip * wip --------- Co-authored-by: StyleCI Bot Co-authored-by: Mior Muhammad Zaki --- .../Eloquent/Relations/MorphOneOrMany.php | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php index 36436037e75f..550db9535726 100755 --- a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php @@ -31,6 +31,15 @@ abstract class MorphOneOrMany extends HasOneOrMany */ protected $morphClass; + protected $morphKeyTypeString; + + public function morphKeyTypeString($morphKeyTypeString = true) + { + $this->morphKeyTypeString = $morphKeyTypeString; + + return $this; + } + /** * Create a new morph one or many relationship instance. * @@ -63,16 +72,18 @@ public function 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); + return; } + + $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); } } @@ -198,7 +209,11 @@ protected function getPossibleInverseRelations(): array #[\Override] protected function getKeys(array $models, $key = null) { - $castKeyToString = in_array(SchemaBuilder::$defaultMorphKeyType, ['uuid', 'ulid', 'string']); + if (isset($this->morphKeyTypeString) && $this->morphKeyTypeString === true) { + $castKeyToString = true; + } else { + $castKeyToString = in_array(SchemaBuilder::$defaultMorphKeyType, ['uuid', 'ulid', 'string']); + } return (new Collection(parent::getKeys($models, $key))) ->transform(fn ($key) => $castKeyToString === true ? (string) $key : $key) @@ -209,7 +224,7 @@ protected function getKeys(array $models, $key = null) #[\Override] protected function whereInMethod(Model $model, $key) { - if (! in_array(SchemaBuilder::$defaultMorphKeyType, ['uuid', 'ulid', 'string'])) { + if (! in_array(SchemaBuilder::$defaultMorphKeyType, ['uuid', 'ulid', 'string']) && (! isset($this->morphKeyTypeString) || $this->morphKeyTypeString === false)) { return parent::whereInMethod($model, $key); } From a27115c8408329942228e3f772b274af5e18b712 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 10:26:37 +0800 Subject: [PATCH 10/23] wip Signed-off-by: Mior Muhammad Zaki --- .../Eloquent/Concerns/HasRelationships.php | 20 ++++--- .../Eloquent/Relations/MorphOneOrMany.php | 58 +++++++++++++++---- ...uentPolymorphicWithStringMorphTypeTest.php | 18 +----- 3 files changed, 61 insertions(+), 35 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index b991fd08227c..03ffeb76ef1d 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -330,16 +330,17 @@ protected function morphEagerTo($name, $type, $id, $ownerKey) * @param string $type * @param string $id * @param string|null $ownerKey + * @param string|null $morphKeyType * @return \Illuminate\Database\Eloquent\Relations\MorphTo<\Illuminate\Database\Eloquent\Model, $this> */ - protected function morphInstanceTo($target, $name, $type, $id, $ownerKey) + protected function morphInstanceTo($target, $name, $type, $id, $ownerKey, $morphKeyType) { $instance = $this->newRelatedInstance( static::getActualClassNameForMorph($target) ); return $this->newMorphTo( - $instance->newQuery(), $this, $id, $ownerKey ?? $instance->getKeyName(), $type, $name + $instance->newQuery(), $this, $id, $ownerKey ?? $instance->getKeyName(), $type, $name, $morphKeyType ); } @@ -355,11 +356,12 @@ protected function morphInstanceTo($target, $name, $type, $id, $ownerKey) * @param string|null $ownerKey * @param string $type * @param string $relation + * @param string|null $morphKeyType * @return \Illuminate\Database\Eloquent\Relations\MorphTo */ - protected function newMorphTo(Builder $query, Model $parent, $foreignKey, $ownerKey, $type, $relation) + protected function newMorphTo(Builder $query, Model $parent, $foreignKey, $ownerKey, $type, $relation, $morphKeyType) { - return new MorphTo($query, $parent, $foreignKey, $ownerKey, $type, $relation); + return new MorphTo($query, $parent, $foreignKey, $ownerKey, $type, $relation, $morphKeyType); } /** @@ -514,9 +516,10 @@ protected function newHasManyThrough(Builder $query, Model $farParent, Model $th * @param string|null $type * @param string|null $id * @param string|null $localKey + * @param string|null $morphKeyType * @return \Illuminate\Database\Eloquent\Relations\MorphMany */ - public function morphMany($related, $name, $type = null, $id = null, $localKey = null) + public function morphMany($related, $name, $type = null, $id = null, $localKey = null, $morphKeyType = null) { $instance = $this->newRelatedInstance($related); @@ -527,7 +530,7 @@ public function morphMany($related, $name, $type = null, $id = null, $localKey = $localKey = $localKey ?: $this->getKeyName(); - return $this->newMorphMany($instance->newQuery(), $this, $instance->qualifyColumn($type), $instance->qualifyColumn($id), $localKey); + return $this->newMorphMany($instance->newQuery(), $this, $instance->qualifyColumn($type), $instance->qualifyColumn($id), $localKey, $morphKeyType); } /** @@ -541,11 +544,12 @@ public function morphMany($related, $name, $type = null, $id = null, $localKey = * @param string $type * @param string $id * @param string $localKey + * @param string|null $morphKeyType * @return \Illuminate\Database\Eloquent\Relations\MorphMany */ - protected function newMorphMany(Builder $query, Model $parent, $type, $id, $localKey) + protected function newMorphMany(Builder $query, Model $parent, $type, $id, $localKey, $morphKeyType = null) { - return new MorphMany($query, $parent, $type, $id, $localKey); + return new MorphMany($query, $parent, $type, $id, $localKey, $morphKeyType); } /** diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php index 550db9535726..aa9921accff3 100755 --- a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php @@ -7,6 +7,7 @@ use Illuminate\Database\Schema\Builder as SchemaBuilder; use Illuminate\Support\Collection; use Illuminate\Support\Str; +use InvalidArgumentException; /** * @template TRelatedModel of \Illuminate\Database\Eloquent\Model @@ -31,11 +32,46 @@ abstract class MorphOneOrMany extends HasOneOrMany */ protected $morphClass; - protected $morphKeyTypeString; + /** + * The morph key type. + * + * @var string|null + */ + protected $morphKeyType = null; + - public function morphKeyTypeString($morphKeyTypeString = true) + /** + * Create a new morph one or many relationship instance. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param TDeclaringModel $parent + * @param string $foreignKey + * @param string $localKey + * @param string|null $morphKeyType + * @return void + */ + public function __construct(Builder $query, Model $parent, $foreignKey, $localKey, $morphKeyType = null) { - $this->morphKeyTypeString = $morphKeyTypeString; + parent::__construct($query, $parent, $foreignKey, $localKey); + + if (! is_null($morphKeyType)) { + $this->morphKeyType($morphKeyType); + } + } + + /** + * Define the morph key type. + * + * @param string $type + * @return $this + */ + public function morphKeyType(string $type) + { + if (! in_array($type, ['int', 'uuid', 'ulid', 'string'])) { + throw new InvalidArgumentException("Morph key type must be 'int', 'uuid', 'ulid', or 'string'."); + } + + $this->morphKeyType = $type; return $this; } @@ -78,7 +114,9 @@ public function addConstraints() $query = $this->getRelationQuery(); - $query->where($this->foreignKey, '=', transform($this->getParentKey(), fn ($key) => match (SchemaBuilder::$defaultMorphKeyType) { + $morphKeyType = $this->morphKeyType ?? SchemaBuilder::$defaultMorphKeyType; + + $query->where($this->foreignKey, '=', transform($this->getParentKey(), fn ($key) => match ($morphKeyType) { 'uuid', 'ulid', 'string' => (string) $key, default => $key, })); @@ -209,11 +247,9 @@ protected function getPossibleInverseRelations(): array #[\Override] protected function getKeys(array $models, $key = null) { - if (isset($this->morphKeyTypeString) && $this->morphKeyTypeString === true) { - $castKeyToString = true; - } else { - $castKeyToString = in_array(SchemaBuilder::$defaultMorphKeyType, ['uuid', 'ulid', 'string']); - } + $morphKeyType = $this->morphKeyType ?? SchemaBuilder::$defaultMorphKeyType; + + $castKeyToString = in_array($morphKeyType, ['uuid', 'ulid', 'string']); return (new Collection(parent::getKeys($models, $key))) ->transform(fn ($key) => $castKeyToString === true ? (string) $key : $key) @@ -224,7 +260,9 @@ protected function getKeys(array $models, $key = null) #[\Override] protected function whereInMethod(Model $model, $key) { - if (! in_array(SchemaBuilder::$defaultMorphKeyType, ['uuid', 'ulid', 'string']) && (! isset($this->morphKeyTypeString) || $this->morphKeyTypeString === false)) { + $morphKeyType = $this->morphKeyType ?? SchemaBuilder::$defaultMorphKeyType; + + if (! in_array($morphKeyType, ['uuid', 'ulid', 'string'])) { return parent::whereInMethod($model, $key); } diff --git a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php index 83bd71c41382..20bfb9c873ef 100644 --- a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php +++ b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php @@ -15,22 +15,6 @@ #[WithMigration] class EloquentPolymorphicWithStringMorphTypeTest extends DatabaseTestCase { - /** @inheritDoc */ - protected function setUp(): void - { - SchemaBuilder::morphUsingString(); - - parent::setUp(); - } - - /** @inheritDoc */ - protected function tearDown(): void - { - parent::tearDown(); - - SchemaBuilder::$defaultMorphKeyType = null; - } - /** @inheritDoc */ protected function afterRefreshingDatabase() { @@ -94,7 +78,7 @@ class EloquentPolymorphicWithStringMorphTypeTestUser extends Authenticatable public function integrations() { - return $this->morphMany(EloquentPolymorphicWithStringMorphTypeTestIntegration::class, 'owner'); + return $this->morphMany(EloquentPolymorphicWithStringMorphTypeTestIntegration::class, 'owner', morphKeyType: 'string'); } } From 940ec05aa8e5ca81e9984ad1ba4d7b464814c77a Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Mon, 7 Apr 2025 02:37:00 +0000 Subject: [PATCH 11/23] Apply fixes from StyleCI --- src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php | 1 - .../Database/EloquentPolymorphicWithStringMorphTypeTest.php | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php index 1872c00db450..fd6c7150dfd8 100755 --- a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php @@ -39,7 +39,6 @@ abstract class MorphOneOrMany extends HasOneOrMany */ protected $morphKeyType = null; - /** * Create a new morph one or many relationship instance. * diff --git a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php index 20bfb9c873ef..2264e554fdff 100644 --- a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php +++ b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php @@ -4,7 +4,6 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Schema\Blueprint; -use Illuminate\Database\Schema\Builder as SchemaBuilder; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; From a24a5e1560e718328035775ad2ae6d14bdcc458f Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 10:38:20 +0800 Subject: [PATCH 12/23] Update EloquentPolymorphicWithStringMorphTypeTest.php --- .../Database/EloquentPolymorphicWithStringMorphTypeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php index 2264e554fdff..082569151556 100644 --- a/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php +++ b/tests/Integration/Database/EloquentPolymorphicWithStringMorphTypeTest.php @@ -19,7 +19,7 @@ protected function afterRefreshingDatabase() { Schema::create('integrations', function (Blueprint $table) { $table->id(); - $table->nullableMorphs('owner'); + $table->nullableStringableMorphs('owner'); $table->string('provider'); }); From df81f7580c41f9629648aba41db9693e9ce06c30 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 10:40:51 +0800 Subject: [PATCH 13/23] wip Signed-off-by: Mior Muhammad Zaki --- .../Database/Eloquent/Concerns/HasRelationships.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index 03ffeb76ef1d..7819ac77019f 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -333,7 +333,7 @@ protected function morphEagerTo($name, $type, $id, $ownerKey) * @param string|null $morphKeyType * @return \Illuminate\Database\Eloquent\Relations\MorphTo<\Illuminate\Database\Eloquent\Model, $this> */ - protected function morphInstanceTo($target, $name, $type, $id, $ownerKey, $morphKeyType) + protected function morphInstanceTo($target, $name, $type, $id, $ownerKey, $morphKeyType = null) { $instance = $this->newRelatedInstance( static::getActualClassNameForMorph($target) @@ -359,7 +359,7 @@ protected function morphInstanceTo($target, $name, $type, $id, $ownerKey, $morph * @param string|null $morphKeyType * @return \Illuminate\Database\Eloquent\Relations\MorphTo */ - protected function newMorphTo(Builder $query, Model $parent, $foreignKey, $ownerKey, $type, $relation, $morphKeyType) + protected function newMorphTo(Builder $query, Model $parent, $foreignKey, $ownerKey, $type, $relation, $morphKeyType = null) { return new MorphTo($query, $parent, $foreignKey, $ownerKey, $type, $relation, $morphKeyType); } From 192f7f845fb39dc5d38bfea5171108b8092971d7 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 10:44:50 +0800 Subject: [PATCH 14/23] wip Signed-off-by: Mior Muhammad Zaki --- .../Eloquent/Relations/MorphOneOrMany.php | 28 +++++-------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php index fd6c7150dfd8..3cfdd0fad7bd 100755 --- a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php @@ -44,18 +44,23 @@ abstract class MorphOneOrMany extends HasOneOrMany * * @param \Illuminate\Database\Eloquent\Builder $query * @param TDeclaringModel $parent - * @param string $foreignKey + * @param string $type + * @param string $id * @param string $localKey * @param string|null $morphKeyType * @return void */ public function __construct(Builder $query, Model $parent, $foreignKey, $localKey, $morphKeyType = null) { - parent::__construct($query, $parent, $foreignKey, $localKey); + $this->morphType = $type; + + $this->morphClass = $parent->getMorphClass(); if (! is_null($morphKeyType)) { $this->morphKeyType($morphKeyType); } + + parent::__construct($query, $parent, $id, $localKey); } /** @@ -75,25 +80,6 @@ public function morphKeyType(string $type) return $this; } - /** - * Create a new morph one or many relationship instance. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param TDeclaringModel $parent - * @param string $type - * @param string $id - * @param string $localKey - * @return void - */ - public function __construct(Builder $query, Model $parent, $type, $id, $localKey) - { - $this->morphType = $type; - - $this->morphClass = $parent->getMorphClass(); - - parent::__construct($query, $parent, $id, $localKey); - } - /** * Set the base constraints on the relation query. * From acbe13b982433ed093be0528fe2115a8932a2501 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 10:48:23 +0800 Subject: [PATCH 15/23] wip Signed-off-by: Mior Muhammad Zaki --- src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php index 3cfdd0fad7bd..2d0161e07644 100755 --- a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php @@ -39,6 +39,7 @@ abstract class MorphOneOrMany extends HasOneOrMany */ protected $morphKeyType = null; + /** * Create a new morph one or many relationship instance. * @@ -50,7 +51,7 @@ abstract class MorphOneOrMany extends HasOneOrMany * @param string|null $morphKeyType * @return void */ - public function __construct(Builder $query, Model $parent, $foreignKey, $localKey, $morphKeyType = null) + public function __construct(Builder $query, Model $parent, $type, $id, $localKey, $morphKeyType = null) { $this->morphType = $type; From b21b912c3861e7e423a832dd44f7b622b6284d3c Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Mon, 7 Apr 2025 02:48:35 +0000 Subject: [PATCH 16/23] Apply fixes from StyleCI --- src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php index 2d0161e07644..b6f3d99f6707 100755 --- a/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php @@ -39,7 +39,6 @@ abstract class MorphOneOrMany extends HasOneOrMany */ protected $morphKeyType = null; - /** * Create a new morph one or many relationship instance. * From 3558fa91c85a305a4632673b12b3914013bcdb26 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 10:50:59 +0800 Subject: [PATCH 17/23] wip Signed-off-by: Mior Muhammad Zaki --- tests/Database/DatabaseEloquentRelationshipsTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Database/DatabaseEloquentRelationshipsTest.php b/tests/Database/DatabaseEloquentRelationshipsTest.php index 3bc33b89246a..81d4d9ec3c19 100644 --- a/tests/Database/DatabaseEloquentRelationshipsTest.php +++ b/tests/Database/DatabaseEloquentRelationshipsTest.php @@ -335,14 +335,14 @@ protected function newHasOne(Builder $query, Model $parent, $foreignKey, $localK return new CustomHasOne($query, $parent, $foreignKey, $localKey); } - protected function newMorphOne(Builder $query, Model $parent, $type, $id, $localKey) + protected function newMorphOne(Builder $query, Model $parent, $type, $id, $localKey, $morphKeyType = null) { - return new CustomMorphOne($query, $parent, $type, $id, $localKey); + return new CustomMorphOne($query, $parent, $type, $id, $localKey, $morphKeyType); } - protected function newMorphMany(Builder $query, Model $parent, $type, $id, $localKey) + protected function newMorphMany(Builder $query, Model $parent, $type, $id, $localKey, $morphKeyType = null) { - return new CustomMorphMany($query, $parent, $type, $id, $localKey); + return new CustomMorphMany($query, $parent, $type, $id, $localKey, $morphKeyType); } protected function newBelongsToMany(Builder $query, Model $parent, $table, $foreignPivotKey, $relatedPivotKey, From 37eefb0427f2883c3da09be111fe89625d368674 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 11:00:20 +0800 Subject: [PATCH 18/23] wip Signed-off-by: Mior Muhammad Zaki --- .../Eloquent/Concerns/HasRelationships.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index 7819ac77019f..22bdc6be5b7e 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -190,9 +190,10 @@ protected function newHasOneThrough(Builder $query, Model $farParent, Model $thr * @param string|null $type * @param string|null $id * @param string|null $localKey + * @param string|null $morphKeyType * @return \Illuminate\Database\Eloquent\Relations\MorphOne */ - public function morphOne($related, $name, $type = null, $id = null, $localKey = null) + public function morphOne($related, $name, $type = null, $id = null, $localKey = null, $morphKeyType = null) { $instance = $this->newRelatedInstance($related); @@ -200,7 +201,7 @@ public function morphOne($related, $name, $type = null, $id = null, $localKey = $localKey = $localKey ?: $this->getKeyName(); - return $this->newMorphOne($instance->newQuery(), $this, $instance->qualifyColumn($type), $instance->qualifyColumn($id), $localKey); + return $this->newMorphOne($instance->newQuery(), $this, $instance->qualifyColumn($type), $instance->qualifyColumn($id), $localKey, $morphKeyType); } /** @@ -214,11 +215,12 @@ public function morphOne($related, $name, $type = null, $id = null, $localKey = * @param string $type * @param string $id * @param string $localKey + * @param string|null $morphKeyType * @return \Illuminate\Database\Eloquent\Relations\MorphOne */ - protected function newMorphOne(Builder $query, Model $parent, $type, $id, $localKey) + protected function newMorphOne(Builder $query, Model $parent, $type, $id, $localKey, $morphKeyType = null) { - return new MorphOne($query, $parent, $type, $id, $localKey); + return new MorphOne($query, $parent, $type, $id, $localKey, $morphKeyType); } /** @@ -330,17 +332,16 @@ protected function morphEagerTo($name, $type, $id, $ownerKey) * @param string $type * @param string $id * @param string|null $ownerKey - * @param string|null $morphKeyType * @return \Illuminate\Database\Eloquent\Relations\MorphTo<\Illuminate\Database\Eloquent\Model, $this> */ - protected function morphInstanceTo($target, $name, $type, $id, $ownerKey, $morphKeyType = null) + protected function morphInstanceTo($target, $name, $type, $id, $ownerKey) { $instance = $this->newRelatedInstance( static::getActualClassNameForMorph($target) ); return $this->newMorphTo( - $instance->newQuery(), $this, $id, $ownerKey ?? $instance->getKeyName(), $type, $name, $morphKeyType + $instance->newQuery(), $this, $id, $ownerKey ?? $instance->getKeyName(), $type, $name ); } @@ -356,12 +357,11 @@ protected function morphInstanceTo($target, $name, $type, $id, $ownerKey, $morph * @param string|null $ownerKey * @param string $type * @param string $relation - * @param string|null $morphKeyType * @return \Illuminate\Database\Eloquent\Relations\MorphTo */ - protected function newMorphTo(Builder $query, Model $parent, $foreignKey, $ownerKey, $type, $relation, $morphKeyType = null) + protected function newMorphTo(Builder $query, Model $parent, $foreignKey, $ownerKey, $type, $relation) { - return new MorphTo($query, $parent, $foreignKey, $ownerKey, $type, $relation, $morphKeyType); + return new MorphTo($query, $parent, $foreignKey, $ownerKey, $type, $relation); } /** From b655f1ac71d9a3494c5192a8da2b4f4cb4f3b7b8 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 19:03:31 +0800 Subject: [PATCH 19/23] wip Signed-off-by: Mior Muhammad Zaki --- .../Eloquent/Concerns/HasRelationships.php | 4 ++++ src/Illuminate/Database/Eloquent/Model.php | 23 +++++++++++++++++++ src/Illuminate/Database/Schema/Blueprint.php | 22 +++++------------- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index 22bdc6be5b7e..b9b8e51a8e06 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -201,6 +201,8 @@ public function morphOne($related, $name, $type = null, $id = null, $localKey = $localKey = $localKey ?: $this->getKeyName(); + $morphKeyType ??= $this->getKeySchemaType(); + return $this->newMorphOne($instance->newQuery(), $this, $instance->qualifyColumn($type), $instance->qualifyColumn($id), $localKey, $morphKeyType); } @@ -530,6 +532,8 @@ public function morphMany($related, $name, $type = null, $id = null, $localKey = $localKey = $localKey ?: $this->getKeyName(); + $morphKeyType ??= $this->getKeySchemaType(); + return $this->newMorphMany($instance->newQuery(), $this, $instance->qualifyColumn($type), $instance->qualifyColumn($id), $localKey, $morphKeyType); } diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 44878f7bf880..15163531c579 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -1948,6 +1948,29 @@ public function getKeyType() return $this->keyType; } + + /** + * Get the schema key type. + * + * @return string + */ + public function getKeySchemaType() + { + if ($this->getKeyType() === 'int') { + return 'int'; + } + + $uses = class_uses_recursive($this); + + if (in_array(Concerns\HasUlids::class, $uses, true)) { + return 'ulid'; + } elseif (in_array(Concerns\HasUuids::class, $uses, true)) { + return 'uuid'; + } + + return 'string'; + } + /** * Set the data type for the primary key. * diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 603b2dedd657..82a99e051657 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -1039,23 +1039,13 @@ public function foreignIdFor($model, $column = null) $column = $column ?: $model->getForeignKey(); - if ($model->getKeyType() === 'int') { - return $this->foreignId($column) - ->table($model->getTable()) - ->referencesModelColumn($model->getKeyName()); - } - - $modelTraits = class_uses_recursive($model); - - if (in_array(HasUlids::class, $modelTraits, true)) { - return $this->foreignUlid($column, 26) - ->table($model->getTable()) - ->referencesModelColumn($model->getKeyName()); - } + $definition = match ($model->getKeySchemaType()) { + 'int' => $this->foreignId($column), + 'ulid' => $this->foreignUlid($column, 26), + default => $this->foreignUuid($column, 26), + }; - return $this->foreignUuid($column) - ->table($model->getTable()) - ->referencesModelColumn($model->getKeyName()); + return $definition->table($model->getTable())->referencesModelColumn($model->getKeyName()); } /** From 5229cc29e9841959847b785a23cb1e4ba0f5473d Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Mon, 7 Apr 2025 11:03:47 +0000 Subject: [PATCH 20/23] Apply fixes from StyleCI --- src/Illuminate/Database/Eloquent/Model.php | 1 - src/Illuminate/Database/Schema/Blueprint.php | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 15163531c579..f570513e7de1 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -1948,7 +1948,6 @@ public function getKeyType() return $this->keyType; } - /** * Get the schema key type. * diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 82a99e051657..e5238e0d6596 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -4,7 +4,6 @@ use Closure; use Illuminate\Database\Connection; -use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Grammars\Grammar; use Illuminate\Database\Schema\Grammars\MySqlGrammar; From 4f7670a5338b5c9914d2fb72b21bbc62d0cb210b Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 19:13:47 +0800 Subject: [PATCH 21/23] wip Signed-off-by: Mior Muhammad Zaki --- src/Illuminate/Database/Schema/Blueprint.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index e5238e0d6596..73d29a83f1ba 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -1041,7 +1041,7 @@ public function foreignIdFor($model, $column = null) $definition = match ($model->getKeySchemaType()) { 'int' => $this->foreignId($column), 'ulid' => $this->foreignUlid($column, 26), - default => $this->foreignUuid($column, 26), + default => $this->foreignUuid($column), }; return $definition->table($model->getTable())->referencesModelColumn($model->getKeyName()); From 231844791c35988e616c232542d285055a281e8f Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 19:15:24 +0800 Subject: [PATCH 22/23] wip Signed-off-by: Mior Muhammad Zaki --- .../Database/Eloquent/Concerns/HasRelationships.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index b9b8e51a8e06..6fc306dfa7d2 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -217,10 +217,10 @@ public function morphOne($related, $name, $type = null, $id = null, $localKey = * @param string $type * @param string $id * @param string $localKey - * @param string|null $morphKeyType + * @param string $morphKeyType * @return \Illuminate\Database\Eloquent\Relations\MorphOne */ - protected function newMorphOne(Builder $query, Model $parent, $type, $id, $localKey, $morphKeyType = null) + protected function newMorphOne(Builder $query, Model $parent, $type, $id, $localKey, $morphKeyType) { return new MorphOne($query, $parent, $type, $id, $localKey, $morphKeyType); } @@ -548,10 +548,10 @@ public function morphMany($related, $name, $type = null, $id = null, $localKey = * @param string $type * @param string $id * @param string $localKey - * @param string|null $morphKeyType + * @param string $morphKeyType * @return \Illuminate\Database\Eloquent\Relations\MorphMany */ - protected function newMorphMany(Builder $query, Model $parent, $type, $id, $localKey, $morphKeyType = null) + protected function newMorphMany(Builder $query, Model $parent, $type, $id, $localKey, $morphKeyType) { return new MorphMany($query, $parent, $type, $id, $localKey, $morphKeyType); } From 8d05e664c7277ae4fdfd8aae9f038cee6c9d8749 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Mon, 7 Apr 2025 20:16:25 +0800 Subject: [PATCH 23/23] wip Signed-off-by: Mior Muhammad Zaki --- src/Illuminate/Database/Eloquent/Model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index f570513e7de1..a52b39a0ec2e 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -1967,7 +1967,7 @@ public function getKeySchemaType() return 'uuid'; } - return 'string'; + return $this->getKeyType(); } /**