From 259297e41b45d024a107a4527a04e298f3f9614b Mon Sep 17 00:00:00 2001 From: Jasper Tey Date: Sat, 23 Mar 2024 15:31:32 -0400 Subject: [PATCH] Refactor domain path and namespace configuration. --- CHANGELOG.md | 7 ++++ README.md | 40 ++++++------------- config/ddd.php | 40 ++++++------------- src/Commands/DomainGeneratorCommand.php | 8 ++-- src/Commands/InstallCommand.php | 6 +-- src/Factories/DomainFactory.php | 3 +- src/Support/Domain.php | 4 +- src/Support/DomainResolver.php | 27 ++++++++++++- src/ValueObjects/DomainNamespaces.php | 4 +- tests/ConfigTest.php | 18 +++++++++ tests/Generator/MakeActionTest.php | 9 +++-- tests/Generator/MakeBaseModelTest.php | 3 +- tests/Generator/MakeBaseViewModelTest.php | 3 +- .../Generator/MakeDataTransferObjectTest.php | 5 ++- tests/Generator/MakeFactoryTest.php | 3 +- tests/Generator/MakeModelTest.php | 11 ++--- tests/Generator/MakeValueObjectTest.php | 5 ++- tests/Generator/MakeViewModelTest.php | 9 +++-- tests/InstallTest.php | 5 ++- 19 files changed, 120 insertions(+), 90 deletions(-) create mode 100644 tests/ConfigTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 68d37e0..935090b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to `laravel-ddd` will be documented in this file. +## [Unversioned] +### Added +- Config keys `ddd.domain_path` and `ddd.domain_namespace` added to specify path to the domain folder and root domain namespace. This allows a custom domain namespace if it differs from the basename of the domain path. e.g., `src/Domains` domain folder, but with `Domain` namespace. + +### Deprecated +- Config `ddd.paths.domains` deprecated in favour of `ddd.domain_path` and `ddd.domain_namespace`. + ## [0.9.0] - 2024-03-11 ### Changed - Internals: normalize generator file paths using `DIRECTORY_SEPARATOR` for consistency across different operating systems when it comes to console output and test expectations. diff --git a/README.md b/README.md index 47d510d..da8c48d 100644 --- a/README.md +++ b/README.md @@ -82,20 +82,23 @@ return [ /* |-------------------------------------------------------------------------- - | Paths + | Domain Path |-------------------------------------------------------------------------- | - | This value contains paths to the layers of the application in the context - | of domain driven design, relative to the base folder of the application. + | The path to the domain folder relative to the application root. | */ + 'domain_path' => 'src/Domain', - 'paths' => [ - // - // Path to the Domain layer. - // - 'domains' => 'src/Domain', - ], + /* + |-------------------------------------------------------------------------- + | Domain Namespace + |-------------------------------------------------------------------------- + | + | The root domain namespace. + | + */ + 'domain_namespace' => 'Domain', /* |-------------------------------------------------------------------------- @@ -114,29 +117,10 @@ return [ | */ 'namespaces' => [ - // - // Models - // 'models' => 'Models', - - // - // Data Transfer Objects (DTO) - // 'data_transfer_objects' => 'Data', - - // - // View Models - // 'view_models' => 'ViewModels', - - // - // Value Objects - // 'value_objects' => 'ValueObjects', - - // - // Actions - // 'actions' => 'Actions', ], diff --git a/config/ddd.php b/config/ddd.php index d89e17b..e7dd5bf 100644 --- a/config/ddd.php +++ b/config/ddd.php @@ -4,20 +4,23 @@ /* |-------------------------------------------------------------------------- - | Paths + | Domain Path |-------------------------------------------------------------------------- | - | This value contains paths to the layers of the application in the context - | of domain driven design, relative to the base folder of the application. + | The path to the domain folder relative to the application root. | */ + 'domain_path' => 'src/Domain', - 'paths' => [ - // - // Path to the Domain layer. - // - 'domains' => 'src/Domain', - ], + /* + |-------------------------------------------------------------------------- + | Domain Namespace + |-------------------------------------------------------------------------- + | + | The root domain namespace. + | + */ + 'domain_namespace' => 'Domain', /* |-------------------------------------------------------------------------- @@ -36,29 +39,10 @@ | */ 'namespaces' => [ - // - // Models - // 'models' => 'Models', - - // - // Data Transfer Objects (DTO) - // 'data_transfer_objects' => 'Data', - - // - // View Models - // 'view_models' => 'ViewModels', - - // - // Value Objects - // 'value_objects' => 'ValueObjects', - - // - // Actions - // 'actions' => 'Actions', ], diff --git a/src/Commands/DomainGeneratorCommand.php b/src/Commands/DomainGeneratorCommand.php index a4fcab9..016c417 100644 --- a/src/Commands/DomainGeneratorCommand.php +++ b/src/Commands/DomainGeneratorCommand.php @@ -4,6 +4,7 @@ use Illuminate\Console\GeneratorCommand; use Illuminate\Support\Str; +use Lunarstorm\LaravelDDD\Support\DomainResolver; use Lunarstorm\LaravelDDD\Support\Path; use Symfony\Component\Console\Input\InputArgument; @@ -22,9 +23,8 @@ protected function getArguments() protected function rootNamespace() { - return str($this->getDomainBasePath()) + return str(DomainResolver::getConfiguredDomainNamespace()) ->rtrim('/\\') - ->basename() ->toString(); } @@ -58,7 +58,9 @@ protected function getDomain() protected function getDomainBasePath() { - return Path::normalize($this->laravel->basePath(config('ddd.paths.domains', 'src/Domains'))); + return Path::normalize($this->laravel->basePath( + DomainResolver::getConfiguredDomainPath() ?? 'src/Domain' + )); } protected function getPath($name) diff --git a/src/Commands/InstallCommand.php b/src/Commands/InstallCommand.php index 4897c79..b566358 100644 --- a/src/Commands/InstallCommand.php +++ b/src/Commands/InstallCommand.php @@ -3,6 +3,7 @@ namespace Lunarstorm\LaravelDDD\Commands; use Illuminate\Console\Command; +use Lunarstorm\LaravelDDD\Support\DomainResolver; use Symfony\Component\Process\Process; class InstallCommand extends Command @@ -34,11 +35,10 @@ public function handle(): int public function registerDomainAutoload() { - $domainPath = config('ddd.paths.domains'); + $domainPath = DomainResolver::getConfiguredDomainPath(); - $domainRootNamespace = str($domainPath) + $domainRootNamespace = str(DomainResolver::getConfiguredDomainNamespace()) ->rtrim('/\\') - ->basename() ->toString(); $this->comment("Registering domain path `{$domainPath}` in composer.json..."); diff --git a/src/Factories/DomainFactory.php b/src/Factories/DomainFactory.php index 52a7bfa..8767e49 100644 --- a/src/Factories/DomainFactory.php +++ b/src/Factories/DomainFactory.php @@ -4,6 +4,7 @@ use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Str; +use Lunarstorm\LaravelDDD\Support\DomainResolver; abstract class DomainFactory extends Factory { @@ -14,7 +15,7 @@ abstract class DomainFactory extends Factory */ protected static function domainNamespace() { - return basename(config('ddd.paths.domains')).'\\'; + return Str::finish(DomainResolver::getConfiguredDomainNamespace(), '\\'); } /** diff --git a/src/Support/Domain.php b/src/Support/Domain.php index 1b3d1a0..c539313 100644 --- a/src/Support/Domain.php +++ b/src/Support/Domain.php @@ -54,12 +54,12 @@ public function __construct(string $domain, ?string $subdomain = null) $this->namespace = DomainNamespaces::from($this->domain, $this->subdomain); - $this->path = Path::join(config('ddd.paths.domains'), $this->domainWithSubdomain); + $this->path = Path::join(DomainResolver::getConfiguredDomainPath(), $this->domainWithSubdomain); } protected function getDomainBasePath() { - return app()->basePath(config('ddd.paths.domains')); + return app()->basePath(DomainResolver::getConfiguredDomainPath()); } public function path(?string $path = null): string diff --git a/src/Support/DomainResolver.php b/src/Support/DomainResolver.php index 04efe97..4a1ead4 100644 --- a/src/Support/DomainResolver.php +++ b/src/Support/DomainResolver.php @@ -2,13 +2,36 @@ namespace Lunarstorm\LaravelDDD\Support; +use Illuminate\Support\Facades\Config; +use Illuminate\Support\Str; + class DomainResolver { + public static function getConfiguredDomainPath(): string + { + if (Config::has('ddd.paths.domains')) { + // Deprecated + return config('ddd.paths.domains'); + } + + return config('ddd.domain_path'); + } + + public static function getConfiguredDomainNamespace(): string + { + if (Config::has('ddd.paths.domains')) { + // Deprecated + return basename(config('ddd.paths.domains')); + } + + return config('ddd.domain_namespace'); + } + public static function guessDomainFromClass(string $class): ?string { - $domainNamespace = basename(config('ddd.paths.domains')).'\\'; + $domainNamespace = Str::finish(DomainResolver::getConfiguredDomainNamespace(), '\\'); - if (! str($class)->startsWith($domainNamespace)) { + if (!str($class)->startsWith($domainNamespace)) { // Not a domain model return null; } diff --git a/src/ValueObjects/DomainNamespaces.php b/src/ValueObjects/DomainNamespaces.php index b7307bb..44f9780 100644 --- a/src/ValueObjects/DomainNamespaces.php +++ b/src/ValueObjects/DomainNamespaces.php @@ -2,6 +2,8 @@ namespace Lunarstorm\LaravelDDD\ValueObjects; +use Lunarstorm\LaravelDDD\Support\DomainResolver; + class DomainNamespaces { public function __construct( @@ -21,7 +23,7 @@ public static function from(string $domain, ?string $subdomain = null): self ->when($subdomain, fn ($domain) => $domain->append("\\{$subdomain}")) ->toString(); - $root = basename(config('ddd.paths.domains')); + $root = DomainResolver::getConfiguredDomainNamespace(); $domainNamespace = implode('\\', [$root, $domainWithSubdomain]); diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php new file mode 100644 index 0000000..c42fd63 --- /dev/null +++ b/tests/ConfigTest.php @@ -0,0 +1,18 @@ +word(); + + Config::set('ddd.domain_path', $path); + + expect(DomainResolver::getConfiguredDomainPath())->toEqual($path); +}); + +it('can customize the domain root namespace via ddd.domain_namespace', function () { + Config::set('ddd.domain_namespace', 'Doughmain'); + + expect(DomainResolver::getConfiguredDomainNamespace())->toEqual('Doughmain'); +}); diff --git a/tests/Generator/MakeActionTest.php b/tests/Generator/MakeActionTest.php index c5ae16f..d80cb6f 100644 --- a/tests/Generator/MakeActionTest.php +++ b/tests/Generator/MakeActionTest.php @@ -6,7 +6,8 @@ use Lunarstorm\LaravelDDD\Tests\Fixtures\Enums\Feature; it('can generate action objects', function ($domainPath, $domainRoot) { - Config::set('ddd.paths.domains', $domainPath); + Config::set('ddd.domain_path', $domainPath); + Config::set('ddd.domain_namespace', $domainRoot); $name = Str::studly(fake()->word()); $domain = Str::studly(fake()->word()); @@ -48,7 +49,7 @@ $domain = Str::studly(fake()->word()); $expectedPath = base_path(implode('/', [ - config('ddd.paths.domains'), + config('ddd.domain_path'), $domain, config('ddd.namespaces.actions'), "{$normalized}.php", @@ -73,7 +74,7 @@ $domain = Str::studly(fake()->word()); $expectedPath = base_path(implode('/', [ - config('ddd.paths.domains'), + config('ddd.domain_path'), $domain, config('ddd.namespaces.actions'), "{$name}.php", @@ -100,7 +101,7 @@ $domain = Str::studly(fake()->word()); $expectedPath = base_path(implode('/', [ - config('ddd.paths.domains'), + config('ddd.domain_path'), $domain, config('ddd.namespaces.actions'), "{$name}.php", diff --git a/tests/Generator/MakeBaseModelTest.php b/tests/Generator/MakeBaseModelTest.php index 8713df0..f7507e8 100644 --- a/tests/Generator/MakeBaseModelTest.php +++ b/tests/Generator/MakeBaseModelTest.php @@ -5,7 +5,8 @@ use Lunarstorm\LaravelDDD\Tests\Fixtures\Enums\Feature; it('can generate domain base model', function ($domainPath, $domainRoot) { - Config::set('ddd.paths.domains', $domainPath); + Config::set('ddd.domain_path', $domainPath); + Config::set('ddd.domain_namespace', $domainRoot); $modelName = 'BaseModel'; $domain = 'Shared'; diff --git a/tests/Generator/MakeBaseViewModelTest.php b/tests/Generator/MakeBaseViewModelTest.php index 49d1df1..9b85555 100644 --- a/tests/Generator/MakeBaseViewModelTest.php +++ b/tests/Generator/MakeBaseViewModelTest.php @@ -5,7 +5,8 @@ use Lunarstorm\LaravelDDD\Tests\Fixtures\Enums\Feature; it('can generate base view model', function ($domainPath, $domainRoot) { - Config::set('ddd.paths.domains', $domainPath); + Config::set('ddd.domain_path', $domainPath); + Config::set('ddd.domain_namespace', $domainRoot); $className = 'ViewModel'; $domain = 'Shared'; diff --git a/tests/Generator/MakeDataTransferObjectTest.php b/tests/Generator/MakeDataTransferObjectTest.php index 6959bc7..5cfd786 100644 --- a/tests/Generator/MakeDataTransferObjectTest.php +++ b/tests/Generator/MakeDataTransferObjectTest.php @@ -6,7 +6,8 @@ use Lunarstorm\LaravelDDD\Tests\Fixtures\Enums\Feature; it('can generate data transfer objects', function ($domainPath, $domainRoot) { - Config::set('ddd.paths.domains', $domainPath); + Config::set('ddd.domain_path', $domainPath); + Config::set('ddd.domain_namespace', $domainRoot); $dtoName = Str::studly(fake()->word()); $domain = Str::studly(fake()->word()); @@ -48,7 +49,7 @@ $domain = Str::studly(fake()->word()); $expectedPath = base_path(implode('/', [ - config('ddd.paths.domains'), + config('ddd.domain_path'), $domain, config('ddd.namespaces.data_transfer_objects'), "{$normalized}.php", diff --git a/tests/Generator/MakeFactoryTest.php b/tests/Generator/MakeFactoryTest.php index 16ad901..2af1625 100644 --- a/tests/Generator/MakeFactoryTest.php +++ b/tests/Generator/MakeFactoryTest.php @@ -8,7 +8,8 @@ use Lunarstorm\LaravelDDD\Tests\Fixtures\Enums\Feature; it('can generate domain factories', function ($domainPath, $domainRoot, $domain, $subdomain) { - Config::set('ddd.paths.domains', $domainPath); + Config::set('ddd.domain_path', $domainPath); + Config::set('ddd.domain_namespace', $domainRoot); $modelName = Str::studly(fake()->word()); diff --git a/tests/Generator/MakeModelTest.php b/tests/Generator/MakeModelTest.php index de4f82a..d4abde0 100644 --- a/tests/Generator/MakeModelTest.php +++ b/tests/Generator/MakeModelTest.php @@ -7,7 +7,8 @@ use Lunarstorm\LaravelDDD\Tests\Fixtures\Enums\Feature; it('can generate domain models', function ($domainPath, $domainRoot) { - Config::set('ddd.paths.domains', $domainPath); + Config::set('ddd.domain_path', $domainPath); + Config::set('ddd.domain_namespace', $domainRoot); $modelName = Str::studly(fake()->word()); $domain = Str::studly(fake()->word()); @@ -46,7 +47,7 @@ })->with('domainPaths'); it('can generate a domain model with factory', function ($domainPath, $domainRoot, $domainName, $subdomain) { - Config::set('ddd.paths.domains', $domainPath); + Config::set('ddd.domain_path', $domainPath); $modelName = Str::studly(fake()->word()); @@ -93,7 +94,7 @@ $domain = Str::studly(fake()->word()); $expectedModelPath = base_path(implode('/', [ - config('ddd.paths.domains'), + config('ddd.domain_path'), $domain, config('ddd.namespaces.models'), "{$normalized}.php", @@ -111,14 +112,14 @@ Config::set('ddd.base_model', $baseModelClass); $expectedModelPath = base_path(implode('/', [ - config('ddd.paths.domains'), + config('ddd.domain_path'), $domain, config('ddd.namespaces.models'), "{$modelName}.php", ])); $expectedModelClass = implode('\\', [ - basename(config('ddd.paths.domains')), + basename(config('ddd.domain_path')), $domain, config('ddd.namespaces.models'), $modelName, diff --git a/tests/Generator/MakeValueObjectTest.php b/tests/Generator/MakeValueObjectTest.php index 8c4cbf7..92d8029 100644 --- a/tests/Generator/MakeValueObjectTest.php +++ b/tests/Generator/MakeValueObjectTest.php @@ -6,7 +6,8 @@ use Lunarstorm\LaravelDDD\Tests\Fixtures\Enums\Feature; it('can generate value objects', function ($domainPath, $domainRoot) { - Config::set('ddd.paths.domains', $domainPath); + Config::set('ddd.domain_path', $domainPath); + Config::set('ddd.domain_namespace', $domainRoot); $valueObjectName = Str::studly(fake()->word()); $domain = Str::studly(fake()->word()); @@ -48,7 +49,7 @@ $domain = Str::studly(fake()->word()); $expectedPath = base_path(implode('/', [ - config('ddd.paths.domains'), + config('ddd.domain_path'), $domain, config('ddd.namespaces.value_objects'), "{$normalized}.php", diff --git a/tests/Generator/MakeViewModelTest.php b/tests/Generator/MakeViewModelTest.php index 4105817..1854d16 100644 --- a/tests/Generator/MakeViewModelTest.php +++ b/tests/Generator/MakeViewModelTest.php @@ -6,7 +6,8 @@ use Lunarstorm\LaravelDDD\Tests\Fixtures\Enums\Feature; it('can generate view models', function ($domainPath, $domainRoot) { - Config::set('ddd.paths.domains', $domainPath); + Config::set('ddd.domain_path', $domainPath); + Config::set('ddd.domain_namespace', $domainRoot); $viewModelName = Str::studly(fake()->word()); $domain = Str::studly(fake()->word()); @@ -48,7 +49,7 @@ $domain = Str::studly(fake()->word()); $expectedPath = base_path(implode('/', [ - config('ddd.paths.domains'), + config('ddd.domain_path'), $domain, config('ddd.namespaces.view_models'), "{$normalized}.php", @@ -64,7 +65,7 @@ $domain = Str::studly(fake()->word()); $expectedPath = base_path(implode('/', [ - config('ddd.paths.domains'), + config('ddd.domain_path'), $domain, config('ddd.namespaces.view_models'), "{$className}.php", @@ -77,7 +78,7 @@ expect(file_exists($expectedPath))->toBeFalse(); // This currently only tests for the default base model - $expectedBaseViewModelPath = base_path(config('ddd.paths.domains').'/Shared/ViewModels/ViewModel.php'); + $expectedBaseViewModelPath = base_path(config('ddd.domain_path') . '/Shared/ViewModels/ViewModel.php'); if (file_exists($expectedBaseViewModelPath)) { unlink($expectedBaseViewModelPath); diff --git a/tests/InstallTest.php b/tests/InstallTest.php index dc05467..ae94877 100644 --- a/tests/InstallTest.php +++ b/tests/InstallTest.php @@ -25,7 +25,8 @@ }); it('can initialize composer.json', function ($domainPath, $domainRoot) { - Config::set('ddd.paths.domains', $domainPath); + Config::set('ddd.domain_path', $domainPath); + Config::set('ddd.domain_namespace', $domainRoot); $data = json_decode(file_get_contents(base_path('composer.json')), true); $before = data_get($data, ['autoload', 'psr-4', $domainRoot.'\\']); @@ -37,7 +38,7 @@ $data = json_decode(file_get_contents(base_path('composer.json')), true); $after = data_get($data, ['autoload', 'psr-4', $domainRoot.'\\']); - expect($after)->toEqual(config('ddd.paths.domains')); + expect($after)->toEqual(config('ddd.domain_path')); unlink(config_path('ddd.php')); })->with([