Skip to content

Commit

Permalink
Add IDE helper model hook
Browse files Browse the repository at this point in the history
  • Loading branch information
staudenmeir committed Dec 16, 2023
1 parent 9167491 commit 0dc38a2
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 0 deletions.
9 changes: 9 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -31,6 +33,13 @@
"config": {
"sort-packages": true
},
"extra": {
"laravel": {
"providers": [
"Staudenmeir\\EloquentJsonRelations\\IdeHelperServiceProvider"
]
}
},
"minimum-stability": "dev",
"prefer-stable": true
}
67 changes: 67 additions & 0 deletions src/IdeHelper/JsonRelationsHook.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace Staudenmeir\EloquentJsonRelations\IdeHelper;

use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
use Barryvdh\LaravelIdeHelper\Contracts\ModelHookInterface;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Str;
use ReflectionClass;
use ReflectionMethod;
use Staudenmeir\EloquentJsonRelations\HasJsonRelationships;
use Staudenmeir\EloquentJsonRelations\Relations\BelongsToJson;
use Staudenmeir\EloquentJsonRelations\Relations\HasManyJson;
use Throwable;

class JsonRelationsHook implements ModelHookInterface
{
public function run(ModelsCommand $command, Model $model): void
{
$traits = class_uses_recursive($model);

if (!in_array(HasJsonRelationships::class, $traits)) {
return;
}

$methods = (new ReflectionClass($model))->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
);
}
}
32 changes: 32 additions & 0 deletions src/IdeHelperServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Staudenmeir\EloquentJsonRelations;

use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
use Staudenmeir\EloquentJsonRelations\IdeHelper\JsonRelationsHook;

class IdeHelperServiceProvider extends ServiceProvider implements DeferrableProvider
{
public function register(): void
{
/** @var \Illuminate\Contracts\Config\Repository $config */
$config = $this->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,
];
}
}
77 changes: 77 additions & 0 deletions tests/IdeHelper/JsonRelationsHookTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

namespace Tests\IdeHelper;

use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
use Illuminate\Database\Capsule\Manager as DB;
use Mockery;
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
use Orchestra\Testbench\TestCase;
use Staudenmeir\EloquentJsonRelations\IdeHelper\JsonRelationsHook;
use Tests\IdeHelper\Models\Role;
use Tests\IdeHelper\Models\User;

class JsonRelationsHookTest extends TestCase
{
use MockeryPHPUnitIntegration;

protected function setUp(): void
{
parent::setUp();

$config = require __DIR__.'/../config/database.php';

$db = new DB();
$db->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());
}
}
17 changes: 17 additions & 0 deletions tests/IdeHelper/Models/Role.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Tests\IdeHelper\Models;

use Illuminate\Database\Eloquent\Model;
use Staudenmeir\EloquentJsonRelations\HasJsonRelationships;
use Staudenmeir\EloquentJsonRelations\Relations\HasManyJson;

class Role extends Model
{
use HasJsonRelationships;

public function users(): HasManyJson
{
return $this->hasManyJson(User::class, 'role_ids');
}
}
17 changes: 17 additions & 0 deletions tests/IdeHelper/Models/User.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Tests\IdeHelper\Models;

use Illuminate\Database\Eloquent\Model;
use Staudenmeir\EloquentJsonRelations\HasJsonRelationships;
use Staudenmeir\EloquentJsonRelations\Relations\BelongsToJson;

class User extends Model
{
use HasJsonRelationships;

public function roles(): BelongsToJson
{
return $this->belongsToJson(Role::class, 'role_ids');
}
}
33 changes: 33 additions & 0 deletions tests/IdeHelperServiceProviderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Tests;

use Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider as BarryvdhIdeHelperServiceProvider;
use Orchestra\Testbench\TestCase;
use Staudenmeir\EloquentJsonRelations\IdeHelperServiceProvider;
use Staudenmeir\EloquentJsonRelations\IdeHelper\JsonRelationsHook;

class IdeHelperServiceProviderTest extends TestCase
{
public function testRegister(): void
{
$this->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,
];
}
}

0 comments on commit 0dc38a2

Please sign in to comment.