Skip to content

Commit 71c81b7

Browse files
dgafkagitbook-bot
authored andcommitted
GITBOOK-880: No subject
1 parent fccd24c commit 71c81b7

File tree

5 files changed

+186
-145
lines changed

5 files changed

+186
-145
lines changed

SUMMARY.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@
3737
* [Advanced Aggregate creation](modelling/command-handling/state-stored-aggregate/advanced-aggregate-creation.md)
3838
* [Repositories Introduction](modelling/command-handling/repository.md)
3939
* [Business Interface](modelling/command-handling/business-interface/README.md)
40-
* [Repository](modelling/command-handling/business-interface/repository.md)
41-
* [Working with Database](modelling/command-handling/business-interface/working-with-database/README.md)
40+
* [Introduction](modelling/command-handling/business-interface/introduction.md)
41+
* [Business Repository](modelling/command-handling/business-interface/repository.md)
42+
* [Database Business Interface](modelling/command-handling/business-interface/working-with-database/README.md)
4243
* [Converting Parameters](modelling/command-handling/business-interface/working-with-database/converting-parameters.md)
4344
* [Converting Results](modelling/command-handling/business-interface/working-with-database/converting-results.md)
4445
* [Saga Introduction](modelling/command-handling/saga.md)

modelling/asynchronous-handling/asynchronous-message-handlers.md

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ There are multiple different implementation which we can use:
5656
At this moment following modules with pollable channels are available:
5757

