From c66dce30a5a220fcb9168fae7f0a0660c4094f0a Mon Sep 17 00:00:00 2001 From: Ion Bazan Date: Tue, 23 Apr 2024 02:31:04 +0800 Subject: [PATCH] Guess inverse relationship name if not provided (#2) Co-authored-by: Alex Bouma --- .github/workflows/ci.yaml | 2 +- src/HasHasManyWithInverseRelation.php | 8 ++++++-- src/HasHasOneWithInverseRelation.php | 8 ++++++-- tests/Stubs/HasManyWithInverse/ChildModel.php | 5 +++++ tests/Stubs/HasManyWithInverse/ParentModel.php | 6 ++++++ tests/Stubs/HasOneWithInverse/ChildModel.php | 5 +++++ tests/Stubs/HasOneWithInverse/ParentModel.php | 6 ++++++ tests/Unit/HasManyWithInverseTest.php | 11 +++++++++++ tests/Unit/HasOneWithInverseTest.php | 11 +++++++++++ 9 files changed, 57 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 444abfe..5c6158b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - php: [ "8.3", "8.2", "8.1", "8.0", "7.4", "7.3" ] + php: [ "8.4", "8.3", "8.2", "8.1", "8.0", "7.4", "7.3" ] name: phpunit (PHP:${{ matrix.php }}) diff --git a/src/HasHasManyWithInverseRelation.php b/src/HasHasManyWithInverseRelation.php index 016d029..79c105e 100644 --- a/src/HasHasManyWithInverseRelation.php +++ b/src/HasHasManyWithInverseRelation.php @@ -2,12 +2,16 @@ namespace Stayallive\Laravel\Eloquent\Relations; +use Illuminate\Support\Str; + trait HasHasManyWithInverseRelation { - public function hasManyWithInverse($related, $inverse, $foreignKey = null, $localKey = null): HasManyWithInverseRelation + public function hasManyWithInverse($related, $inverse = null, $foreignKey = null, $localKey = null): HasManyWithInverseRelation { /** @var \Illuminate\Database\Eloquent\Model $this */ - $instance = $this->newRelatedInstance($related); + $instance = $this->newRelatedInstance($related); + + $inverse = $inverse ?: Str::camel(class_basename($this)); $localKey = $localKey ?: $this->getKeyName(); $foreignKey = $foreignKey ?: $this->getForeignKey(); diff --git a/src/HasHasOneWithInverseRelation.php b/src/HasHasOneWithInverseRelation.php index ed8be2f..6c398c2 100644 --- a/src/HasHasOneWithInverseRelation.php +++ b/src/HasHasOneWithInverseRelation.php @@ -2,12 +2,16 @@ namespace Stayallive\Laravel\Eloquent\Relations; +use Illuminate\Support\Str; + trait HasHasOneWithInverseRelation { - public function hasOneWithInverse($related, $inverse, $foreignKey = null, $localKey = null): HasOneWithInverseRelation + public function hasOneWithInverse($related, $inverse = null, $foreignKey = null, $localKey = null): HasOneWithInverseRelation { /** @var \Illuminate\Database\Eloquent\Model $this */ - $instance = $this->newRelatedInstance($related); + $instance = $this->newRelatedInstance($related); + + $inverse = $inverse ?: Str::camel(class_basename($this)); $localKey = $localKey ?: $this->getKeyName(); $foreignKey = $foreignKey ?: $this->getForeignKey(); diff --git a/tests/Stubs/HasManyWithInverse/ChildModel.php b/tests/Stubs/HasManyWithInverse/ChildModel.php index e9735b7..c88ac3f 100644 --- a/tests/Stubs/HasManyWithInverse/ChildModel.php +++ b/tests/Stubs/HasManyWithInverse/ChildModel.php @@ -16,4 +16,9 @@ public function parent(): BelongsTo { return $this->belongsTo(ParentModel::class, 'parent_id'); } + + public function parentModel(): BelongsTo + { + return $this->belongsTo(ParentModel::class, 'parent_id'); + } } diff --git a/tests/Stubs/HasManyWithInverse/ParentModel.php b/tests/Stubs/HasManyWithInverse/ParentModel.php index 2abde9f..47b2886 100644 --- a/tests/Stubs/HasManyWithInverse/ParentModel.php +++ b/tests/Stubs/HasManyWithInverse/ParentModel.php @@ -9,6 +9,7 @@ /** * @property int $id * @property \Illuminate\Database\Eloquent\Collection $children + * @property \Illuminate\Database\Eloquent\Collection $childrenDefaultInverse */ class ParentModel extends Model { @@ -24,4 +25,9 @@ public function children(): HasMany // The `parent` argument (second) is the name of the inverse relationship as defined in the ChildModel return $this->hasManyWithInverse(ChildModel::class, 'parent', 'parent_id'); } + + public function childrenDefaultInverse(): HasMany + { + return $this->hasManyWithInverse(ChildModel::class, null, 'parent_id'); + } } diff --git a/tests/Stubs/HasOneWithInverse/ChildModel.php b/tests/Stubs/HasOneWithInverse/ChildModel.php index ac0a4eb..62cbe7a 100644 --- a/tests/Stubs/HasOneWithInverse/ChildModel.php +++ b/tests/Stubs/HasOneWithInverse/ChildModel.php @@ -16,4 +16,9 @@ public function parent(): BelongsTo { return $this->belongsTo(ParentModel::class, 'parent_id'); } + + public function parentModel(): BelongsTo + { + return $this->belongsTo(ParentModel::class, 'parent_id'); + } } diff --git a/tests/Stubs/HasOneWithInverse/ParentModel.php b/tests/Stubs/HasOneWithInverse/ParentModel.php index 35edaff..a01f3ae 100644 --- a/tests/Stubs/HasOneWithInverse/ParentModel.php +++ b/tests/Stubs/HasOneWithInverse/ParentModel.php @@ -9,6 +9,7 @@ /** * @property int $id * @property \Tests\Stubs\HasOneWithInverse\ChildModel $child + * @property \Tests\Stubs\HasOneWithInverse\ChildModel $childDefaultInverse */ class ParentModel extends Model { @@ -24,4 +25,9 @@ public function child(): HasOne // The `parent` argument (second) is the name of the inverse relationship as defined in the ChildModel return $this->hasOneWithInverse(ChildModel::class, 'parent', 'parent_id'); } + + public function childDefaultInverse(): HasOne + { + return $this->hasOneWithInverse(ChildModel::class, null, 'parent_id'); + } } diff --git a/tests/Unit/HasManyWithInverseTest.php b/tests/Unit/HasManyWithInverseTest.php index 21464e0..70ba7ff 100644 --- a/tests/Unit/HasManyWithInverseTest.php +++ b/tests/Unit/HasManyWithInverseTest.php @@ -19,6 +19,17 @@ }); }); +test('inverse relationship name can be automatically guessed if not provided', function () { + /** @var \Tests\Stubs\HasManyWithInverse\ParentModel $parent */ + $parent = ParentModel::create([]); + + /** @var \Tests\Stubs\HasManyWithInverse\ChildModel $child */ + $child = $parent->childrenDefaultInverse()->create([]); + + expect($child->relationLoaded('parentModel'))->toBeTrue(); + expect($child->getRelations()['parentModel']->id)->toBe($parent->id); +}); + test('children have the parent relationship automatically set when being created', function () { /** @var \Tests\Stubs\HasManyWithInverse\ParentModel $parent */ $parent = ParentModel::create([]); diff --git a/tests/Unit/HasOneWithInverseTest.php b/tests/Unit/HasOneWithInverseTest.php index c2dc7b1..ef256ad 100644 --- a/tests/Unit/HasOneWithInverseTest.php +++ b/tests/Unit/HasOneWithInverseTest.php @@ -19,6 +19,17 @@ }); }); +test('inverse relationship name can be automatically guessed if not provided', function () { + /** @var \Tests\Stubs\HasOneWithInverse\ParentModel $parent */ + $parent = ParentModel::create([]); + + /** @var \Tests\Stubs\HasOneWithInverse\ChildModel $child */ + $child = $parent->childDefaultInverse()->create([]); + + expect($child->relationLoaded('parentModel'))->toBeTrue(); + expect($child->getRelations()['parentModel']->id)->toBe($parent->id); +}); + test('child has the parent relationship automatically set when being created', function () { /** @var \Tests\Stubs\HasOneWithInverse\ParentModel $parent */ $parent = ParentModel::create([]);