Skip to content

Commit

Permalink
Update readme and fix custom resolver logic.
Browse files Browse the repository at this point in the history
  • Loading branch information
jaspertey committed Nov 13, 2024
1 parent bb20d63 commit 5bb5de6
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 31 deletions.
121 changes: 98 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/lunarstorm/laravel-ddd/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/lunarstorm/laravel-ddd/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain)
[![Total Downloads](https://img.shields.io/packagist/dt/lunarstorm/laravel-ddd.svg?style=flat-square)](https://packagist.org/packages/lunarstorm/laravel-ddd)

Laravel-DDD is a toolkit to support domain driven design (DDD) in Laravel applications. One of the pain points when adopting DDD is the inability to use Laravel's native `make` commands to generate domain objects since they are typically stored outside the `App\*` namespace. This package aims to fill the gaps by providing equivalent commands such as `ddd:model`, `ddd:dto`, `ddd:view-model` and many more.
Laravel-DDD is a toolkit to support domain driven design (DDD) in Laravel applications. One of the pain points when adopting DDD is the inability to use Laravel's native `make` commands to generate objects outside the `App\*` namespace. This package aims to fill the gaps by providing equivalent commands such as `ddd:model`, `ddd:dto`, `ddd:view-model` and many more.

## Installation
You can install the package via composer:
Expand All @@ -24,7 +24,7 @@ The following additional packages are suggested (but not required) while working
- Data Transfer Objects: [spatie/laravel-data](https://github.com/spatie/laravel-data)
- Actions: [lorisleiva/laravel-actions](https://github.com/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](#publishing-stubs-advanced) 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 [publish and customize the stubs](#customizing-stubs) accordingly.

### Deployment
In production, run `ddd:optimize` during the deployment process to [optimize autoloading](#autoloading-in-production).
Expand All @@ -40,7 +40,7 @@ Since Laravel 11.27.1, `php artisan optimize` automatically invokes `ddd:optimiz
10.25.x | 1.x |
11.x | 1.x |

See **[UPGRADING](UPGRADING.md)** for more details about upgrading from 0.x.
See **[UPGRADING](UPGRADING.md)** for more details about upgrading from an older versions.

<a name="usage"></a>

Expand Down Expand Up @@ -97,6 +97,36 @@ The following generators are currently available:

Generated objects will be placed in the appropriate domain namespace as specified by `ddd.namespaces.*` in the [config file](#config-file).

### Config Utility (Since 1.2)
A configuration utility was introduced in 1.2 to help manage the package's configuration over time.
```bash
php artisan ddd:config
```
Output:
```
┌ Laravel-DDD Config Utility ──────────────────────────────────┐
│ › ● Run the configuration wizard │
│ ○ Update and merge ddd.php with latest package version │
│ ○ Detect domain namespace from composer.json │
│ ○ Sync composer.json from ddd.php │
│ ○ Exit │
└──────────────────────────────────────────────────────────────┘
```
These config tasks are also invokeable directly using arguments:
```bash
# Run the configuration wizard
php artisan ddd:config wizard

# Update and merge ddd.php with latest package version
php artisan ddd:config update

# Detect domain namespace from composer.json
php artisan ddd:config detect

# Sync composer.json from ddd.php
php artisan ddd:config composer
```

### Other Commands
```bash
# Show a summary of current domains in the domain folder
Expand Down Expand Up @@ -230,34 +260,83 @@ php artisan ddd:view-model Reporting.Customer:MonthlyInvoicesReportViewModel
# (supported by all commands where a domain option is accepted)
```

## 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:
### Custom Object Resolution
If you require advanced customization of generated object naming conventions, you may register a custom resolver using `DDD::resolveObjectSchemaUsing()` in your AppServiceProvider's boot method:
```php
use Lunarstorm\LaravelDDD\Facades\DDD;
use Lunarstorm\LaravelDDD\ValueObjects\CommandContext;
use Lunarstorm\LaravelDDD\ValueObjects\ObjectSchema;

DDD::resolveObjectSchemaUsing(function (string $domainName, string $nameInput, string $type, CommandContext $command): ?ObjectSchema {
if ($type === 'controller' && $command->option('api')) {
return new ObjectSchema(
name: $name = str($nameInput)->replaceEnd('Controller', '')->finish('ApiController')->toString(),
namespace: "App\\Api\\Controllers\\{$domainName}",
fullyQualifiedName: "App\\Api\\Controllers\\{$domainName}\\{$name}",
path: "src/App/Api/Controllers/{$domainName}/{$name}.php",
);
}

// Return null to fall back to the default
return null;
});
```
The example above will result in the following:
```bash
php artisan ddd:publish --config
php artisan ddd:publish --stubs
php artisan ddd:controller Invoicing:PaymentController --api
# Controller [src/App/Api/Controllers/Invoicing/PaymentApiController.php] created successfully.
```

### Publishing Stubs (Advanced)
For more granular management of stubs, you may use the `ddd:stub` command:
<a name="customizing-stubs"></a>

## Customizing Stubs
This package ships with a few ddd-specific stubs, while the rest are pulled from the framework. For a quick reference of available stubs and their source, you may use the `ddd:stub --list` command:
```bash
# Publish one or more stubs interactively via prompts
php artisan ddd:stub
php artisan ddd:stub --list
```

### Stub Priority
When generating objects using `ddd:*`, stubs are prioritized as follows:
- Try `stubs/ddd/*.stub` (customized for `ddd:*` only)
- Try `stubs/*.stub` (shared by both `make:*` and `ddd:*`)
- Fallback to the package or framework default

### Publishing Stubs
To publish stubs interactively, you may use the `ddd:stub` command:
```bash
php artisan ddd:stub
```
```
┌ What do you want to do? ─────────────────────────────────────┐
│ › ● Choose stubs to publish │
│ ○ Publish all stubs │
└──────────────────────────────────────────────────────────────┘
┌ Which stub should be published? ─────────────────────────────┐
│ policy │
├──────────────────────────────────────────────────────────────┤
│ › ◼ policy.plain.stub │
│ ◻ policy.stub │
└────────────────────────────────────────────────── 1 selected ┘
Use the space bar to select options.
```
You may also use shortcuts to skip the interactive steps:
```bash
# 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
# Publish one or more stubs specified as arguments (see ddd:stub --list)
php artisan ddd:stub model
php artisan ddd:stub model dto action
php artisan ddd:stub controller controller.plain controller.api

# Options:

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

# Overwrite any existing files
php artisan ddd:stub ... --force
```
To publish multiple related stubs at once, use `*` or `.` as a wildcard ending.
```bash
Expand All @@ -270,10 +349,6 @@ 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
```

## 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
19 changes: 17 additions & 2 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
# Upgrading

## From 0.x to 1.x

## From 1.1.x to 1.2.x
### Breaking
- Stubs are now published `to base_path('stubs/ddd')` instead of `resource_path('stubs/ddd')`. In other words, they are now co-located alongside the framework's published stubs, within a ddd subfolder.
- Published stubs now use `.stub` extension instead of `.php.stub` (following Laravel's convention).
- If you haven't previously published stubs in your installation, this change will not affect you.

### Update Config
- Support for Application Layer and Custom Layers was added, introducing changes to the config file.
- Run `php artisan ddd:config update` to rebuild your application's published `ddd.php` config to align with the package's latest copy.
- The update utility will attempt to respect your existing customizations, but you should still review and verify manually.

### Publishing Stubs
- Old way (removed): `php artisan vendor:publish --tag="ddd-stubs"`
- New way, using stub utility command: `php artisan ddd:stub` (see [Customizing Stubs](README.md#customizing-stubs) in README for more details).

## From 0.x to 1.x
- Minimum required Laravel version is 10.25.
- The ddd generator [command syntax](README.md#usage) in 1.x. Generator commands no longer receive a domain argument. For example, instead of `ddd:action Invoicing CreateInvoice`, one of the following would be used:
- Using the --domain option: ddd:action CreateInvoice --domain=Invoicing (this takes precedence).
Expand Down
5 changes: 5 additions & 0 deletions src/Commands/Concerns/ResolvesDomainFromInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ protected function getPath($name)
: parent::getPath($name);
}

protected function qualifyClass($name)
{
return $this->blueprint->qualifyClass($name);
}

protected function beforeHandle()
{
$nameInput = $this->getNameInput();
Expand Down
5 changes: 0 additions & 5 deletions src/Commands/DomainControllerMakeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,6 @@ protected function buildClass($name)

$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");

Expand Down
5 changes: 5 additions & 0 deletions src/Support/GeneratorBlueprint.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ public function getPath($name)
return Path::normalize(app()->basePath($this->schema->path));
}

public function qualifyClass($name)
{
return $this->schema->fullyQualifiedName;
}

public function getFactoryFor(string $name)
{
return $this->domain->factory($name);
Expand Down
5 changes: 4 additions & 1 deletion tests/Support/ResolveObjectSchemaUsingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,8 @@
$expectedPath = base_path('src/App/Api/Controllers/Invoicing/PaymentApiController.php');

expect(file_get_contents($expectedPath))
->toContain("namespace App\Api\Controllers\Invoicing;");
->toContain(...[
"namespace App\Api\Controllers\Invoicing;",
'class PaymentApiController',
]);
});

0 comments on commit 5bb5de6

Please sign in to comment.