Skip to content

Commit

Permalink
[1.2] Refactoring stubs (#71)
Browse files Browse the repository at this point in the history
* Updates:
- normalize domain stub trait across all domain generators
- ensure ddd:controller is able to check for base controller existence
- refine ddd:model stub replacements

* Introduce ddd:publish and ddd:stub commands.

* Normalize the resolution of published stubs.

* Ensure post-build replacements are skipped in ddd:model when using custom stubs.

* Implement ddd:publish and ddd:stub commands.

* Refinements to readme and stub documentation.

---------

Co-authored-by: JasperTey <[email protected]>
  • Loading branch information
JasperTey and JasperTey authored Nov 10, 2024
1 parent 4d6523b commit 3c73e2d
Show file tree
Hide file tree
Showing 66 changed files with 1,216 additions and 268 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
All notable changes to `laravel-ddd` will be documented in this file.

## [Unreleased]
### Breaking
- Stubs are now published to `/stubs/ddd/*` instead of `resources/stubs/ddd/*`. If you have ddd stubs published from a prior version, they should be relocated.

### Added
- Experimental: Ability to configure the Application Layer, to generate domain objects that don't typically belong inside the domain layer.
- Ability to configure the Application Layer, to generate domain objects that don't typically belong inside the domain layer.
```php
// In config/ddd.php
'application' => [
Expand All @@ -22,6 +25,7 @@ All notable changes to `laravel-ddd` will be documented in this file.
- Added `ddd:middleware` to generate domain-specific middleware in the application layer.
- Added `ddd:migration` to generate domain migrations.
- Added `ddd:seeder` to generate domain seeders.
- Added `ddd:stub` to list, search, and publish one or more stubs as needed.
- Migration folders across domains will be registered and scanned when running `php artisan migrate`, in addition to the standard application `database/migrations` path.

### Changed
Expand Down
48 changes: 42 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Actions: [lorisleiva/laravel-actions](https://github.com/lorisleiva/laravel-acti
```bash
composer require lorisleiva/laravel-actions
```
The default DTO and Action stubs of this package reference classes from these packages. If this doesn't apply to your application, you may customize the stubs accordingly.
The default DTO and Action stubs of this package reference classes from these packages. If this doesn't apply to your application, you may [customize the stubs](#publishing-stubs-advanced) accordingly.

### Deployment
In production, run `ddd:optimize` during the deployment process to [optimize autoloading](#autoloading-in-production).
Expand Down Expand Up @@ -147,8 +147,8 @@ Output:
│ └─ UpdateInvoiceRequest.php
├─ src/Domain
└─ Invoicing
└─ Models
└─ Invoice.php
└─ Models
└─ Invoice.php
```

### Nested Objects
Expand Down Expand Up @@ -211,13 +211,49 @@ php artisan ddd:view-model Reporting.Customer:MonthlyInvoicesReportViewModel
```

## Customization
### Config File
This package ships with opinionated (but sensible) configuration defaults. You may customize by publishing the [config file](#config-file) and generator stubs as needed:

```bash
php artisan vendor:publish --tag="ddd-config"
php artisan vendor:publish --tag="ddd-stubs"
php artisan ddd:publish --config
php artisan ddd:publish --stubs
```

### Publishing Stubs (Advanced)
For more granular management of stubs, you may use the `ddd:stub` command:
```bash
# Publish one or more stubs interactively via prompts
php artisan ddd:stub

# Publish all stubs
php artisan ddd:stub --all

# Publish and overwrite only the files that have already been published
php artisan ddd:stub --all --existing

# Overwrite any existing files
php artisan ddd:stub --all --force

# Publish one or more stubs specified as arguments
php artisan ddd:stub model
php artisan ddd:stub model dto action
php artisan ddd:stub controller controller.plain controller.api
```
To publish multiple related stubs at once, use `*` or `.` as a wildcard ending.
```bash
php artisan ddd:stub listener.
```
Output:
```bash
Publishing /stubs/ddd/listener.typed.queued.stub
Publishing /stubs/ddd/listener.queued.stub
Publishing /stubs/ddd/listener.typed.stub
Publishing /stubs/ddd/listener.stub
```
For a quick reference of available stubs, use the `--list` option:
```bash
php artisan ddd:stub --list
```
Note that the extended commands do not publish ddd-specific stubs, and inherit the respective application-level stubs published by Laravel.

## Domain Autoloading and Discovery
Autoloading behaviour can be configured with the `ddd.autoload` configuration option. By default, domain providers, commands, policies, and factories are auto-discovered and registered.
Expand Down
70 changes: 70 additions & 0 deletions src/Commands/Concerns/HasDomainStubs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

namespace Lunarstorm\LaravelDDD\Commands\Concerns;

use Illuminate\Support\Str;
use Lunarstorm\LaravelDDD\Facades\DDD;

trait HasDomainStubs
{
protected static $usingPublishedStub = false;

protected function usingPublishedStub($usingPublishedStub = true)
{
static::$usingPublishedStub = $usingPublishedStub;

return $this;
}

protected function isUsingPublishedStub(): bool
{
return static::$usingPublishedStub;
}

protected function getStub()
{
$stub = parent::getStub();

if ($publishedStub = $this->resolvePublishedDddStub($stub)) {
$stub = $publishedStub;
}

$this->usingPublishedStub(str($stub)->startsWith(app()->basePath('stubs')));

return $stub;
}

protected function resolvePublishedDddStub($path)
{
$stubFilename = str($path)
->basename()
->ltrim('/\\')
->toString();

// Check if there is a user-published stub
if (file_exists($publishedPath = app()->basePath('stubs/ddd/'.$stubFilename))) {
return $publishedPath;
}

// Also check for legacy stub extensions
if (file_exists($legacyPublishedPath = Str::replaceLast('.stub', '.php.stub', $publishedPath))) {
return $legacyPublishedPath;
}

return null;
}

protected function resolveDddStubPath($path)
{
$path = str($path)
->basename()
->ltrim('/\\')
->toString();

if ($publishedPath = $this->resolvePublishedDddStub($path)) {
return $publishedPath;
}

return DDD::packagePath('stubs/'.$path);
}
}
32 changes: 32 additions & 0 deletions src/Commands/Concerns/InteractsWithStubs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Lunarstorm\LaravelDDD\Commands\Concerns;

trait InteractsWithStubs
{
protected function fillPlaceholder($stub, $placeholder, $value)
{
return str_replace(["{{$placeholder}}", "{{ $placeholder }}"], $value, $stub);
}

protected function preparePlaceholders(): array
{
return [];
}

protected function applyPlaceholders($stub)
{
$placeholders = $this->preparePlaceholders();

foreach ($placeholders as $placeholder => $value) {
$stub = $this->fillPlaceholder($stub, $placeholder, $value ?? '');
}

return $stub;
}

protected function buildClass($name)
{
return $this->applyPlaceholders(parent::buildClass($name));
}
}
6 changes: 5 additions & 1 deletion src/Commands/DomainActionMakeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

namespace Lunarstorm\LaravelDDD\Commands;

use Lunarstorm\LaravelDDD\Commands\Concerns\HasDomainStubs;

class DomainActionMakeCommand extends DomainGeneratorCommand
{
use HasDomainStubs;

protected $name = 'ddd:action';

/**
Expand All @@ -17,7 +21,7 @@ class DomainActionMakeCommand extends DomainGeneratorCommand

protected function getStub()
{
return $this->resolveStubPath('action.php.stub');
return $this->resolveDddStubPath('action.stub');
}

protected function preparePlaceholders(): array
Expand Down
5 changes: 4 additions & 1 deletion src/Commands/DomainBaseModelMakeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

namespace Lunarstorm\LaravelDDD\Commands;

use Lunarstorm\LaravelDDD\Commands\Concerns\HasDomainStubs;
use Symfony\Component\Console\Input\InputArgument;

class DomainBaseModelMakeCommand extends DomainGeneratorCommand
{
use HasDomainStubs;

protected $name = 'ddd:base-model';

/**
Expand All @@ -31,7 +34,7 @@ protected function getArguments()

protected function getStub()
{
return $this->resolveStubPath('base-model.php.stub');
return $this->resolveDddStubPath('base-model.stub');
}

protected function getRelativeDomainNamespace(): string
Expand Down
5 changes: 4 additions & 1 deletion src/Commands/DomainBaseViewModelMakeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

namespace Lunarstorm\LaravelDDD\Commands;

use Lunarstorm\LaravelDDD\Commands\Concerns\HasDomainStubs;
use Symfony\Component\Console\Input\InputArgument;

class DomainBaseViewModelMakeCommand extends DomainGeneratorCommand
{
use HasDomainStubs;

protected $name = 'ddd:base-view-model';

/**
Expand All @@ -31,7 +34,7 @@ protected function getArguments()

protected function getStub()
{
return $this->resolveStubPath('base-view-model.php.stub');
return $this->resolveDddStubPath('base-view-model.stub');
}

protected function getRelativeDomainNamespace(): string
Expand Down
4 changes: 3 additions & 1 deletion src/Commands/DomainCastMakeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
namespace Lunarstorm\LaravelDDD\Commands;

use Illuminate\Foundation\Console\CastMakeCommand;
use Lunarstorm\LaravelDDD\Commands\Concerns\HasDomainStubs;
use Lunarstorm\LaravelDDD\Commands\Concerns\ResolvesDomainFromInput;

class DomainCastMakeCommand extends CastMakeCommand
{
use ResolvesDomainFromInput;
use HasDomainStubs,
ResolvesDomainFromInput;

protected $name = 'ddd:cast';
}
4 changes: 3 additions & 1 deletion src/Commands/DomainChannelMakeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
namespace Lunarstorm\LaravelDDD\Commands;

use Illuminate\Foundation\Console\ChannelMakeCommand;
use Lunarstorm\LaravelDDD\Commands\Concerns\HasDomainStubs;
use Lunarstorm\LaravelDDD\Commands\Concerns\ResolvesDomainFromInput;

class DomainChannelMakeCommand extends ChannelMakeCommand
{
use ResolvesDomainFromInput;
use HasDomainStubs,
ResolvesDomainFromInput;

protected $name = 'ddd:channel';
}
4 changes: 3 additions & 1 deletion src/Commands/DomainClassMakeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
namespace Lunarstorm\LaravelDDD\Commands;

use Illuminate\Foundation\Console\ClassMakeCommand;
use Lunarstorm\LaravelDDD\Commands\Concerns\HasDomainStubs;
use Lunarstorm\LaravelDDD\Commands\Concerns\ResolvesDomainFromInput;

class DomainClassMakeCommand extends ClassMakeCommand
{
use ResolvesDomainFromInput;
use HasDomainStubs,
ResolvesDomainFromInput;

protected $name = 'ddd:class';
}
4 changes: 3 additions & 1 deletion src/Commands/DomainConsoleMakeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
namespace Lunarstorm\LaravelDDD\Commands;

use Illuminate\Foundation\Console\ConsoleMakeCommand;
use Lunarstorm\LaravelDDD\Commands\Concerns\HasDomainStubs;
use Lunarstorm\LaravelDDD\Commands\Concerns\ResolvesDomainFromInput;

class DomainConsoleMakeCommand extends ConsoleMakeCommand
{
use ResolvesDomainFromInput;
use HasDomainStubs,
ResolvesDomainFromInput;

protected $name = 'ddd:command';
}
36 changes: 36 additions & 0 deletions src/Commands/DomainControllerMakeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@

use Illuminate\Routing\Console\ControllerMakeCommand;
use Lunarstorm\LaravelDDD\Commands\Concerns\ForwardsToDomainCommands;
use Lunarstorm\LaravelDDD\Commands\Concerns\HasDomainStubs;
use Lunarstorm\LaravelDDD\Commands\Concerns\ResolvesDomainFromInput;

use function Laravel\Prompts\confirm;

class DomainControllerMakeCommand extends ControllerMakeCommand
{
use ForwardsToDomainCommands,
HasDomainStubs,
ResolvesDomainFromInput;

protected $name = 'ddd:controller';
Expand Down Expand Up @@ -79,4 +81,38 @@ protected function buildFormRequestReplacements(array $replace, $modelClass)
'{{namespacedRequests}}' => $namespacedRequests,
]);
}

protected function buildClass($name)
{
$stub = parent::buildClass($name);

if ($this->isUsingPublishedStub()) {
return $stub;
}

$replace = [];

// Todo: these were attempted tweaks to counteract failing CI tests
// on Laravel 10, and should be revisited at some point.
// $replace["use {$this->rootNamespace()}Http\Controllers\Controller;\n"] = '';
// $replace[' extends Controller'] = '';

$appRootNamespace = $this->laravel->getNamespace();
$pathToAppBaseController = parent::getPath("Http\Controllers\Controller");

$baseControllerExists = $this->files->exists($pathToAppBaseController);

if ($baseControllerExists) {
$controllerClass = class_basename($name);
$replace["\nclass {$controllerClass}\n"] = "\nuse {$appRootNamespace}Http\Controllers\Controller;\n\nclass {$controllerClass} extends Controller\n";
}

$stub = str_replace(
array_keys($replace),
array_values($replace),
$stub
);

return $this->sortImports($stub);
}
}
Loading

0 comments on commit 3c73e2d

Please sign in to comment.