From 2341dfe2854bf12643620127f64673a23e4fd3a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ba=CC=81lint=20Szekeres?= Date: Thu, 12 Nov 2020 23:14:00 +0100 Subject: [PATCH] Use dynamic app namespace in Eloquent Factory instead of static App\ --- .../Console/Factories/FactoryMakeCommand.php | 12 ++++---- .../Database/Eloquent/Factories/Factory.php | 20 +++++++++---- .../Database/DatabaseEloquentFactoryTest.php | 30 ++++++++++++++++++- 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php b/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php index d5565212e50d..6233fe29f07d 100644 --- a/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php +++ b/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php @@ -68,8 +68,8 @@ protected function buildClass($name) $model = class_basename($namespaceModel); - if (Str::startsWith($namespaceModel, 'App\\Models')) { - $namespace = Str::beforeLast('Database\\Factories\\'.Str::after($namespaceModel, 'App\\Models\\'), '\\'); + if (Str::startsWith($namespaceModel, $this->rootNamespace().'Models')) { + $namespace = Str::beforeLast('Database\\Factories\\'.Str::after($namespaceModel, $this->rootNamespace().'Models\\'), '\\'); } else { $namespace = 'Database\\Factories'; } @@ -99,7 +99,7 @@ protected function buildClass($name) */ protected function getPath($name) { - $name = (string) Str::of($name)->replaceFirst('App\\', '')->finish('Factory'); + $name = (string) Str::of($name)->replaceFirst($this->rootNamespace(), '')->finish('Factory'); return $this->laravel->databasePath().'/factories/'.str_replace('\\', '/', $name).'.php'; } @@ -116,17 +116,17 @@ protected function guessModelName($name) $name = substr($name, 0, -7); } - $modelName = $this->qualifyModel(Str::after($name, 'App\\')); + $modelName = $this->qualifyModel(Str::after($name, $this->rootNamespace())); if (class_exists($modelName)) { return $modelName; } if (is_dir(app_path('Models/'))) { - return 'App\Models\Model'; + return $this->rootNamespace().'Models\Model'; } - return 'App\Model'; + return $this->rootNamespace().'Model'; } /** diff --git a/src/Illuminate/Database/Eloquent/Factories/Factory.php b/src/Illuminate/Database/Eloquent/Factories/Factory.php index bb5383c57e25..88276822da7b 100644 --- a/src/Illuminate/Database/Eloquent/Factories/Factory.php +++ b/src/Illuminate/Database/Eloquent/Factories/Factory.php @@ -7,6 +7,7 @@ use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Illuminate\Database\Eloquent\Model; +use Illuminate\Foundation\Application; use Illuminate\Support\Collection; use Illuminate\Support\Str; use Illuminate\Support\Traits\ForwardsCalls; @@ -626,10 +627,13 @@ public function modelName() { $resolver = static::$modelNameResolver ?: function (self $factory) { $factoryBasename = Str::replaceLast('Factory', '', class_basename($factory)); + $rootNamespace = Container::getInstance() + ->make(Application::class) + ->getNamespace(); - return class_exists('App\\Models\\'.$factoryBasename) - ? 'App\\Models\\'.$factoryBasename - : 'App\\'.$factoryBasename; + return class_exists($rootNamespace.'Models\\'.$factoryBasename) + ? $rootNamespace.'Models\\'.$factoryBasename + : $rootNamespace.$factoryBasename; }; return $this->model ?: $resolver($this); @@ -700,9 +704,13 @@ protected function withFaker() public static function resolveFactoryName(string $modelName) { $resolver = static::$factoryNameResolver ?: function (string $modelName) { - $modelName = Str::startsWith($modelName, 'App\\Models\\') - ? Str::after($modelName, 'App\\Models\\') - : Str::after($modelName, 'App\\'); + $rootNamespace = Container::getInstance() + ->make(Application::class) + ->getNamespace(); + + $modelName = Str::startsWith($modelName, $rootNamespace.'Models\\') + ? Str::after($modelName, $rootNamespace.'Models\\') + : Str::after($modelName, $rootNamespace); return static::$namespace.$modelName.'Factory'; }; diff --git a/tests/Database/DatabaseEloquentFactoryTest.php b/tests/Database/DatabaseEloquentFactoryTest.php index 203df06d27e7..3b87fca3ee58 100644 --- a/tests/Database/DatabaseEloquentFactoryTest.php +++ b/tests/Database/DatabaseEloquentFactoryTest.php @@ -9,15 +9,20 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\Sequence; use Illuminate\Database\Eloquent\Model as Eloquent; +use Illuminate\Foundation\Application; +use Mockery; use PHPUnit\Framework\TestCase; class DatabaseEloquentFactoryTest extends TestCase { protected function setUp(): void { - Container::getInstance()->singleton(\Faker\Generator::class, function ($app, $parameters) { + $container = Container::getInstance(); + $container->singleton(\Faker\Generator::class, function ($app, $parameters) { return \Faker\Factory::create('en_US'); }); + $container->instance(Application::class, $app = Mockery::mock(Application::class)); + $app->shouldReceive('getNamespace')->andReturn('App\\'); $db = new DB; @@ -81,7 +86,11 @@ public function createSchema() */ protected function tearDown(): void { + Mockery::close(); + $this->schema()->drop('users'); + + Container::setInstance(null); } public function test_basic_model_can_be_created() @@ -326,6 +335,25 @@ public function test_resolve_nested_model_factories() } } + public function test_resolve_non_app_nested_model_factories() + { + Container::getInstance()->instance(Application::class, $app = Mockery::mock(Application::class)); + $app->shouldReceive('getNamespace')->andReturn('Foo\\'); + + Factory::useNamespace('Factories\\'); + + $resolves = [ + 'Foo\\Bar' => 'Factories\\BarFactory', + 'Foo\\Models\\Bar' => 'Factories\\BarFactory', + 'Foo\\Models\\Nested\\Bar' => 'Factories\\Nested\\BarFactory', + 'Foo\\Models\\Really\\Nested\\Bar' => 'Factories\\Really\\Nested\\BarFactory', + ]; + + foreach ($resolves as $model => $factory) { + $this->assertEquals($factory, Factory::resolveFactoryName($model)); + } + } + public function test_model_has_factory() { Factory::guessFactoryNamesUsing(function ($model) {