Skip to content

Commit 1540fe4

Browse files
committed
feat: Use reflection to detect model relations
refs: #50
1 parent a22d3a2 commit 1540fe4

File tree

2 files changed

+76
-26
lines changed

2 files changed

+76
-26
lines changed

src/Generators/AbstractTestsGenerator.php

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44

55
use DateTime;
66
use Illuminate\Database\Eloquent\Factory as LegacyFactories;
7+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
78
use Illuminate\Support\Arr;
89
use Illuminate\Support\Str;
910
use RonasIT\Support\Events\SuccessCreateMessage;
1011
use RonasIT\Support\Exceptions\CircularRelationsFoundedException;
12+
use ReflectionClass;
13+
use ReflectionMethod;
1114
use RonasIT\Support\Exceptions\ClassNotExistsException;
15+
use Throwable;
1216

1317
abstract class AbstractTestsGenerator extends EntityGenerator
1418
{
@@ -242,28 +246,49 @@ protected function buildRelationsTree($models): array
242246
return array_unique($models);
243247
}
244248

245-
protected function getRelatedModels($model)
249+
protected function getRelatedModels($model): array
246250
{
247-
$content = $this->getModelClassContent($model);
251+
$class = $this->getModelClass($model);
248252

249-
preg_match_all('/(?<=belongsTo\().*(?=::class)/', $content, $matches);
250-
251-
return head($matches);
252-
}
253-
254-
protected function getModelClassContent($model): string
255-
{
256-
$path = base_path("{$this->paths['models']}/{$model}.php");
257-
258-
if (!$this->classExists('models', $model)) {
253+
if (!class_exists($this->getModelClass($model))) {
259254
$this->throwFailureException(
260255
ClassNotExistsException::class,
261256
"Cannot create {$model} Model cause {$model} Model does not exists.",
262257
"Create a {$model} Model by himself or run command 'php artisan make:entity {$model} --only-model'."
263258
);
264259
}
265260

266-
return file_get_contents($path);
261+
$instance = new $class();
262+
263+
$publicMethods = (new ReflectionClass($class))->getMethods(ReflectionMethod::IS_PUBLIC);
264+
265+
$methods = array_filter($publicMethods, fn ($method) =>
266+
$method->class === $class
267+
&& !$method->getParameters()
268+
&& $method->getName() !== 'getRelationships'
269+
);
270+
271+
$relatedModels = [];
272+
273+
foreach ($methods as $method) {
274+
try {
275+
$methodName = $method->getName();
276+
277+
$methodReturn = $instance->$methodName();
278+
279+
if (!$methodReturn instanceof BelongsTo) {
280+
continue;
281+
}
282+
} catch (Throwable) {
283+
continue;
284+
}
285+
286+
$relationModel = get_class($methodReturn->getRelated());
287+
288+
$relatedModels[] = class_basename($relationModel);
289+
}
290+
291+
return $relatedModels;
267292
}
268293

269294
protected function canGenerateUserData(): bool

src/Generators/FactoryGenerator.php

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace RonasIT\Support\Generators;
44

55
use Faker\Generator as Faker;
6+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
67
use Illuminate\Support\Arr;
78
use Illuminate\Support\Str;
89
use RonasIT\Support\Exceptions\ModelFactoryNotFound;
@@ -11,6 +12,9 @@
1112
use RonasIT\Support\Exceptions\ClassAlreadyExistsException;
1213
use RonasIT\Support\Events\SuccessCreateMessage;
1314
use Exception;
15+
use ReflectionClass;
16+
use ReflectionMethod;
17+
use Throwable;
1418

1519
class FactoryGenerator extends EntityGenerator
1620
{
@@ -246,27 +250,48 @@ protected function getModelClass($model): string
246250
return "{$modelNamespace}\\{$model}";
247251
}
248252

249-
protected function getRelatedModels($model)
253+
protected function getRelatedModels($model): array
250254
{
251-
$content = $this->getModelClassContent($model);
255+
$class = $this->getModelClass($model);
252256

253-
preg_match_all('/(?<=belongsTo\().*(?=::class)/', $content, $matches);
254-
255-
return head($matches);
256-
}
257-
258-
protected function getModelClassContent($model): string
259-
{
260-
$path = base_path("{$this->paths['models']}/{$model}.php");
261-
262-
if (!$this->classExists('models', $model)) {
257+
if (!class_exists($this->getModelClass($model))) {
263258
$this->throwFailureException(
264259
ClassNotExistsException::class,
265260
"Cannot create {$model} Model cause {$model} Model does not exists.",
266261
"Create a {$model} Model by himself or run command 'php artisan make:entity {$model} --only-model'."
267262
);
268263
}
269264

270-
return file_get_contents($path);
265+
$instance = new $class();
266+
267+
$publicMethods = (new ReflectionClass($class))->getMethods(ReflectionMethod::IS_PUBLIC);
268+
269+
$methods = array_filter($publicMethods, fn ($method) =>
270+
$method->class === $class
271+
&& !$method->getParameters()
272+
&& $method->getName() !== 'getRelationships'
273+
);
274+
275+
$relatedModels = [];
276+
277+
foreach ($methods as $method) {
278+
try {
279+
$methodName = $method->getName();
280+
281+
$methodReturn = $instance->$methodName();
282+
283+
if (!$methodReturn instanceof BelongsTo) {
284+
continue;
285+
}
286+
} catch (Throwable) {
287+
continue;
288+
}
289+
290+
$relationModel = get_class($methodReturn->getRelated());
291+
292+
$relatedModels[] = class_basename($relationModel);
293+
}
294+
295+
return $relatedModels;
271296
}
272297
}

0 commit comments

Comments
 (0)