From 0eb283bd8e861229da31dbcace232463efdcbb28 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Tue, 20 Jun 2023 08:24:55 +0200 Subject: [PATCH] Support HasOneDeep relationships --- composer.json | 2 +- .../IsConcatenableBelongsToJsonRelation.php | 15 +++++++++++---- .../IsConcatenableHasManyJsonRelation.php | 17 +++++++++++++---- .../BelongsToJson/FirstPositionTest.php | 9 +++++++++ .../HasManyJson/FirstPositionTest.php | 9 +++++++++ tests/Models/Role.php | 6 ++++++ tests/Models/User.php | 6 ++++++ 7 files changed, 55 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 174afd0..6be6567 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "require-dev": { "phpunit/phpunit": "^9.5", "nesbot/carbon": "^2.62.1", - "staudenmeir/eloquent-has-many-deep": "^1.17" + "staudenmeir/eloquent-has-many-deep": "^1.17.2" }, "autoload": { "psr-4": { diff --git a/src/Relations/Traits/Concatenation/IsConcatenableBelongsToJsonRelation.php b/src/Relations/Traits/Concatenation/IsConcatenableBelongsToJsonRelation.php index bedd768..43d9ba8 100644 --- a/src/Relations/Traits/Concatenation/IsConcatenableBelongsToJsonRelation.php +++ b/src/Relations/Traits/Concatenation/IsConcatenableBelongsToJsonRelation.php @@ -57,10 +57,15 @@ public function appendToDeepRelationship(array $through, array $foreignKeys, arr * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation + * @param string $type * @return array */ - public function matchResultsForDeepRelationship(array $models, Collection $results, string $relation): array - { + public function matchResultsForDeepRelationship( + array $models, + Collection $results, + string $relation, + string $type = 'many' + ): array { $dictionary = $this->buildDictionaryForDeepRelationship($results); foreach ($models as $model) { @@ -72,9 +77,11 @@ public function matchResultsForDeepRelationship(array $models, Collection $resul } } - $collection = $this->related->newCollection($matches); + $value = $type === 'one' + ? (reset($matches) ?: null) + : $this->related->newCollection($matches); - $model->setRelation($relation, $collection); + $model->setRelation($relation, $value); } return $models; diff --git a/src/Relations/Traits/Concatenation/IsConcatenableHasManyJsonRelation.php b/src/Relations/Traits/Concatenation/IsConcatenableHasManyJsonRelation.php index 0fc50dc..b0c0468 100644 --- a/src/Relations/Traits/Concatenation/IsConcatenableHasManyJsonRelation.php +++ b/src/Relations/Traits/Concatenation/IsConcatenableHasManyJsonRelation.php @@ -73,19 +73,28 @@ public function getThroughKeyForDeepRelationships(string $alias): Expression * @param array $models * @param \Illuminate\Database\Eloquent\Collection $results * @param string $relation + * @param string $type * @return array */ - public function matchResultsForDeepRelationship(array $models, Collection $results, string $relation): array - { + public function matchResultsForDeepRelationship( + array $models, + Collection $results, + string $relation, + string $type = 'many' + ): array { $dictionary = $this->buildDictionaryForDeepRelationship($results); foreach ($models as $model) { $key = $this->getDictionaryKey($model->{$this->localKey}); if (isset($dictionary[$key])) { - $collection = $this->related->newCollection($dictionary[$key]); + $value = $dictionary[$key]; + + $value = $type === 'one' + ? (reset($value) ?: null) + : $this->related->newCollection($value); - $model->setRelation($relation, $collection); + $model->setRelation($relation, $value); } } diff --git a/tests/Concatenation/BelongsToJson/FirstPositionTest.php b/tests/Concatenation/BelongsToJson/FirstPositionTest.php index e8791a5..fddf847 100644 --- a/tests/Concatenation/BelongsToJson/FirstPositionTest.php +++ b/tests/Concatenation/BelongsToJson/FirstPositionTest.php @@ -40,6 +40,15 @@ public function testEagerLoading() $this->assertEquals([83, 84], $users[2]->permissions->pluck('id')->all()); } + public function testEagerLoadingWithHasOneDeep() + { + $users = User::with('permission')->get(); + + $this->assertEquals(81, $users[0]->permission->id); + $this->assertNull($users[1]->permission); + $this->assertEquals(83, $users[2]->permission->id); + } + public function testEagerLoadingWithObjects() { $users = User::with('permissions2')->get(); diff --git a/tests/Concatenation/HasManyJson/FirstPositionTest.php b/tests/Concatenation/HasManyJson/FirstPositionTest.php index 0e6f73a..3635ed9 100644 --- a/tests/Concatenation/HasManyJson/FirstPositionTest.php +++ b/tests/Concatenation/HasManyJson/FirstPositionTest.php @@ -57,6 +57,15 @@ public function testEagerLoadingWithObjects() $this->assertEquals([], $roles[3]->countries2->pluck('id')->all()); } + public function testEagerLoadingWithHasOneDeep() + { + $roles = Role::with('country')->get(); + + $this->assertEquals(71, $roles[0]->country->id); + $this->assertEquals(71, $roles[1]->country->id); + $this->assertNull($roles[3]->country); + } + public function testLazyEagerLoading() { $roles = Role::all()->load('countries'); diff --git a/tests/Models/Role.php b/tests/Models/Role.php index 27dec9b..ccab37f 100644 --- a/tests/Models/Role.php +++ b/tests/Models/Role.php @@ -4,6 +4,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Staudenmeir\EloquentHasManyDeep\HasManyDeep; +use Staudenmeir\EloquentHasManyDeep\HasOneDeep; use Staudenmeir\EloquentHasManyDeep\HasRelationships; use Staudenmeir\EloquentJsonRelations\JsonKey; use Staudenmeir\EloquentJsonRelations\Relations\HasManyJson; @@ -22,6 +23,11 @@ public function countries2(): HasManyDeep return $this->hasManyDeepFromRelations($this->users2(), (new User())->country()); } + public function country(): HasOneDeep + { + return $this->hasOneDeepFromRelations($this->users(), (new User())->country()); + } + public function permissions(): HasMany { return $this->hasMany(Permission::class); diff --git a/tests/Models/User.php b/tests/Models/User.php index 7ca3c14..75ea47b 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\HasOneThrough; use Staudenmeir\EloquentHasManyDeep\HasManyDeep; +use Staudenmeir\EloquentHasManyDeep\HasOneDeep; use Staudenmeir\EloquentHasManyDeep\HasRelationships; use Staudenmeir\EloquentJsonRelations\Relations\BelongsToJson; @@ -27,6 +28,11 @@ public function locale(): BelongsTo return $this->belongsTo(Locale::class, 'options->locale_id'); } + public function permission(): HasOneDeep + { + return $this->hasOneDeepFromRelations($this->roles(), (new Role())->permissions()); + } + public function permissions(): HasManyDeep { return $this->hasManyDeepFromRelations($this->roles(), (new Role())->permissions());