Skip to content

Next version #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jan 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 0 additions & 29 deletions CHANGELOG.md

This file was deleted.

100 changes: 90 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Symfony Bundle for DDD

Various additions for [domain driven development](https://martinfowler.com/tags/domain%20driven%20design.html) inside Symfony.
This Symfony bundle augments [geekcell/php-ddd](https://github.com/geekcell/php-ddd) with framework-specific implementations to enable seamless [domain driven design](https://martinfowler.com/tags/domain%20driven%20design.html) in a familiar environment.

## Installation

Expand All @@ -10,48 +10,128 @@ To use this bundle, require it in Composer
composer require geekcell/ddd-bundle
```

## Quickstart

- [Aggregate Root](#aggregate-root)
- [Repositories](#repositories)
- [Command & Query Bus](#command--query-bus)
- [Supporting Tools](#supporting-tools)

## Aggregate Root

Extend from `AggregateRoot` to record and commit domain events. Domain events must implement the (marker) interface `DomainEvent`. Events will be dispatched via the currently configured Symfony event dispatcher.

### Example Usage

```php
use GeekCell\DDDBundle\Domain\Event\DomainEvent;
use GeekCell\DDDBundle\Domain\Model\AggregateRoot;
use GeekCell\Ddd\Contracts\Domain\Event as DomainEvent;
use GeekCell\DddBundle\Domain\AggregateRoot;

class OrderPlacedEvent implements DomainEvent
{
...
public function __construct(
private readonly Order $order,
) {
}

// Getters etc.
}

class Order extends AggregateRoot
{
public function save(): void
{
$this->record(new OrderPlacedEvent());
$this->record(new OrderPlacedEvent($this));
}

...
// ...
}

$order = new Order();
$order = new Order( /* ... */ );
$order->save();
$order->commit(); // <- Events will be dispatched
$order->commit(); // All recorded events will be dispatched and released
```

_Hint: If you want to dispatch an event directly, use `AggregateRoot::dispatch()` instead of `AggregateRoot::record()`._

If you cannot (or don't want to) extend from `AggregateRoot`, you can alternative use `DispatchableTrait` to add dispatching capabilities to any class. The former is however the recommended way.

## Repositories

_coming soon..._

## Command & Query Bus

You can use `CommandBus` and `QueryBus` as services to implement [CQRS](https://martinfowler.com/bliki/CQRS.html). Internally, both buses will use the [Symfony messenger](https://symfony.com/doc/current/messenger.html) as "backend".

## Example Usage

```php
// src/Application/Query/TopRatedBookQuery.php
use GeekCell\Ddd\Contracts\Application\Query;

class TopRatedBooksQuery implements Query
{
public function __construct(
private readonly string $category,
private readonly int $sinceDays,
private readonly int $limit = 10,
) {
}

// Getters etc.
}

// src/Application/Query/TopRatedBookQueryHandler.php
use GeekCell\Ddd\Contracts\Application\QueryHandler;

#[AsMessageHandler]
class TopRatedBookQueryHandler implements QueryHandler
{
public function __construct(
private readonly BookRepository $repository,
) {
}

public function __invoke(TopRatedBookQuery $query)
{
$books = $this->repository
->findTopRated($query->getCategory(), $query->getSinceDays())
->paginate($query->getLimit());

return $books;
}
}

// src/Infrastructure/Http/Controller/BookController.php
use GeekCell\Ddd\Contracts\Application\QueryBus;

class BookController extends AbstractController
{
public function __construct(
private readonly QueryBus $queryBus,
) {
}

#[Route('/books/top-rated')]
public function getTopRated(Request $request)
{
$query = new TopRatedBooksQuery( /* extract from request */ );
$topRatedBooks = $this->queryBus->dispatch($query);

// ...
}
}
```

## Supporting Tools

### Facades

Facades are heavily inspired by [Laravel's Facades](https://laravel.com/docs/facades) and are more or less singletons on steroids. They are basically a shortcut to services inside the DIC.

```php
use GeekCell\DDDBundle\Support\Facades\EventDispatcher;
use GeekCell\DddBundle\Support\Facades\EventDispatcher;

EventDispatcher::dispatch($someEvent);

Expand All @@ -61,7 +141,7 @@ EventDispatcher::dispatch($someEvent);
You can create your own facades by extending from `Facade` and implementing the `Facade::getFacadeAccessor()` method to return the DIC service alias.

```php
use GeekCell\DDDBundle\Support\Facades\Facade;
use GeekCell\DddBundle\Support\Facades\Facade;

class Logger extends Facade
{
Expand Down
25 changes: 15 additions & 10 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"name": "geekcell/ddd-bundle",
"description": "A bundle for pragmatic domain driven design in Symfony.",
"type": "symfony-bundle",
"version": "1.0.3",
"version": "1.1.0",
"license": "MIT",
"authors": [
{
Expand All @@ -10,28 +11,32 @@
}
],
"require": {
"symfony/http-kernel": "^6.0",
"symfony/event-dispatcher": "^6.0",
"symfony/dependency-injection": "^6.0",
"beberlei/assert": "^3.3",
"geekcell/ddd": "^1.0.0",
"symfony/config": "^6.0",
"beberlei/assert": "^3.3"
"symfony/dependency-injection": "^6.0",
"symfony/event-dispatcher": "^6.0",
"symfony/http-kernel": "^6.0",
"symfony/messenger": "^6.0",
"doctrine/orm": "^2.12",
"symfony/string": "^6.2"
},
"autoload": {
"psr-4": {
"GeekCell\\DDDBundle\\": "src"
"GeekCell\\DddBundle\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"GeekCell\\DDDBundle\\Tests\\": "tests/"
"GeekCell\\DddBundle\\Tests\\": "tests/"
}
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.13",
"mockery/mockery": "^1.5",
"phpunit/phpunit": "^9.5",
"phpstan/phpstan": "^1.9",
"friendsofphp/php-cs-fixer": "^3.13",
"phpstan/phpstan-mockery": "^1.1"
"phpstan/phpstan-mockery": "^1.1",
"phpunit/phpunit": "^9.5"
},
"scripts": {
"gc:tests": "phpunit --testdox --colors=always",
Expand Down
Loading