Skip to content

Commit

Permalink
v1.0 (#46)
Browse files Browse the repository at this point in the history
* Drop Laravel 9 support

* Remove Laravel 9 related shims.

* Proxy-generators, WIP.

* make:enum only in laravel 11

* Use ddd:* command prefixes.

* Update command prefixes.

* Refactoring internals, WIP.

* Fix styling

* Almost all tests passing now.

* Formatting.

* Fix test.

* Change details.

* Include next branch.

* Switch to standard console prompt.

* Bump phpstan php-version to 8.2

* Skip enum tests for < laravel 11

* Update readme.

* Standardize generator class names following Laravel's conventions.

* Formatting.

* ddd:list

* Normalize path.

* Formatting

* Update wordings.

* Bump dependabot/fetch-metadata from 1.6.0 to 2.0.0

Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 1.6.0 to 2.0.0.
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](dependabot/fetch-metadata@v1.6.0...v2.0.0)

---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Prompts (#48)

* Use Laravel Prompts for domain input prompt.

* Add version matrix to readme.

* Bump dependencies.

* Address base-view-model generation issues.

* Command aliases.

* Feature: Domain autoloader (#49)

* Domain autoloading and discovery (providers, commands, policies, factories)

---------
Co-authored-by: Jasper Tey <jasper.tey@gmail.com>

* Update change details.

* ddd:upgrade command to help convert outdated 0.x config files.

* Generate factories within domain layer. (#52)

* Add upgrade notes.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: JasperTey <JasperTey@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Peter Elmered <peter@elmered.com>
  • Loading branch information
4 people authored Mar 31, 2024
1 parent 5e32899 commit de613d9
Show file tree
Hide file tree
Showing 104 changed files with 3,186 additions and 647 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/phpstan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
php-version: '8.2'
coverage: none

- name: Install composer dependencies
Expand Down
11 changes: 4 additions & 7 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
push:
branches: [main]
pull_request:
branches: [main]
branches: [main, next]

jobs:
test:
Expand All @@ -14,18 +14,15 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest]
php: [8.3, 8.2, 8.1]
laravel: [11.*, 10.*, 9.*]
laravel: [11.*, 10.25.*]
stability: [prefer-lowest, prefer-stable]
include:
- laravel: 11.*
testbench: 9.*
carbon: ^3.0
- laravel: 10.*
- laravel: 10.25.*
testbench: 8.*
carbon: ^2.63
- laravel: 9.*
testbench: 7.*
carbon: ^2.63
carbon: 2.*
exclude:
- laravel: 11.*
php: 8.1
Expand Down
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,46 @@

All notable changes to `laravel-ddd` will be documented in this file.

## [Unversioned]
### Added
- `ddd:list` to show a summary of current domains in the domain folder.
- For all generator commands, if a domain isn't specified, prompt for it with auto-completion suggestions based on the contents of the root domain folder.
- Command aliases for some generators:
- Data Transfer Object: `ddd:dto`, `ddd:data`, `ddd:data-transfer-object`, `ddd:datatransferobject`
- Value Object: `ddd:value`, `ddd:valueobject`, `ddd:value-object`
- View Model: `ddd:view-model`, `ddd:viewmodel`
- Additional generators that extend Laravel's generators and funnel the generated objects into the domain layer:
- `ddd:cast {domain}:{name}`
- `ddd:channel {domain}:{name}`
- `ddd:command {domain}:{name}`
- `ddd:enum {domain}:{name}` (Laravel 11 only)
- `ddd:event {domain}:{name}`
- `ddd:exception {domain}:{name}`
- `ddd:job {domain}:{name}`
- `ddd:listener {domain}:{name}`
- `ddd:mail {domain}:{name}`
- `ddd:notification {domain}:{name}`
- `ddd:observer {domain}:{name}`
- `ddd:policy {domain}:{name}`
- `ddd:provider {domain}:{name}`
- `ddd:resource {domain}:{name}`
- `ddd:rule {domain}:{name}`
- `ddd:scope {domain}:{name}`
- Support for autoloading and discovery of domain service providers, commands, policies, and factories.

### Changed
- (BREAKING) For applications that published the config prior to this release, config should be removed, re-published, and re-configured.
- (BREAKING) Generator commands no longer receive a domain argument. 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).
- Shorthand syntax: `ddd:action Invoicing:CreateInvoice`.
- Or simply `ddd:action CreateInvoice` to be prompted for the domain afterwards.
- Improved the reliability of generating base view models when `ddd.base_view_model` is something other than the default `Domain\Shared\ViewModels\ViewModel`.
- Domain factories are now generated inside the domain layer under the configured factory namespace `ddd.namespaces.factory` (default `Database\Factories`). Factories located in `/database/factories/<domain>/*` (v0.x) will continue to work as a fallback when attempting to resolve a domain model's factory.
- Minimum supported Laravel version is now 10.25.

### Chore
- Dropped Laravel 9 support.

## [0.10.0] - 2024-03-23
### Added
- Add `ddd.domain_path` and `ddd.domain_namespace` to config, to specify the path to the domain layer and root domain namespace more explicitly (replaces the previous `ddd.paths.domains` config).
Expand Down
233 changes: 197 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@
[![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) patterns in Laravel applications. One of the pain points when adopting DDD is the inability to use Laravel's native `make:model` artisan command to properly generate domain models, since domain models are not intended to be stored in the `App/Models/*` namespace. This package aims to fill the gaps by providing an equivalent command, `ddd:model`, plus a few more.

> :warning: **Disclaimer**: This package is subject to frequent design changes as it evolves towards a stable v1.0 release. It is currently being tested and fine tuned within Lunarstorm's client projects.
Laravel-DDD is a toolkit to support domain driven design (DDD) patterns in Laravel applications. One of the pain points when adopting DDD is the inability to use Laravel's native `make:model` artisan command to properly generate domain models, since domain models are not intended to be stored in the `App/Models/*` namespace. This package aims to fill the gaps by providing an equivalent command, `ddd:model`, plus many more.

## Installation

You can install the package via composer:

```bash
Expand All @@ -22,62 +19,163 @@ You may then initialize the package using the `ddd:install` artisan command. Thi
php artisan ddd:install
```

### Version Compatibility
Laravel | LaravelDDD
:---------------|:-----------
9.x - 10.24.x | 0.x
10.25.x | 1.x
11.x | 1.x

> This documentation is for 1.x. For 0.x usage, please refer to the [0.x README](https://github.com/lunarstorm/laravel-ddd/blob/v0.10.0/README.md).
>
### Upgrading from 0.x
Things to be aware of when upgrading from 0.x:
- If the config file was published, it should be removed, re-published, and re-configured according to the latest format. A helper command `ddd:upgrade` is available to assist with this.
- If stubs were published, they should also be re-published and updated to ensure everything is up-to-date.
- In production, `ddd:cache` should be run during the deployment process to optimize autoloading. See the [Autoloading in Production](#autoloading-in-production) section for more details.

## Usage
### Syntax
All domain generator commands use the following syntax:
```bash
# Specifying the domain as an option
php artisan ddd:{object} {name} --domain={domain}

# Specifying the domain as part of the name (short-hand syntax)
php artisan ddd:{object} {domain}:{name}

The following generator commands are currently available:
# Not specifying the domain at all, which will then prompt
# prompt for it (with auto-completion)
php artisan ddd:{object} {name}
```

## Available Commands
### Generators
The following generators are currently available, shown using short-hand syntax:
```bash
# Generate a domain model
php artisan ddd:model {domain} {name}
php artisan ddd:model Invoicing:Invoice

# Generate a domain model with factory
php artisan ddd:model {domain} {name} -f
php artisan ddd:model {domain} {name} --factory
php artisan ddd:model Invoicing:Invoice -f
php artisan ddd:model Invoicing:Invoice --factory

# Generate a domain factory
php artisan ddd:factory {domain} {name} [--model={model}]
php artisan ddd:factory Invoicing:InvoiceFactory
php artisan ddd:factory Invoicing:InvoiceFactory --model=Invoice # optionally specifying the model

# Generate a data transfer object
php artisan ddd:dto {domain} {name}
php artisan ddd:dto Invoicing:LineItemPayload

# Generates a value object
php artisan ddd:value {domain} {name}
php artisan ddd:value Shared:DollarAmount

# Generates a view model
php artisan ddd:view-model {domain} {name}
php artisan ddd:view-model Invoicing:ShowInvoiceViewModel

# Generates an action
php artisan ddd:action {domain} {name}
php artisan ddd:action Invoicing:SendInvoiceToCustomer

# Extended Commands
# These extend Laravel's respective make:* commands and places the objects into the domain layer
php artisan ddd:cast Invoicing:MoneyCast
php artisan ddd:channel Invoicing:InvoiceChannel
php artisan ddd:command Invoicing:InvoiceDeliver
php artisan ddd:enum Customer:CustomerType # Laravel 11+ only
php artisan ddd:event Invoicing:PaymentWasReceived
php artisan ddd:exception Invoicing:InvoiceNotFoundException
php artisan ddd:job Invoicing:GenerateInvoicePdf
php artisan ddd:listener Invoicing:HandlePaymentReceived
php artisan ddd:mail Invoicing:OverduePaymentReminderEmail
php artisan ddd:notification Invoicing:YourPaymentWasReceived
php artisan ddd:observer Invoicing:InvoiceObserver
php artisan ddd:policy Invoicing:InvoicePolicy
php artisan ddd:provider Invoicing:InvoiceServiceProvider
php artisan ddd:resource Invoicing:InvoiceResource
php artisan ddd:rule Invoicing:ValidPaymentMethod
php artisan ddd:scope Invoicing:ArchivedInvoicesScope
```
Generated objects will be placed in the appropriate domain namespace as specified by `ddd.namespaces.*` in the configuration file.

Examples:
### Other Commands
```bash
php artisan ddd:model Invoicing LineItem # Domain/Invoicing/Models/LineItem
php artisan ddd:model Invoicing LineItem -f # Domain/Invoicing/Models/LineItem + Database/Factories/Invoicing/LineItemFactory
php artisan ddd:factory Invoicing LineItemFactory # Database/Factories/Invoicing/LineItemFactory
php artisan ddd:dto Invoicing LinePayload # Domain/Invoicing/Data/LinePayload
php artisan ddd:value Shared Percentage # Domain/Shared/ValueObjects/Percentage
php artisan ddd:view-model Invoicing ShowInvoiceViewModel # Domain/Invoicing/ViewModels/ShowInvoiceViewModel
php artisan ddd:action Invoicing SendInvoiceToCustomer # Domain/Invoicing/Actions/SendInvoiceToCustomer
# Show a summary of current domains in the domain folder
php artisan ddd:list

# Cache domain manifests (used for autoloading)
php artisan ddd:cache

# Clear the domain cache
php artisan ddd:clear
```

Subdomains (nested domains) can be specified with dot notation:
### Subdomains (nested domains)
Subdomains can be specified with dot notation wherever a domain option is accepted.
```bash
php artisan ddd:model Invoicing.Customer CustomerInvoice # Domain/Invoicing/Customer/Models/CustomerInvoice
php artisan ddd:factory Invoicing.Customer CustomerInvoice # Database/Factories/Invoicing/Customer/CustomerInvoiceFactory
# (supported by all generator commands)
# Domain/Reporting/Internal/ViewModels/MonthlyInvoicesReportViewModel
php artisan ddd:view-model Reporting.Internal:MonthlyInvoicesReportViewModel

# Domain/Reporting/Customer/ViewModels/MonthlyInvoicesReportViewModel
php artisan ddd:view-model Reporting.Customer:MonthlyInvoicesReportViewModel

# (supported by all commands where a domain option is accepted)
```

This package ships with opinionated (but sensible) configuration defaults. If you need to customize, you may do so by publishing the config file and generator stubs as needed:
### Customization
This package ships with opinionated (but sensible) configuration defaults. You may customize by publishing the config file and generator stubs as needed:

```bash
php artisan vendor:publish --tag="ddd-config"
php artisan vendor:publish --tag="ddd-stubs"
```
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.

```php
'autoload' => [
'providers' => true,
'commands' => true,
'policies' => true,
'factories' => true,
],
```
### Service Providers
When `ddd.autoload.providers` is enabled, any class within the domain layer extending `Illuminate\Support\ServiceProvider` will be auto-registered as a service provider.

### Console Commands
When `ddd.autoload.commands` is enabled, any class within the domain layer extending `Illuminate\Console\Command` will be auto-registered as a command when running in console.

### Policies
When `ddd.autoload.policies` is enabled, the package will register a custom policy discovery callback to resolve policy names for domain models, and fallback to Laravel's default for all other cases. If your application implements its own policy discovery using `Gate::guessPolicyNamesUsing()`, you should set `ddd.autoload.policies` to `false` to ensure it is not overridden.

### Factories
When `ddd.autoload.factories` is enabled, the package will register a custom factory discovery callback to resolve factory names for domain models, and fallback to Laravel's default for all other cases. Note that this does not affect domain models using the `Lunarstorm\LaravelDDD\Factories\HasDomainFactory` trait. Where this is useful is with regular models in the domain layer that use the standard `Illuminate\Database\Eloquent\Factories\HasFactory` trait.

If your application implements its own factory discovery using `Factory::guessFactoryNamesUsing()`, you should set `ddd.autoload.factories` to `false` to ensure it is not overridden.

### Disabling Autoloading
You may disable autoloading by setting the respective autoload options to `false` in the configuration file as needed, or by commenting out the autoload configuration entirely.
```php
// 'autoload' => [
// 'providers' => true,
// 'commands' => true,
// 'policies' => true,
// 'factories' => true,
// ],
```
<a name="autoloading-in-production"></a>
## Autoloading in Production
In production, you should cache the autoload manifests using the `ddd:cache` command as part of your application's deployment process. This will speed up the auto-discovery and registration of domain providers and commands. The `ddd:clear` command may be used to clear the cache if needed.

<a name="config-file"></a>
## Configuration File
This is the content of the published config file (`ddd.php`):

```php

return [

/*
Expand Down Expand Up @@ -109,19 +207,36 @@ return [
| objects relative to the domain namespace of which the object
| belongs to.
|
| e.g., Domain/Invoicing/Models/*
| Domain/Invoicing/Data/*
| Domain/Invoicing/ViewModels/*
| Domain/Invoicing/ValueObjects/*
| Domain/Invoicing/Actions/*
| e.g., Domain\Invoicing\Models\*
| Domain\Invoicing\Data\*
| Domain\Invoicing\ViewModels\*
| Domain\Invoicing\ValueObjects\*
| Domain\Invoicing\Actions\*
|
*/
'namespaces' => [
'models' => 'Models',
'data_transfer_objects' => 'Data',
'view_models' => 'ViewModels',
'value_objects' => 'ValueObjects',
'actions' => 'Actions',
'model' => 'Models',
'data_transfer_object' => 'Data',
'view_model' => 'ViewModels',
'value_object' => 'ValueObjects',
'action' => 'Actions',
'cast' => 'Casts',
'channel' => 'Channels',
'command' => 'Commands',
'enum' => 'Enums',
'event' => 'Events',
'exception' => 'Exceptions',
'factory' => 'Database\Factories',
'job' => 'Jobs',
'listener' => 'Listeners',
'mail' => 'Mail',
'notification' => 'Notifications',
'observer' => 'Observers',
'policy' => 'Policies',
'provider' => 'Providers',
'resource' => 'Resources',
'rule' => 'Rules',
'scope' => 'Scopes',
],

/*
Expand Down Expand Up @@ -172,6 +287,52 @@ return [
|
*/
'base_action' => null,

/*
|--------------------------------------------------------------------------
| Autoloading
|--------------------------------------------------------------------------
|
| Configure whether domain providers, commands, policies, and factories
| should be auto-discovered and registered.
|
*/
'autoload' => [
/**
* When enabled, any class within the domain layer extending `Illuminate\Support\ServiceProvider`
* will be auto-registered as a service provider
*/
'providers' => true,

/**
* When enabled, any class within the domain layer extending `Illuminate\Console\Command`
* will be auto-registered as a command when running in console.
*/
'commands' => true,

/**
* When enabled, the package will register a custom policy discovery callback to resolve policy names
* for domain models, and fallback to Laravel's default for all other cases.
*/
'policies' => true,

/**
* When enabled, the package will register a custom factory discovery callback to resolve factory names
* for domain models, and fallback to Laravel's default for all other cases.
*/
'factories' => true,
],

/*
|--------------------------------------------------------------------------
| Caching
|--------------------------------------------------------------------------
|
| The folder where the domain cache files will be stored. Used for domain
| autoloading.
|
*/
'cache_directory' => 'bootstrap/cache/ddd',
];
```

Expand Down
Loading

0 comments on commit de613d9

Please sign in to comment.