diff --git a/composer.json b/composer.json index 0355b07..8281bbd 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,8 @@ "staudenmeir/eloquent-has-many-deep-contracts": "^1.1" }, "require-dev": { + "barryvdh/laravel-ide-helper": "^2.13", + "orchestra/testbench": "^8.17", "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^10.1", "staudenmeir/eloquent-has-many-deep": "^1.18.1" @@ -31,6 +33,13 @@ "config": { "sort-packages": true }, + "extra": { + "laravel": { + "providers": [ + "Staudenmeir\\EloquentJsonRelations\\IdeHelperServiceProvider" + ] + } + }, "minimum-stability": "dev", "prefer-stable": true } diff --git a/src/IdeHelper/JsonRelationsHook.php b/src/IdeHelper/JsonRelationsHook.php new file mode 100644 index 0000000..97cbd87 --- /dev/null +++ b/src/IdeHelper/JsonRelationsHook.php @@ -0,0 +1,67 @@ +getMethods(ReflectionMethod::IS_PUBLIC); + + foreach ($methods as $method) { + if ($method->isStatic() || $method->getNumberOfParameters() > 0) { + continue; + } + + try { + $relationship = $method->invoke($model); + } catch (Throwable) { + continue; + } + + if ($relationship instanceof BelongsToJson || $relationship instanceof HasManyJson) { + $this->addRelationship($command, $method, $relationship); + } + } + } + + protected function addRelationship(ModelsCommand $command, ReflectionMethod $method, Relation $relationship): void + { + $type = '\\' . Collection::class . '|\\' . $relationship->getRelated()::class . '[]'; + + $command->setProperty( + $method->getName(), + $type, + true, + false + ); + + $command->setProperty( + Str::snake($method->getName()) . '_count', + 'int', + true, + false, + null, + true + ); + } +} diff --git a/src/IdeHelperServiceProvider.php b/src/IdeHelperServiceProvider.php new file mode 100644 index 0000000..67b5b10 --- /dev/null +++ b/src/IdeHelperServiceProvider.php @@ -0,0 +1,32 @@ +app->get('config'); + + $config->set( + 'ide-helper.model_hooks', + array_merge( + [JsonRelationsHook::class], + $config->get('ide-helper.model_hooks', []) + ) + ); + } + + public function provides(): array + { + return [ + ModelsCommand::class, + ]; + } +} diff --git a/tests/IdeHelper/JsonRelationsHookTest.php b/tests/IdeHelper/JsonRelationsHookTest.php new file mode 100644 index 0000000..c04d401 --- /dev/null +++ b/tests/IdeHelper/JsonRelationsHookTest.php @@ -0,0 +1,77 @@ +addConnection($config[getenv('DATABASE') ?: 'sqlite']); + $db->setAsGlobal(); + $db->bootEloquent(); + } + + public function testRunWithBelongsToJson() + { + $command = Mockery::mock(ModelsCommand::class); + $command->shouldReceive('setProperty')->once()->with( + 'roles', + '\Illuminate\Database\Eloquent\Collection|\Tests\IdeHelper\Models\Role[]', + true, + false + ); + $command->shouldReceive('setProperty')->once()->with( + 'roles_count', + 'int', + true, + false, + null, + true + ); + + $hook = new JsonRelationsHook(); + $hook->run($command, new User()); + } + + public function testRunWithHasManyJson() + { + if (DB::connection()->getDriverName() === 'sqlite') { + $this->markTestSkipped(); + } + + $command = Mockery::mock(ModelsCommand::class); + $command->shouldReceive('setProperty')->once()->with( + 'users', + '\Illuminate\Database\Eloquent\Collection|\Tests\IdeHelper\Models\User[]', + true, + false + ); + $command->shouldReceive('setProperty')->once()->with( + 'users_count', + 'int', + true, + false, + null, + true + ); + + $hook = new JsonRelationsHook(); + $hook->run($command, new Role()); + } +} diff --git a/tests/IdeHelper/Models/Role.php b/tests/IdeHelper/Models/Role.php new file mode 100644 index 0000000..72cede1 --- /dev/null +++ b/tests/IdeHelper/Models/Role.php @@ -0,0 +1,17 @@ +hasManyJson(User::class, 'role_ids'); + } +} diff --git a/tests/IdeHelper/Models/User.php b/tests/IdeHelper/Models/User.php new file mode 100644 index 0000000..030e31f --- /dev/null +++ b/tests/IdeHelper/Models/User.php @@ -0,0 +1,17 @@ +belongsToJson(Role::class, 'role_ids'); + } +} diff --git a/tests/IdeHelperServiceProviderTest.php b/tests/IdeHelperServiceProviderTest.php new file mode 100644 index 0000000..26f2a50 --- /dev/null +++ b/tests/IdeHelperServiceProviderTest.php @@ -0,0 +1,33 @@ +app->loadDeferredProvider(BarryvdhIdeHelperServiceProvider::class); + $this->app->loadDeferredProvider(IdeHelperServiceProvider::class); + + /** @var \Illuminate\Contracts\Config\Repository $config */ + $config = $this->app->get('config'); + + $this->assertContains( + JsonRelationsHook::class, + $config->get('ide-helper.model_hooks'), + ); + } + + protected function getPackageProviders($app): array + { + return [ + BarryvdhIdeHelperServiceProvider::class, + IdeHelperServiceProvider::class, + ]; + } +}