5858
* [AMQP Support (RabbitMQ)](../../modules/amqp-support-rabbitmq.md#message-channel)
59+
* [Kafka Support](../../modules/kafka-support.md)
5960
* [DBAL Support](../../modules/dbal-support.md#message-channel)
6061
* [SQS Support](../../modules/amazon-sqs-support.md)
6162
* [Redis Support](../../modules/redis-support.md)
Original file line numberDiff line numberDiff line change
@@ -1,136 +1,2 @@
11
# Business Interface
22

3-
Be sure to read [CQRS Introduction](../) before diving in this chapter.
4-
5-
## Execute your Business Actions via Interface
6-
7-
Business Interface aims is to reduce boierplate code and make your domain actions explicit. \
8-
We provide an Interface with methods and Ecotone delivers implementation. This way we can get rid of delegation level code and focus on the things we want to achieve. \
9-
For example, if we don't want to trigger action via Command/Query Bus, we can do it directly using our business interface and skip all the Middlewares that would normally trigger during Bus execution.
10-
11-
There are different types of Business Interfaces and in this chapter we will discuss the basics and in another two, we will dive into abstracting away [Repositories](repository.md) and [Database Layers](working-with-database/).
12-
13-
## Command Interface
14-
15-
Let's take as an example creating new Ticket
16-
17-
```php
18-
class TicketService
19-
{
20-
#[CommandHandler("ticket.create")]
21-
public function createTicket(CreateTicketCommand $command) : void
22-
{
23-
// handle create ticket command
24-
}
25-
}
26-
```
27-
28-
We may define interface, that will call this Command Handler whenever will be executed.
29-
30-
```php
31-
interface TicketApi
32-
{
33-
#[BusinessMethod('ticket.create')]
34-
public function create(CreateTicketCommand $command): void;
35-
}
36-
```
37-
38-
This way we don't need to use Command Bus and can bypass all Bus related interceptors.
39-
40-
The attribute `#[BusinessMethod]` tells Ecotone that given `interface` is meant to be used as entrypoint to Messaging and which Message Handler it should send the Message to. \
41-
Ecotone will provide implementation of this interface directly in your Dependency Container.
42-
43-
{% hint style="success" %}
44-
We already used Business Interfaces without being aware, `Command`, `Query` and `Event` Buses are Business Interfaces.\
45-
From lower level API `Business Method` is actually a [Message Gateway](../../../messaging/messaging-concepts/messaging-gateway.md).
46-
{% endhint %}
47-
48-
## Aggregate Command Interface
49-
50-
We may also execute given Aggregate directly using Business Interface.
51-
52-
```php
53-
#[Aggregate]
54-
class Ticket
55-
{
56-
#[Identifier]
57-
private Uuid $ticketId;
58-
private bool $isClosed;
59-
60-
#[CommandHandler("ticket.close")]
61-
public function close(): void
62-
{
63-
$this->isClosed = true;
64-
}
65-
}
66-
```
67-
68-
Then we define interface:
69-
70-
```php
71-
interface TicketApi
72-
{
73-
#[BusinessMethod('ticket.close')]
74-
public function create(#[Identifier] Uuid $ticketId): void;
75-
}
76-
```
77-
78-
{% hint style="success" %}
79-
We may of course pass Command class, if we need to pass data to our Aggregate's Command Handler.
80-
{% endhint %}
81-
82-
## Query Interface
83-
84-
Defining Query Interface works exactly the same as Command Interface and we may also use it with Aggregates.
85-
86-
```php
87-
class TicketService
88-
{
89-
#[QueryHandler("ticket.get_by_id")]
90-
public function getTicket(GetTicketById $query) : array
91-
{
92-
//return ticket
93-
}
94-
}
95-
```
96-
97-
Then we may call this Query Handler using Interface
98-
99-
```php
100-
interface TicketApi
101-
{
102-
#[BusinessMethod("ticket.get_by_id")]
103-
public function getTicket(GetTicketById $query): array;
104-
}
105-
```
106-
107-
## Query Interface Conversion
108-
109-
If we have registered [Converter](../../../messaging/conversion/) then we let`Ecotone` convert the result of your `Query Handler` to specific format.  
110-
111-
```php
112-
class TicketService
113-
{
114-
#[QueryHandler("ticket.get_by_id")]
115-
public function getTicket(GetTicketById $query) : array
116-
{
117-
//return ticket
118-
}
119-
}
120-
```
121-
122-
Then we may call this Query Handler using Interface
123-
124-
```php
125-
interface TicketApi
126-
{
127-
#[BusinessMethod("ticket.get_by_id")]
128-
public function getTicket(GetTicketById $query): TicketDTO;
129-
}
130-
```
131-
132-
Ecotone will use defined Converter to conver `array` to `TicketDTO`.
133-
134-
{% hint style="success" %}
135-
Such conversion are useful in order to work with objects and to avoid writing transformation code in our business code.
136-
{% endhint %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# Introduction
2+
3+
Be sure to read [CQRS Introduction](../) before diving in this chapter.
4+
5+
## Execute your Business Actions via Interface
6+
7+
Business Interface aims to reduce boierplate code and make your domain actions explicit. \
8+
In Application we describe an Interface, which executes Business methods. Ecotone will deliver implementation for this interface, which will bind the interface with specific actions. \
9+
This way we can get rid of delegation level code and focus on the things we want to achieve. \
10+
\
11+
For example, if we don't want to trigger action via Command/Query Bus, we can do it directly using our business interface and skip all the Middlewares that would normally trigger during Bus execution.\
12+
There are different types of Business Interfaces and in this chapter we will discuss the basics of build our own Business Interface, in next sections we will dive into specific types of business interfaces: [Repositories](repository.md) and [Database Layers](working-with-database/).
13+
14+
## Command Interface
15+
16+
Let's take as an example creating new Ticket
17+
18+
```php
19+
class TicketService
20+
{
21+
#[CommandHandler("ticket.create")]
22+
public function createTicket(CreateTicketCommand $command) : void
23+
{
24+
// handle create ticket command
25+
}
26+
}
27+
```
28+
29+
We may define interface, that will call this Command Handler whenever will be executed.
30+
31+
```php
32+
interface TicketApi
33+
{
34+
#[BusinessMethod('ticket.create')]
35+
public function create(CreateTicketCommand $command): void;
36+
}
37+
```
38+
39+
This way we don't need to use Command Bus and we can bypass all Bus related interceptors.
40+
41+
The attribute **#\[BusinessMethod]** tells Ecotone that given **Interface** is meant to be used as entrypoint to Messaging and which Message Handler it should send the Message to. \
42+
Ecotone will provide implementation of this interface directly in our Dependency Container.
43+
44+
{% hint style="success" %}
45+
From lower level API `Business Method` is actually a [Message Gateway](../../../messaging/messaging-concepts/messaging-gateway.md).
46+
{% endhint %}
47+
48+
## Aggregate Command Interface
49+
50+
We may also execute given Aggregate directly using Business Interface.
51+
52+
```php
53+
#[Aggregate]
54+
class Ticket
55+
{
56+
#[Identifier]
57+
private Uuid $ticketId;
58+
private bool $isClosed;
59+
60+
#[CommandHandler("ticket.close")]
61+
public function close(): void
62+
{
63+
$this->isClosed = true;
64+
}
65+
}
66+
```
67+
68+
Then we define interface:
69+
70+
```php
71+
interface TicketApi
72+
{
73+
#[BusinessMethod('ticket.close')]
74+
public function create(#[Identifier] Uuid $ticketId): void;
75+
}
76+
```
77+
78+
{% hint style="success" %}
79+
We may of course pass Command class if we need to pass more data to our Aggregate's Command Handler.
80+
{% endhint %}
81+
82+
## Query Interface
83+
84+
Defining Query Interface works exactly the same as Command Interface and we may also use it with Aggregates.
85+
86+
```php
87+
class TicketService
88+
{
89+
#[QueryHandler("ticket.get_by_id")]
90+
public function getTicket(GetTicketById $query) : array
91+
{
92+
//return ticket
93+
}
94+
}
95+
```
96+
97+
Then we may call this Query Handler using Interface
98+
99+
```php
100+
interface TicketApi
101+
{
102+
#[BusinessMethod("ticket.get_by_id")]
103+
public function getTicket(GetTicketById $query): array;
104+
}
105+
```
106+
107+
## Result Conversion
108+
109+
If we have registered [Converter](../../../messaging/conversion/) then we let Ecotone do conversion to **Message Handler** specific format:
110+
111+
```php
112+
class TicketService
113+
{
114+
#[QueryHandler("ticket.get_by_id")]
115+
public function getTicket(GetTicketById $query) : array
116+
{
117+
//return ticket as array
118+
}
119+
}
120+
```
121+
122+
Then we may call this Query Handler using Interface
123+
124+
```php
125+
interface TicketApi
126+
{
127+
// return ticket as Class
128+
#[BusinessMethod("ticket.get_by_id")]
129+
public function getTicket(GetTicketById $query): TicketDTO;
130+
}
131+
```
132+
133+
Ecotone will use defined Converter to convert **`array`** to **`TicketDTO`**.
134+
135+
{% hint style="success" %}
136+
Such conversion are useful in order to work with objects and to avoid writing transformation code in our business code. We can build generic queries, and transform them to different classes using different business methods.
137+
{% endhint %}
138+
139+
## Payload Conversion
140+
141+
If we have registered [Converter](../../../messaging/conversion/) then we let Ecotone do conversion to **Message Handler** specific format:
142+
143+
```php
144+
class TicketService
145+
{
146+
#[CommandHandler("ticket.create")]
147+
public function getTicket(CreateTicket $command) : void
148+
{
149+
150+
}
151+
}
152+
```
153+
154+
Then we may call this Query Handler using Interface
155+
156+
```php
157+
interface TicketApi
158+
{
159+
#[BusinessMethod("ticket.create")]
160+
public function getTicket(array $query): void;
161+
}
162+
```
163+
164+
Ecotone will use defined Converter to convert **array** to **CreateTicket** command class.
165+
166+
{% hint style="success" %}
167+
This type of conversion is especially useful, when we receive data from external source and we simply want to push it to given Message Handler. We avoid doing transformations ourselves, as we simply push what we receive as array.
168+
{% endhint %}

modelling/command-handling/business-interface/repository.md

+14-9
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
# Repository
1+
# Business Repository
22

33
## Business Repository Interface
44

5-
Special type of `Business Interface` is `Repository`. \
6-
If you want to fetch or store Aggregate register under [Ecotone's Repository](../repository.md) you may use `#[Repository]` attribute.  
5+
Special type of **Business Interface** is **Repository**. \
6+
This Interface allows us to simply load and store our Aggregates directly. In situations when we call Command directly in our Aggregates we won't be in need to use it. However for some specific cases, where we need to load Aggregate and store it outside of Aggregate's Command Handler, this business interface becomes useful. 
77

8-
### For State-Stored Aggregate
8+
{% hint style="info" %}
9+
To make use of this Business Interface, we need our [Aggregate Repository](../repository.md) being registered.
10+
{% endhint %}
11+
12+
## Business Repository
913

1014
```php
1115
interface OrderRepository
@@ -21,13 +25,16 @@ interface OrderRepository
2125
}
2226
```
2327

24-
Ecotone will read type hint to understand, which Aggregate you would like to fetch or save.
28+
Ecotone will read type hint to understand which Aggregate you would like to fetch or save.
2529

2630
{% hint style="info" %}
27-
Implementation will be delivered by Framework. All you need to do is to define the interface and it will available in your Dependency Container
31+
Implementation will be delivered by Ecotone. All you need to do is to define the interface and it will available in your Dependency Container
2832
{% endhint %}
2933

30-
### For Event Sourced Aggregate
34+
## Pure Event Sourced Repository <a href="#for-event-sourced-aggregate" id="for-event-sourced-aggregate"></a>
35+
36+
When using Pure Event Sourced Aggregate, instance of Aggregate does not hold recorded Events. Therefore passing aggregate instance would not contain any information about recorded events. \
37+
For Pure Event Sourced Aggregates, we can use direct event passing to the repository:
3138

3239
```php
3340
interface OrderRepository
@@ -43,5 +50,3 @@ interface OrderRepository
4350
public function save(string $aggregateId, int $currentVersion, array $events): void;
4451
}
4552
```
46-
47-
The difference is in `save` method, you need to provide `aggregate id, current aggregate's version and array of events` you would like to store.

0 commit comments

Comments
 (0)