diff --git a/composer.json b/composer.json index be15d9c..1f039f5 100644 --- a/composer.json +++ b/composer.json @@ -34,13 +34,17 @@ "illuminate/filesystem": "^10.17" }, "require-dev": { + "fakerphp/faker": "^1.21", + "mockery/mockery": "^1.5.1", + "laravel/framework": "^10.17", "laravel/pint": "^1.6", - "orchestra/testbench": "^8.9", + "orchestra/testbench-core": "^8.10.2", "phpstan/phpstan": "^1.10.6", - "phpunit/phpunit": "^10.1" + "phpunit/phpunit": "^10.1", + "symfony/yaml": "^6.2" }, "conflict": { - "orchestra/canvas": "<8.8.0", + "orchestra/canvas": "<8.9.0", "orchestra/testbench-core": "<8.2.0" }, "config": { diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3d858b8..8b13789 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,11 +1 @@ -parameters: - ignoreErrors: - - - message: "#^Call to an undefined method Illuminate\\\\Contracts\\\\Container\\\\Container\\:\\:basePath\\(\\)\\.$#" - count: 1 - path: src/LaravelServiceProvider.php - - - message: "#^Method Orchestra\\\\Canvas\\\\Core\\\\Presets\\\\Preset\\:\\:config\\(\\) has no return type specified\\.$#" - count: 1 - path: src/Presets/Preset.php diff --git a/src/CodeGenerator.php b/src/CodeGenerator.php deleted file mode 100644 index 8c87691..0000000 --- a/src/CodeGenerator.php +++ /dev/null @@ -1,88 +0,0 @@ -preset = $preset; - - return $this; - } - - /** - * Generate code. - * - * @return int - */ - public function generateCode(bool $force = false) - { - return $this->resolveGeneratesCodeProcessor()($force); - } - - /** - * Code already exists. - */ - public function codeAlreadyExists(string $className): int - { - $this->components->error(sprintf('%s [%s] already exists!', $this->type, $className)); - - return static::FAILURE; - } - - /** - * Code successfully generated. - */ - public function codeHasBeenGenerated(string $className): int - { - $this->components->info(sprintf('%s [%s] created successfully.', $this->type, $className)); - - return static::SUCCESS; - } - - /** - * Get the default namespace for the class. - */ - public function getDefaultNamespace(string $rootNamespace): string - { - return $rootNamespace; - } - - /** - * Generator options. - * - * @return array - */ - public function generatorOptions(): array - { - return [ - 'name' => $this->generatorName(), - ]; - } - - /** - * Resolve generates code processor. - */ - protected function resolveGeneratesCodeProcessor(): GeneratesCode - { - /** @var \Orchestra\Canvas\Core\GeneratesCode $class */ - $class = property_exists($this, 'processor') - ? $this->processor - : GeneratesCode::class; - - return new $class($this->preset, $this); - } -} diff --git a/src/Commands/GeneratorCommand.php b/src/Commands/GeneratorCommand.php new file mode 100644 index 0000000..09f1229 --- /dev/null +++ b/src/Commands/GeneratorCommand.php @@ -0,0 +1,91 @@ +addGeneratorPresetOptions(); + } + + /** + * Execute the console command. + * + * @return bool|null + * + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function handle() + { + return $this->generateCode() ? self::SUCCESS : self::FAILURE; + } + + /** + * Get the destination class path. + * + * @param string $name + * @return string + */ + protected function getPath($name) + { + return $this->getPathUsingCanvas($name); + } + + /** + * Qualify the given model class base name. + * + * @return string + */ + protected function qualifyModel(string $model) + { + return $this->qualifyModelUsingCanvas($model); + } + + /** + * Get the root namespace for the class. + * + * @return string + */ + protected function rootNamespace() + { + return $this->rootNamespaceUsingCanvas(); + } + + /** + * Get the model for the default guard's user provider. + */ + protected function userProviderModel(): ?string + { + return $this->userProviderModelUsingCanvas(); + } + + /** + * Get the first view directory path from the application configuration. + * + * @return string + */ + protected function viewPath($path = '') + { + return $this->viewPathUsingCanvas($path); + } +} diff --git a/src/Commands/Generators/Code.php b/src/Commands/Generators/Code.php deleted file mode 100644 index 33f12d4..0000000 --- a/src/Commands/Generators/Code.php +++ /dev/null @@ -1,31 +0,0 @@ -getStubFileName(); - } - - /** - * Get the stub file name for the generator. - */ - public function getStubFileName(): string - { - return __DIR__.'/../../../storage/canvas/code.stub'; - } -} diff --git a/src/Commands/Generators/ConsoleGenerator.php b/src/Commands/Generators/ConsoleGenerator.php deleted file mode 100644 index de76c1a..0000000 --- a/src/Commands/Generators/ConsoleGenerator.php +++ /dev/null @@ -1,87 +0,0 @@ - - */ - protected string $processor = GeneratesCommandCode::class; - - /** - * Get the stub file for the generator. - */ - public function getPublishedStubFileName(): ?string - { - return null; - } - - /** - * Get the stub file for the generator. - */ - public function getStubFile(): string - { - return __DIR__.'/../../../storage/canvas/generator.stub'; - } - - /** - * Get the default namespace for the class. - */ - public function getDefaultNamespace(string $rootNamespace): string - { - return $this->preset->config('console.namespace', $rootNamespace.'\Console\Commands'); - } - - /** - * Generator options. - * - * @return array - */ - public function generatorOptions(): array - { - /** @var string $command */ - $command = $this->option('command'); - - if (! Str::startsWith($command, 'make:')) { - $command = "make:{$command}"; - } - - return [ - 'command' => $command, - 'force' => $this->option('force'), - ]; - } - - /** - * Get the console command options. - * - * @return array - */ - protected function getOptions() - { - return [ - ['force', 'f', InputOption::VALUE_NONE, 'Create the class even if the generator already exists'], - ['command', null, InputOption::VALUE_OPTIONAL, 'The terminal command that should be assigned', 'make:name'], - ]; - } -} diff --git a/src/CommandsProvider.php b/src/CommandsProvider.php deleted file mode 100644 index 314c504..0000000 --- a/src/CommandsProvider.php +++ /dev/null @@ -1,36 +0,0 @@ -bound('orchestra.canvas')) { - return $app->make('orchestra.canvas'); - } - - return new Presets\Laravel([ - 'preset' => 'laravel', - 'namespace' => trim($this->app->getNamespace(), '\\'), - 'user-auth-provider' => $this->userProviderModel(), - ], $app->basePath(), $app->make('files')); - } - - /** - * Get the model for the default guard's user provider. - */ - protected function userProviderModel(): ?string - { - $guard = config('auth.defaults.guard'); - - $provider = config("auth.guards.{$guard}.provider"); - - return config("auth.providers.{$provider}.model"); - } -} diff --git a/src/Concerns/CodeGenerator.php b/src/Concerns/CodeGenerator.php new file mode 100644 index 0000000..6b31891 --- /dev/null +++ b/src/Concerns/CodeGenerator.php @@ -0,0 +1,93 @@ +getNameInput(); + $force = $this->hasOption('force') && $this->option('force') === true; + + $className = $this->qualifyClass($name); + $path = $this->getPath($this->qualifyClass($name)); + + // First we need to ensure that the given name is not a reserved word within the PHP + // language and that the class name will actually be valid. If it is not valid we + // can error now and prevent from polluting the filesystem using invalid files. + if ($this->isReservedName($name)) { + $this->components->error('The name "'.$name.'" is reserved by PHP.'); + + return false; + } + + // Next, We will check to see if the class already exists. If it does, we don't want + // to create the class and overwrite the user's code. So, we will bail out so the + // code is untouched. Otherwise, we will continue generating this class' files. + if (! $force && $this->alreadyExists($name)) { + return $this->codeAlreadyExists($className); + } + + // Next, we will generate the path to the location where this class' file should get + // written. Then, we will build the class and make the proper replacements on the + // stub files so that it gets the correctly formatted namespace and class name. + $this->makeDirectory($path); + + $this->files->put( + $path, $this->sortImports($this->generatingCode($this->buildClass($className), $className)) + ); + + if (\in_array(CreatesMatchingTest::class, class_uses_recursive($this))) { + $this->handleTestCreationUsingCanvas($path); + } + + return tap($this->codeHasBeenGenerated($className), function ($exitCode) use ($className, $path) { + $this->afterCodeHasBeenGenerated($className, $path); + }); + } + + /** + * Handle generating code. + */ + public function generatingCode(string $stub, string $className): string + { + return $stub; + } + + /** + * Code already exists. + */ + public function codeAlreadyExists(string $className): bool + { + $this->components->error(sprintf('%s [%s] already exists!', $this->type, $className)); + + return false; + } + + /** + * Code successfully generated. + */ + public function codeHasBeenGenerated(string $className): bool + { + $this->components->info(sprintf('%s [%s] created successfully.', $this->type, $className)); + + return true; + } + + /** + * Run after code successfully generated. + */ + public function afterCodeHasBeenGenerated(string $className, string $path): void + { + // + } +} diff --git a/src/Concerns/CreatesUsingGeneratorPreset.php b/src/Concerns/CreatesUsingGeneratorPreset.php new file mode 100644 index 0000000..436ef0a --- /dev/null +++ b/src/Concerns/CreatesUsingGeneratorPreset.php @@ -0,0 +1,44 @@ +getDefinition()->addOption(new InputOption( + 'preset', + null, + InputOption::VALUE_OPTIONAL, + sprintf('Preset used when generating %s', Str::lower($this->type)), + null, + )); + } + + /** + * Resolve the generator preset. + * + * @return \Orchestra\Canvas\Core\Presets\Preset + */ + protected function generatorPreset() + { + return $this->laravel->make(PresetManager::class)->driver($this->option('preset')); + } + + /** + * Get the generator preset source path. + */ + protected function getGeneratorSourcePath(): string + { + return $this->generatorPreset()->sourcePath(); + } +} diff --git a/src/Concerns/ResolvesPresetStubs.php b/src/Concerns/ResolvesPresetStubs.php new file mode 100644 index 0000000..b2b1c94 --- /dev/null +++ b/src/Concerns/ResolvesPresetStubs.php @@ -0,0 +1,32 @@ +generatorPreset(); + + return $preset->hasCustomStubPath() && file_exists($customPath = implode('/', [$preset->basePath(), trim($stub, '/')])) + ? $customPath + : $this->resolveDefaultStubPath($stub); + } + + /** + * Resolve the default fully-qualified path to the stub. + * + * @param string $stub + * @return string + */ + protected function resolveDefaultStubPath($stub) + { + return $stub; + } +} diff --git a/src/Concerns/TestGenerator.php b/src/Concerns/TestGenerator.php new file mode 100644 index 0000000..5704281 --- /dev/null +++ b/src/Concerns/TestGenerator.php @@ -0,0 +1,29 @@ +option('test') && ! $this->option('pest')) { + return false; + } + + $sourcePath = \in_array(CreatesUsingGeneratorPreset::class, class_uses_recursive($this)) + ? $this->generatorPreset()->sourcePath() + : $this->laravel['path']; + + return $this->call('make:test', [ + 'name' => Str::of($path)->after($sourcePath)->beforeLast('.php')->append('Test')->replace('\\', '/'), + '--pest' => $this->option('pest'), + ]) == 0; + } +} diff --git a/src/Concerns/UsesGeneratorOverrides.php b/src/Concerns/UsesGeneratorOverrides.php new file mode 100644 index 0000000..38d4486 --- /dev/null +++ b/src/Concerns/UsesGeneratorOverrides.php @@ -0,0 +1,60 @@ +rootNamespace())) { + return $model; + } + + return $this->generatorPreset()->modelNamespace().$model; + } + + /** + * Get the destination class path. + */ + protected function getPathUsingCanvas(string $name): string + { + $name = Str::replaceFirst($this->rootNamespace(), '', $name); + + return $this->getGeneratorSourcePath().'/'.str_replace('\\', '/', $name).'.php'; + } + + /** + * Get the root namespace for the class. + */ + protected function rootNamespaceUsingCanvas(): string + { + return $this->generatorPreset()->rootNamespace(); + } + + /** + * Get the model for the default guard's user provider. + */ + protected function userProviderModelUsingCanvas(?string $guard = null): ?string + { + return $this->generatorPreset()->userProviderModel($guard); + } + + /** + * Get the first view directory path from the application configuration. + */ + protected function viewPathUsingCanvas(string $path = ''): string + { + $views = $this->generatorPreset()->viewPath(); + + return $views.($path ? DIRECTORY_SEPARATOR.$path : $path); + } +} diff --git a/src/Contracts/GeneratesCode.php b/src/Contracts/GeneratesCode.php new file mode 100644 index 0000000..692d665 --- /dev/null +++ b/src/Contracts/GeneratesCode.php @@ -0,0 +1,28 @@ + - */ - protected $options = []; - - /** - * Construct a new processor. - */ - public function __construct( - protected Presets\Preset $preset, - protected Contracts\GeneratesCodeListener $listener - ) { - $this->files = $preset->filesystem(); - $this->options = $listener->generatorOptions(); - } - - /** - * Execute generates code processor. - * - * @return int - */ - public function __invoke(bool $force = false) - { - $name = $this->listener->generatorName(); - - $className = $this->qualifyClass($name); - - $path = $this->getPath($className); - - // First we will check to see if the class already exists. If it does, we don't want - // to create the class and overwrite the user's code. So, we will bail out so the - // code is untouched. Otherwise, we will continue generating this class' files. - if (! $force && $this->alreadyExists($name)) { - return $this->listener->codeAlreadyExists($className); - } - - // Next, we will generate the path to the location where this class' file should get - // written. Then, we will build the class and make the proper replacements on the - // stub files so that it gets the correctly formatted namespace and class name. - $this->makeDirectory($path); - - $this->files->put($path, $this->sortImports($this->buildClass($className))); - - return tap($this->listener->codeHasBeenGenerated($className), function ($exitCode) use ($className, $path) { - $this->listener->afterCodeHasBeenGenerated($className, Str::of($path)->after($this->preset->sourcePath())); - }); - } - - /** - * Parse the class name and format according to the root namespace. - */ - protected function qualifyClass(string $name): string - { - $name = ltrim($name, '\\/'); - - $rootNamespace = $this->rootNamespace(); - - if (Str::startsWith($name, $rootNamespace)) { - return $name; - } - - $name = str_replace('/', '\\', $name); - - return $this->qualifyClass( - $this->getDefaultNamespace(trim($rootNamespace, '\\')).'\\'.$name - ); - } - - /** - * Get the default namespace for the class. - */ - protected function getDefaultNamespace(string $rootNamespace): string - { - return $this->listener->getDefaultNamespace($rootNamespace); - } - - /** - * Determine if the class already exists. - */ - protected function alreadyExists(string $rawName): bool - { - return $this->files->exists($this->getPath($this->qualifyClass($rawName))); - } - - /** - * Get the destination class path. - */ - protected function getPath(string $name): string - { - $name = Str::replaceFirst($this->rootNamespace(), '', $name); - - return $this->preset->sourcePath().'/'.str_replace('\\', '/', $name).'.php'; - } - - /** - * Build the directory for the class if necessary. - */ - protected function makeDirectory(string $path): string - { - if (! $this->files->isDirectory(\dirname($path))) { - $this->files->makeDirectory(\dirname($path), 0777, true, true); - } - - return $path; - } - - /** - * Build the class with the given name. - * - * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException - */ - protected function buildClass(string $name): string - { - return $this->generatingCode( - $this->files->get($this->getListenerStubFile()), $name - ); - } - - /** - * Handle generating code. - */ - protected function generatingCode(string $stub, string $name): string - { - return $this->listener->generatingCode( - $this->replaceClass( - $this->replaceNamespace($stub, $name), $name - ), $name - ); - } - - /** - * Get generator stub file. - */ - protected function getListenerStubFile(): string - { - if (\is_null($publishedStubFile = $this->listener->getPublishedStubFileName())) { - return $this->listener->getStubFile(); - } - - $stubFile = sprintf( - '%s/stubs/%s', $this->preset->basePath(), $publishedStubFile - ); - - if (! $this->files->exists($stubFile)) { - return $this->listener->getStubFile(); - } - - return $stubFile; - } - - /** - * Replace the namespace for the given stub. - */ - protected function replaceNamespace(string $stub, string $name): string - { - $stub = str_replace( - ['DummyRootNamespace\\', '{{ rootNamespace }}\\', '{{rootNamespace}}\\'], - '{{rootNamespace}}', - $stub - ); - - $searches = [ - ['DummyNamespace', 'DummyRootNamespace', 'NamespacedDummyUserModel'], - ['{{ namespace }}', '{{ rootNamespace }}', '{{ namespacedUserModel }}'], - ['{{namespace}}', '{{rootNamespace}}', '{{namespacedUserModel}}'], - ]; - - foreach ($searches as $search) { - $stub = str_replace( - $search, - [$this->getNamespace($name), $this->rootNamespace().'\\', $this->userProviderModel()], - $stub - ); - } - - return $stub; - } - - /** - * Replace the class name for the given stub. - */ - protected function replaceClass(string $stub, string $name): string - { - $class = str_replace($this->getNamespace($name).'\\', '', $name); - - $stub = str_replace( - ['DummyClass', '{{ class }}', '{{class}}'], $class, $stub - ); - - return str_replace( - ['DummyUser', '{{ userModel }}', '{{userModel}}'], - class_basename($this->userProviderModel()), - $stub - ); - } - - /** - * Get the full namespace for a given class, without the class name. - */ - protected function getNamespace(string $name): string - { - return trim(implode('\\', \array_slice(explode('\\', $name), 0, -1)), '\\'); - } - - /** - * Alphabetically sorts the imports for the given stub. - */ - protected function sortImports(string $stub): string - { - if (preg_match('/(?P(?:use [^;]+;$\n?)+)/m', $stub, $match)) { - $imports = explode("\n", trim($match['imports'])); - - sort($imports); - - return str_replace(trim($match['imports']), implode("\n", $imports), $stub); - } - - return $stub; - } - - /** - * Get the root namespace for the class. - */ - protected function rootNamespace(): string - { - return $this->preset->rootNamespace().'\\'; - } - - /** - * Get the model for the default guard's user provider. - */ - protected function userProviderModel(): string - { - return $this->preset->config('user-auth-provider', User::class); - } -} diff --git a/src/GeneratesCodeWithComponent.php b/src/GeneratesCodeWithComponent.php deleted file mode 100644 index 4e47abf..0000000 --- a/src/GeneratesCodeWithComponent.php +++ /dev/null @@ -1,34 +0,0 @@ -options['inline'])) { - $stub = str_replace( - ['DummyView', '{{ view }}', '{{view}}'], - "<<<'blade'\n
\n ".Inspiring::quote()."\n
\nblade", - $stub - ); - } - - return str_replace( - ['DummyView', '{{ view }}', '{{view}}'], - 'view(\'components.'.Str::kebab(class_basename($name)).'\')', - $stub - ); - } -} diff --git a/src/GeneratesCodeWithEloquent.php b/src/GeneratesCodeWithEloquent.php deleted file mode 100644 index a5a4407..0000000 --- a/src/GeneratesCodeWithEloquent.php +++ /dev/null @@ -1,87 +0,0 @@ -options['model']; - - return ! empty($model) ? $this->replaceModel($stub, $model) : $stub; - } - - /** - * Replace the model for the given stub. - */ - protected function replaceModel(string $stub, string $model): string - { - $modelClass = $this->parseModel($model); - - $replace = [ - 'DummyFullModelClass' => $modelClass, - '{{ namespacedModel }}' => $modelClass, - '{{namespacedModel}}' => $modelClass, - 'DummyModelClass' => class_basename($modelClass), - '{{ model }}' => class_basename($modelClass), - '{{model}}' => class_basename($modelClass), - 'DummyModelVariable' => lcfirst(class_basename($modelClass)), - '{{ modelVariable }}' => lcfirst(class_basename($modelClass)), - '{{modelVariable}}' => lcfirst(class_basename($modelClass)), - ]; - - return str_replace( - array_keys($replace), array_values($replace), $stub - ); - } - - /** - * Get the fully-qualified model class name. - * - * @param string $model - * - * @throws \InvalidArgumentException - */ - protected function parseModel($model): string - { - if (preg_match('([^A-Za-z0-9_/\\\\])', $model)) { - throw new InvalidArgumentException('Model name contains invalid characters.'); - } - - return $this->qualifyModel($model); - } - - /** - * Qualify the given model class base name. - */ - protected function qualifyModel(string $model): string - { - $model = ltrim($model, '\\/'); - - $model = str_replace('/', '\\', $model); - - $rootNamespace = $this->rootNamespace(); - $namespaceModel = $this->preset->modelNamespace().'\\'.$model; - - if (Str::startsWith($model, $namespaceModel)) { - return $model; - } elseif (! \is_null($this->preset->config('model.namespace'))) { - return $namespaceModel; - } - - return is_dir($this->preset->sourcePath().'/Models') - ? $rootNamespace.'Models\\'.$model - : $namespaceModel; - } -} diff --git a/src/GeneratesCodeWithMarkdown.php b/src/GeneratesCodeWithMarkdown.php deleted file mode 100644 index cdbe111..0000000 --- a/src/GeneratesCodeWithMarkdown.php +++ /dev/null @@ -1,20 +0,0 @@ -options['view'])) { - $stub = str_replace(['DummyView', '{{ view }}', '{{view}}'], $this->options['view'], $stub); - } - - return $stub; - } -} diff --git a/src/GeneratesCommandCode.php b/src/GeneratesCommandCode.php deleted file mode 100644 index bcc7aad..0000000 --- a/src/GeneratesCommandCode.php +++ /dev/null @@ -1,23 +0,0 @@ -options['command'] ?: 'app:'.Str::of($name)->classBasename()->kebab()->value(); - - return str_replace(['dummy:command', '{{ command }}', '{{command}}'], $command, $stub); - } -} diff --git a/src/LaravelServiceProvider.php b/src/LaravelServiceProvider.php index eba91ac..47b5e6b 100644 --- a/src/LaravelServiceProvider.php +++ b/src/LaravelServiceProvider.php @@ -2,31 +2,28 @@ namespace Orchestra\Canvas\Core; -use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Support\ServiceProvider; class LaravelServiceProvider extends ServiceProvider implements DeferrableProvider { - use CommandsProvider; - /** * Register services. */ public function register(): void { - $this->app->singleton(Presets\Preset::class, fn (Container $app) => $this->presetForLaravel($app)); + $this->app->singleton(PresetManager::class, fn ($app) => new PresetManager($app)); } /** * Get the services provided by the provider. * - * @return array + * @return array */ public function provides(): array { return [ - Presets\Preset::class, + PresetManager::class, ]; } } diff --git a/src/PresetManager.php b/src/PresetManager.php new file mode 100644 index 0000000..4d94304 --- /dev/null +++ b/src/PresetManager.php @@ -0,0 +1,46 @@ +container); + } + + /** + * Set the default driver name. + * + * @param string $name + * @return void + */ + public function setDefaultDriver($name) + { + $this->defaultPreset = $name; + } + + /** + * Get the default driver name. + * + * @return string + */ + public function getDefaultDriver() + { + return $this->defaultPreset; + } +} diff --git a/src/Presets/Laravel.php b/src/Presets/Laravel.php index 23b296f..73d5115 100644 --- a/src/Presets/Laravel.php +++ b/src/Presets/Laravel.php @@ -2,106 +2,177 @@ namespace Orchestra\Canvas\Core\Presets; -use Illuminate\Support\Arr; -use Symfony\Component\Console\Application; - class Laravel extends Preset { /** - * List of global generators. + * Preset name. * - * @var array> + * @return string */ - protected static $generators = []; + public function name() + { + return 'laravel'; + } /** - * Add global command. + * Get the path to the base working directory. * - * @param array> $generators + * @return string */ - public static function commands(array $generators): void + public function basePath() { - static::$generators = array_merge(static::$generators, $generators); + return $this->app->basePath(); } /** - * Preset name. + * Get the path to the source directory. + * + * @return string */ - public function name(): string + public function sourcePath() { - return 'laravel'; + return $this->app->basePath('app'); } /** - * Get the path to the base working directory. + * Get the path to the testing directory. + * + * @return string */ - public function laravelPath(): string + public function testingPath() { - return $this->basePath(); + return $this->app->basePath('tests'); } /** - * Get the path to the source directory. + * Get the path to the resource directory. + * + * @return string + */ + public function resourcePath() + { + return $this->app->resourcePath(); + } + + /** + * Get the path to the view directory. + * + * @return string */ - public function sourcePath(): string + public function viewPath() { - return sprintf( - '%s/%s', - $this->basePath(), - $this->config('paths.src', 'app') - ); + return $this->app['config']['view.paths'][0] ?? $this->app->resourcePath('views'); + } + + /** + * Get the path to the factory directory. + * + * @return string + */ + public function factoryPath() + { + return $this->app->databasePath('factories'); + } + + /** + * Get the path to the migration directory. + * + * @return string + */ + public function migrationPath() + { + return $this->app->databasePath('migrations'); + } + + /** + * Get the path to the seeder directory. + */ + public function seederPath(): string + { + if (is_dir($seederPath = $this->app->databasePath('seeds'))) { + return $seederPath; + } + + return $this->app->databasePath('seeders'); } /** * Preset namespace. + * + * @return string */ - public function rootNamespace(): string + public function rootNamespace() { - return $this->config['namespace'] ?? 'App'; + return $this->app->getNamespace(); } /** - * Testing namespace. + * Command namespace. + * + * @return string */ - public function testingNamespace(): string + public function commandNamespace() { - return $this->config('testing.namespace', 'Tests'); + return "{$this->rootNamespace()}Console\Commands\\"; } /** * Model namespace. + * + * @return string */ - public function modelNamespace(): string + public function modelNamespace() { - return $this->config('model.namespace', $this->rootNamespace().'\Models'); + return is_dir("{$this->sourcePath()}/Models") ? "{$this->rootNamespace()}Models\\" : $this->rootNamespace(); } /** * Provider namespace. + * + * @return string */ - public function providerNamespace(): string + public function providerNamespace() { - return $this->config('provider.namespace', $this->rootNamespace().'\Providers'); + return "{$this->rootNamespace()}Providers\\"; } /** - * Get custom stub path. + * Testing namespace. + * + * @return string */ - public function getCustomStubPath(): ?string + public function testingNamespace() { - return sprintf('%s/%s', $this->basePath(), 'stubs'); + return 'Tests\\'; } /** - * Sync commands to preset. + * Database factory namespace. + * + * @return string */ - public function addAdditionalCommands(Application $app): void + public function factoryNamespace() { - parent::addAdditionalCommands($app); + return 'Database\Factories\\'; + } - foreach (Arr::wrap(static::$generators) as $generator) { - /** @var class-string<\Symfony\Component\Console\Command\Command> $generator */ - $app->add(new $generator($this)); - } + /** + * Database seeder namespace. + * + * @return string + */ + public function seederNamespace() + { + return 'Database\Seeders\\'; + } + + /** + * Preset has custom stub path. + * + * @return bool + */ + public function hasCustomStubPath() + { + return true; } } diff --git a/src/Presets/Package.php b/src/Presets/Package.php deleted file mode 100644 index c977120..0000000 --- a/src/Presets/Package.php +++ /dev/null @@ -1,114 +0,0 @@ -> - */ - protected static $generators = []; - - /** - * Add global command. - * - * @param array> $generators - */ - public static function commands(array $generators): void - { - static::$generators = array_merge(static::$generators, $generators); - } - - /** - * Preset name. - */ - public function name(): string - { - return 'package'; - } - - /** - * Get the path to the base working directory. - */ - public function laravelPath(): string - { - return sprintf('%s/orchestra/testbench-core/laravel', $this->vendorPath()); - } - - /** - * Get the path to the source directory. - */ - public function sourcePath(): string - { - return sprintf( - '%s/%s', - $this->basePath(), - $this->config('paths.src', 'src') - ); - } - - /** - * Preset namespace. - */ - public function rootNamespace(): string - { - $namespace = trim($this->config['namespace'] ?? ''); - - if (empty($namespace)) { - throw new InvalidArgumentException("Please configure namespace configuration under 'canvas.yaml'"); - } - - return $namespace; - } - - /** - * Testing namespace. - */ - public function testingNamespace(): string - { - return $this->config('testing.namespace', $this->rootNamespace().'\Tests'); - } - - /** - * Model namespace. - */ - public function modelNamespace(): string - { - return $this->config('model.namespace', $this->rootNamespace()); - } - - /** - * Provider namespace. - */ - public function providerNamespace(): string - { - return $this->config('provider.namespace', $this->rootNamespace()); - } - - /** - * Get custom stub path. - */ - public function getCustomStubPath(): ?string - { - return sprintf('%s/stubs', $this->basePath()); - } - - /** - * Sync commands to preset. - */ - public function addAdditionalCommands(Application $app): void - { - parent::addAdditionalCommands($app); - - foreach (Arr::wrap(static::$generators) as $generator) { - /** @var class-string<\Symfony\Component\Console\Command\Command> $generator */ - $app->add(new $generator($this)); - } - } -} diff --git a/src/Presets/Preset.php b/src/Presets/Preset.php index c62a001..8b6de9e 100644 --- a/src/Presets/Preset.php +++ b/src/Presets/Preset.php @@ -2,201 +2,175 @@ namespace Orchestra\Canvas\Core\Presets; -use Illuminate\Filesystem\Filesystem; -use Illuminate\Support\Arr; -use Symfony\Component\Console\Application; +use Illuminate\Contracts\Foundation\Application; +use LogicException; abstract class Preset { + /** + * The application instance. + * + * @var \Illuminate\Contracts\Foundation\Application + */ + protected $app; + /** * Construct a new preset. * - * @param array $config + * @return void */ - public function __construct( - protected array $config, - protected string $basePath, - protected Filesystem $files - ) { - // + public function __construct(Application $app) + { + $this->app = $app; } /** * Check if preset name equal to $name. + * + * @param string $name + * @return bool */ - public function is(string $name): bool + public function is($name) { return $this->name() === $name; } /** - * Get configuration. + * Get the model for the default guard's user provider. * - * @param mixed|null $default + * @param string|null $guard + * @return string|null */ - public function config(?string $key = null, $default = null) + public function userProviderModel($guard = null) { - if (\is_null($key)) { - return $this->config; + /** @var \Illuminate\Contracts\Config\Repository $config */ + $config = $this->app->make('config'); + + $guard = $guard ?: $config->get('auth.defaults.guard'); + + if (\is_null($provider = $config->get('auth.guards.'.$guard.'.provider'))) { + throw new LogicException('The ['.$guard.'] guard is not defined in your "auth" configuration file.'); } - return Arr::get($this->config, $key, $default); + return $config->get("auth.providers.{$provider}.model"); } /** - * Get the filesystem instance. + * Preset name. + * + * @return string */ - public function filesystem(): Filesystem - { - return $this->files; - } + abstract public function name(); /** * Get the path to the base working directory. + * + * @return string */ - public function basePath(): string - { - return $this->basePath; - } + abstract public function basePath(); /** - * Get the path to the testing directory. + * Get the path to the source directory. + * + * @return string */ - public function testingPath(): string - { - return "{$this->basePath}/tests"; - } + abstract public function sourcePath(); /** - * Get the path to the vendor directory. + * Get the path to the testing directory. + * + * @return string */ - public function vendorPath(): string - { - return "{$this->basePath}/vendor"; - } + abstract public function testingPath(); /** * Get the path to the resource directory. + * + * @return string */ - public function resourcePath(): string - { - return sprintf( - '%s/%s', - $this->basePath(), - $this->config('paths.resource', 'resources') - ); - } - - /** - * Get the path to the factory directory. - */ - public function factoryPath(): string - { - return sprintf( - '%s/%s', - $this->basePath(), - $this->config('factory.path', 'database/factories') - ); - } - - /** - * Get the path to the migration directory. - */ - public function migrationPath(): string - { - return sprintf( - '%s/%s', - $this->basePath(), - $this->config('migration.path', 'database/migrations') - ); - } - - /** - * Get the path to the seeder directory. - */ - public function seederPath(): string - { - return sprintf( - '%s/%s', - $this->basePath(), - $this->config('seeder.path', 'database/seeders') - ); - } + abstract public function resourcePath(); /** - * Database factory namespace. + * Get the path to the view directory. + * + * @return string */ - public function factoryNamespace(): string - { - return $this->config('factory.namespace', 'Database\Factories'); - } + abstract public function viewPath(); /** - * Database seeder namespace. + * Get the path to the factory directory. + * + * @return string */ - public function seederNamespace(): string - { - return $this->config('seeder.path', 'Database\Seeders'); - } + abstract public function factoryPath(); /** - * Sync commands to preset. + * Get the path to the migration directory. + * + * @return string */ - public function addAdditionalCommands(Application $app): void - { - tap($this->config('generators') ?? [], function ($generators) use ($app) { - foreach (Arr::wrap($generators) as $generator) { - /** @var class-string<\Symfony\Component\Console\Command\Command> $generator */ - $app->add(new $generator($this)); - } - }); - } + abstract public function migrationPath(); /** - * Preset has custom stub path. + * Get the path to the seeder directory. + * + * @return string */ - public function hasCustomStubPath(): bool - { - return ! \is_null($this->getCustomStubPath()); - } + abstract public function seederPath(); /** - * Preset name. + * Preset namespace. + * + * @return string */ - abstract public function name(): string; + abstract public function rootNamespace(); /** - * Get the path to the base working directory. + * Command namespace. + * + * @return string */ - abstract public function laravelPath(): string; + abstract public function commandNamespace(); /** - * Get the path to the source directory. + * Model namespace. + * + * @return string */ - abstract public function sourcePath(): string; + abstract public function modelNamespace(); /** - * Preset namespace. + * Provider namespace. + * + * @return string */ - abstract public function rootNamespace(): string; + abstract public function providerNamespace(); /** * Testing namespace. + * + * @return string */ - abstract public function testingNamespace(): string; + abstract public function testingNamespace(); /** - * Model namespace. + * Database factory namespace. + * + * @return string */ - abstract public function modelNamespace(): string; + abstract public function factoryNamespace(); /** - * Provider namespace. + * Database seeder namespace. + * + * @return string */ - abstract public function providerNamespace(): string; + abstract public function seederNamespace(); /** - * Get custom stub path. + * Preset has custom stub path. + * + * @return bool */ - abstract public function getCustomStubPath(): ?string; + abstract public function hasCustomStubPath(); } diff --git a/src/TestGenerator.php b/src/TestGenerator.php deleted file mode 100644 index 2c4f453..0000000 --- a/src/TestGenerator.php +++ /dev/null @@ -1,23 +0,0 @@ -option('test') && ! $this->option('pest')) { - return false; - } - - return $this->callSilent('make:test', [ - 'name' => Str::of($path)->after($this->preset->sourcePath())->beforeLast('.php')->append('Test')->replace('\\', '/'), - '--pest' => $this->option('pest'), - ]) == 0; - } -} diff --git a/src/Testing/Concerns/InteractsWithPublishedFiles.php b/src/Testing/Concerns/InteractsWithPublishedFiles.php deleted file mode 100644 index 23815c2..0000000 --- a/src/Testing/Concerns/InteractsWithPublishedFiles.php +++ /dev/null @@ -1,157 +0,0 @@ -filesystem = $this->app['files']; - - $this->cleanUpFiles(); - $this->cleanUpMigrationFiles(); - } - - /** - * Teardown Interacts with Published Files environment. - */ - protected function tearDownInteractsWithPublishedFiles(): void - { - $this->cleanUpFiles(); - $this->cleanUpMigrationFiles(); - - unset($this->filesystem); - } - - /** - * Assert file does contains data. - * - * @param array $contains - */ - protected function assertFileContains(array $contains, string $file, string $message = ''): void - { - $this->assertFilenameExists($file); - - $haystack = $this->filesystem->get( - $this->app->basePath($file) - ); - - foreach ($contains as $needle) { - $this->assertStringContainsString($needle, $haystack, $message); - } - } - - /** - * Assert file doesn't contains data. - * - * @param array $contains - */ - protected function assertFileNotContains(array $contains, string $file, string $message = ''): void - { - $this->assertFilenameExists($file); - - $haystack = $this->filesystem->get( - $this->app->basePath($file) - ); - - foreach ($contains as $needle) { - $this->assertStringNotContainsString($needle, $haystack, $message); - } - } - - /** - * Assert file does contains data. - * - * @param array $contains - */ - protected function assertMigrationFileContains(array $contains, string $file, string $message = ''): void - { - $haystack = $this->filesystem->get($this->getMigrationFile($file)); - - foreach ($contains as $needle) { - $this->assertStringContainsString($needle, $haystack, $message); - } - } - - /** - * Assert file doesn't contains data. - * - * @param array $contains - */ - protected function assertMigrationFileNotContains(array $contains, string $file, string $message = ''): void - { - $haystack = $this->filesystem->get($this->getMigrationFile($file)); - - foreach ($contains as $needle) { - $this->assertStringNotContainsString($needle, $haystack, $message); - } - } - - /** - * Assert filename exists. - */ - protected function assertFilenameExists(string $file): void - { - $appFile = $this->app->basePath($file); - - $this->assertTrue($this->filesystem->exists($appFile), "Assert file {$file} does exist"); - } - - /** - * Assert filename not exists. - */ - protected function assertFilenameNotExists(string $file): void - { - $appFile = $this->app->basePath($file); - - $this->assertTrue(! $this->filesystem->exists($appFile), "Assert file {$file} doesn't exist"); - } - - /** - * Removes generated files. - */ - protected function cleanUpFiles(): void - { - $this->filesystem->delete( - Collection::make($this->files ?? []) - ->transform(fn ($file) => $this->app->basePath($file)) - ->filter(fn ($file) => $this->filesystem->exists($file)) - ->all() - ); - } - - /** - * Removes generated migration files. - */ - protected function getMigrationFile(string $filename): string - { - $migrationPath = $this->app->databasePath('migrations'); - - return $this->filesystem->glob("{$migrationPath}/*{$filename}")[0]; - } - - /** - * Removes generated migration files. - */ - protected function cleanUpMigrationFiles(): void - { - $this->filesystem->delete( - Collection::make($this->filesystem->files($this->app->databasePath('migrations'))) - ->filter(fn ($file) => Str::endsWith($file, '.php')) - ->all() - ); - } -} diff --git a/src/Testing/TestCase.php b/src/Testing/TestCase.php deleted file mode 100644 index 28411cb..0000000 --- a/src/Testing/TestCase.php +++ /dev/null @@ -1,15 +0,0 @@ -|null - */ - protected $files = []; -} diff --git a/tests/Feature/Commands/Generators/CodeTest.php b/tests/Feature/Commands/Generators/CodeTest.php deleted file mode 100644 index eb1c192..0000000 --- a/tests/Feature/Commands/Generators/CodeTest.php +++ /dev/null @@ -1,53 +0,0 @@ - 'App', 'generators' => [Generators\Code::class]], $this->app->basePath(), $this->filesystem - ); - - $this->instance('orchestra.canvas', $preset); - - Artisan::starting(fn ($artisan) => $preset->addAdditionalCommands($artisan)); - - $this->artisan('make:class', ['name' => 'Value/Foo']) - ->assertExitCode(0); - - $this->assertFileContains([ - 'namespace App\Value;', - 'class Foo', - ], 'app/Value/Foo.php'); - } - - /** @test */ - public function it_cant_generate_class_file() - { - $this->expectException('Symfony\Component\Console\Exception\CommandNotFoundException'); - $this->expectExceptionMessage('The command "make:class" does not exist.'); - - $this->artisan('make:class', ['name' => 'Foo']) - ->assertExitCode(0); - - $this->assertFileContains([ - 'namespace App\Value;', - 'class Foo', - ], 'app/Value/Foo.php'); - } -} diff --git a/tests/Feature/Commands/Generators/ConsoleGeneratorTest.php b/tests/Feature/Commands/Generators/ConsoleGeneratorTest.php deleted file mode 100644 index c7a48f6..0000000 --- a/tests/Feature/Commands/Generators/ConsoleGeneratorTest.php +++ /dev/null @@ -1,87 +0,0 @@ - 'App', 'generators' => [Generators\ConsoleGenerator::class]], $this->app->basePath(), $this->filesystem - ); - - $this->instance('orchestra.canvas', $preset); - - Artisan::starting(fn ($artisan) => $preset->addAdditionalCommands($artisan)); - - $this->artisan('make:generator', ['name' => 'FooCommand']) - ->assertExitCode(0); - - $this->assertFileContains([ - 'namespace App\Console\Commands;', - 'use Orchestra\Canvas\Commands\Generator;', - 'use Symfony\Component\Console\Attribute\AsCommand;', - '#[AsCommand(name: \'make:name\', description: \'Create a new class\')]', - 'class FooCommand extends Generator', - ], 'app/Console/Commands/FooCommand.php'); - } - - /** @test */ - public function it_can_generate_command_file_with_command_name() - { - $preset = new Laravel( - ['namespace' => 'App', 'generators' => [Generators\ConsoleGenerator::class]], $this->app->basePath(), $this->filesystem - ); - - $this->instance('orchestra.canvas', $preset); - - Artisan::starting(fn ($artisan) => $preset->addAdditionalCommands($artisan)); - - $this->artisan('make:generator', ['name' => 'FooCommand', '--command' => 'make:foobar']) - ->assertExitCode(0); - - $this->assertFileContains([ - 'namespace App\Console\Commands;', - 'use Orchestra\Canvas\Commands\Generator;', - 'use Symfony\Component\Console\Attribute\AsCommand;', - '#[AsCommand(name: \'make:foobar\', description: \'Create a new class\')]', - 'class FooCommand extends Generator', - ], 'app/Console/Commands/FooCommand.php'); - } - - /** @test */ - public function it_can_generate_command_file_with_command_name_without_make_prefix() - { - $preset = new Laravel( - ['namespace' => 'App', 'generators' => [Generators\ConsoleGenerator::class]], $this->app->basePath(), $this->filesystem - ); - - $this->instance('orchestra.canvas', $preset); - - Artisan::starting(fn ($artisan) => $preset->addAdditionalCommands($artisan)); - - $this->artisan('make:generator', ['name' => 'FooCommand', '--command' => 'foobar']) - ->assertExitCode(0); - - $this->assertFileContains([ - 'namespace App\Console\Commands;', - 'use Orchestra\Canvas\Commands\Generator;', - 'use Symfony\Component\Console\Attribute\AsCommand;', - '#[AsCommand(name: \'make:foobar\', description: \'Create a new class\')]', - 'class FooCommand extends Generator', - ], 'app/Console/Commands/FooCommand.php'); - } -} diff --git a/tests/Feature/CommandsProviderTest.php b/tests/Feature/CommandsProviderTest.php deleted file mode 100644 index 3f9c2b6..0000000 --- a/tests/Feature/CommandsProviderTest.php +++ /dev/null @@ -1,34 +0,0 @@ -getBasePath(); - $preset = $this->presetForLaravel($this->app); - - $this->assertSame('laravel', $preset->name()); - $this->assertTrue($preset->is('laravel')); - $this->assertFalse($preset->is('package')); - - $this->assertSame($directory, $preset->basePath()); - - $this->assertSame('App', $preset->rootNamespace()); - $this->assertSame('App\Models', $preset->modelNamespace()); - $this->assertSame('App\Providers', $preset->providerNamespace()); - - $this->assertSame("{$directory}/app", $preset->sourcePath()); - $this->assertSame("{$directory}/resources", $preset->resourcePath()); - $this->assertSame("{$directory}/database/factories", $preset->factoryPath()); - $this->assertSame("{$directory}/database/migrations", $preset->migrationPath()); - $this->assertSame("{$directory}/database/seeders", $preset->seederPath()); - } -} diff --git a/tests/Presets/LaravelPresetTest.php b/tests/Presets/LaravelPresetTest.php new file mode 100644 index 0000000..97689a4 --- /dev/null +++ b/tests/Presets/LaravelPresetTest.php @@ -0,0 +1,53 @@ +app[PresetManager::class]->driver('laravel'); + + $this->assertInstanceOf(Laravel::class, $preset); + $this->assertSame('laravel', $preset->name()); + $this->assertTrue($preset->is('laravel')); + + $this->assertSame($this->app->basePath(), $preset->basePath()); + $this->assertSame($this->app->basePath('app'), $preset->sourcePath()); + $this->assertSame($this->app->basePath('tests'), $preset->testingPath()); + $this->assertSame($this->app->resourcePath(), $preset->resourcePath()); + $this->assertSame($this->app->resourcePath('views'), $preset->viewPath()); + $this->assertSame($this->app->databasePath('factories'), $preset->factoryPath()); + $this->assertSame($this->app->databasePath('migrations'), $preset->migrationPath()); + $this->assertSame($this->app->databasePath('seeders'), $preset->seederPath()); + + $this->assertSame($this->app->getNamespace(), $preset->rootNamespace()); + $this->assertSame($this->app->getNamespace().'Console\Commands\\', $preset->commandNamespace()); + $this->assertSame($this->app->getNamespace().'Models\\', $preset->modelNamespace()); + $this->assertSame($this->app->getNamespace().'Providers\\', $preset->providerNamespace()); + $this->assertSame('Database\Factories\\', $preset->factoryNamespace()); + $this->assertSame('Database\Seeders\\', $preset->seederNamespace()); + $this->assertSame('Tests\\', $preset->testingNamespace()); + + $this->assertTrue($preset->hasCustomStubPath()); + $this->assertSame('Illuminate\Foundation\Auth\User', $preset->userProviderModel()); + } + + /** @test */ + public function it_available_as_default_driver() + { + $preset = $this->app[PresetManager::class]->driver(); + + $this->assertInstanceOf(Laravel::class, $preset); + $this->assertSame('laravel', $preset->name()); + $this->assertTrue($preset->is('laravel')); + } +} diff --git a/tests/Unit/Presets/LaravelTest.php b/tests/Unit/Presets/LaravelTest.php deleted file mode 100644 index ae4bb50..0000000 --- a/tests/Unit/Presets/LaravelTest.php +++ /dev/null @@ -1,96 +0,0 @@ -assertSame('laravel', $preset->name()); - $this->assertSame([], $preset->config()); - $this->assertTrue($preset->is('laravel')); - $this->assertFalse($preset->is('package')); - - $this->assertSame($directory, $preset->basePath()); - $this->assertSame($preset->basePath(), $preset->laravelPath()); - - $this->assertSame('App', $preset->rootNamespace()); - $this->assertSame('Tests', $preset->testingNamespace()); - $this->assertSame('App\Models', $preset->modelNamespace()); - $this->assertSame('App\Providers', $preset->providerNamespace()); - $this->assertSame('Database\Factories', $preset->factoryNamespace()); - $this->assertSame('Database\Seeders', $preset->seederNamespace()); - - $this->assertSame("{$directory}/app", $preset->sourcePath()); - $this->assertSame("{$directory}/vendor", $preset->vendorPath()); - $this->assertSame("{$directory}/resources", $preset->resourcePath()); - $this->assertSame("{$directory}/database/factories", $preset->factoryPath()); - $this->assertSame("{$directory}/database/migrations", $preset->migrationPath()); - $this->assertSame("{$directory}/database/seeders", $preset->seederPath()); - - $this->assertTrue($preset->hasCustomStubPath()); - $this->assertSame("{$directory}/stubs", $preset->getCustomStubPath()); - - $this->assertSame($files, $preset->filesystem()); - } - - /** @test */ - public function it_can_configure_model_namespace() - { - $directory = __DIR__; - $preset = new Laravel(['namespace' => 'App', 'model' => ['namespace' => 'App\Model']], $directory, new Filesystem()); - - $this->assertSame('App', $preset->rootNamespace()); - $this->assertSame('App\Model', $preset->modelNamespace()); - $this->assertSame('App\Providers', $preset->providerNamespace()); - } - - /** @test */ - public function it_can_configure_provider_namespace() - { - $directory = __DIR__; - $preset = new Laravel(['namespace' => 'App', 'provider' => ['namespace' => 'App']], $directory, new Filesystem()); - - $this->assertSame('App', $preset->rootNamespace()); - $this->assertSame('App\Models', $preset->modelNamespace()); - $this->assertSame('App', $preset->providerNamespace()); - } - - /** @test */ - public function it_can_add_additional_commands() - { - Laravel::commands([ - Generators\Code::class, - ]); - - $app = m::mock(Application::class); - $app->shouldReceive('add') - ->once() - ->with(m::type(Generators\Code::class)) - ->andReturnUsing(fn ($generator) => $this->assertInstanceOf(Generators\Code::class, $generator)); - - $directory = __DIR__; - $preset = new Laravel(['namespace' => 'App', 'provider' => ['namespace' => 'App']], $directory, new Filesystem()); - - $preset->addAdditionalCommands($app); - } -} diff --git a/tests/Unit/Presets/PackageTest.php b/tests/Unit/Presets/PackageTest.php deleted file mode 100644 index 38655e3..0000000 --- a/tests/Unit/Presets/PackageTest.php +++ /dev/null @@ -1,99 +0,0 @@ - 'FooBar'], $directory, $files = new Filesystem()); - - $this->assertSame('package', $preset->name()); - $this->assertSame(['namespace' => 'FooBar'], $preset->config()); - $this->assertTrue($preset->is('package')); - $this->assertFalse($preset->is('laravel')); - - $this->assertSame($directory, $preset->basePath()); - $this->assertSame("{$directory}/vendor/orchestra/testbench-core/laravel", $preset->laravelPath()); - - $this->assertSame('FooBar', $preset->rootNamespace()); - $this->assertSame('FooBar\Tests', $preset->testingNamespace()); - $this->assertSame('FooBar', $preset->modelNamespace()); - $this->assertSame('FooBar', $preset->providerNamespace()); - $this->assertSame('Database\Factories', $preset->factoryNamespace()); - $this->assertSame('Database\Seeders', $preset->seederNamespace()); - - $this->assertSame("{$directory}/src", $preset->sourcePath()); - $this->assertSame("{$directory}/vendor", $preset->vendorPath()); - $this->assertSame("{$directory}/resources", $preset->resourcePath()); - $this->assertSame("{$directory}/database/factories", $preset->factoryPath()); - $this->assertSame("{$directory}/database/migrations", $preset->migrationPath()); - $this->assertSame("{$directory}/database/seeders", $preset->seederPath()); - - $this->assertTrue($preset->hasCustomStubPath()); - $this->assertSame("{$directory}/stubs", $preset->getCustomStubPath()); - - $this->assertSame($files, $preset->filesystem()); - } - - /** @test */ - public function it_can_configure_model_namespace() - { - $directory = __DIR__; - $preset = new Package(['namespace' => 'FooBar', 'model' => ['namespace' => 'FooBar\Model']], $directory, new Filesystem()); - - $this->assertSame('FooBar', $preset->rootNamespace()); - $this->assertSame('FooBar\Model', $preset->modelNamespace()); - $this->assertSame('FooBar', $preset->providerNamespace()); - } - - /** @test */ - public function it_can_configure_provider_namespace() - { - $directory = __DIR__; - $preset = new Package(['namespace' => 'FooBar', 'provider' => ['namespace' => 'FooBar\Providers']], $directory, new Filesystem()); - - $this->assertSame('FooBar', $preset->rootNamespace()); - $this->assertSame('FooBar', $preset->modelNamespace()); - $this->assertSame('FooBar\Providers', $preset->providerNamespace()); - } - - /** @test */ - public function it_requires_root_namespace_to_be_configured() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage("Please configure namespace configuration under 'canvas.yaml'"); - $directory = __DIR__; - $preset = new Package([], $directory, new Filesystem()); - - $preset->rootNamespace(); - } - - /** @test */ - public function it_can_add_additional_commands() - { - Package::commands([ - Generators\Code::class, - ]); - - $app = m::mock(Application::class); - $app->shouldReceive('add') - ->once() - ->with(m::type(Generators\Code::class)) - ->andReturnUsing(fn ($generator) => $this->assertInstanceOf(Generators\Code::class, $generator)); - - $directory = __DIR__; - $preset = new Package(['namespace' => 'App', 'provider' => ['namespace' => 'App']], $directory, new Filesystem()); - - $preset->addAdditionalCommands($app); - } -}