Skip to content

Commit 46bb33e

Browse files
committed
update readme
1 parent a457a90 commit 46bb33e

12 files changed

+176
-58
lines changed

README.md

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,36 +13,57 @@ composer require patchlevel/event-sourcing-psr-container
1313

1414
## Documentation
1515

16+
### Config Builder
17+
18+
To create a configuration array, you can use the ConfigBuilder.
19+
This offers methods to adjust the configuration.
20+
21+
```php
22+
$eventSourcingConfig = (new ConfigBuilder())
23+
->singleTable()
24+
->databaseUrl('mysql://user:secret@localhost/app')
25+
->addAggregatePath(__DIR__ . '/Aggregate')
26+
->addEventPath(__DIR__ . '/Events')
27+
->addProcessor(SendEmailProcessor::class)
28+
->addProjector(ProfileProjection::class)
29+
->build();
30+
```
31+
1632
### Default Build-In Container
1733

34+
The own PSR container implementation already integrates all necessary factories.
35+
So we only have to pass the configuration.
36+
1837
```php
1938
use Patchlevel\EventSourcing\Container\ConfigBuilder;
2039
use Patchlevel\EventSourcing\Container\DefaultContainer;
2140

22-
$config = (new ConfigBuilder())
23-
->singleTable()
24-
->databaseUrl('mysql://user:secret@localhost/app')
25-
->addAggregatePath('src/Domain/Hotel')
26-
->addEventPath('src/Domain/Hotel/Event')
27-
->addProjector(HotelProjection::class)
28-
->addProcessor(SendCheckInEmailProcessor::class)
29-
->build();
30-
3141
$container = new DefaultContainer(
32-
$config,
42+
$eventSourcingConfig,
3343
[
3444
HotelProjection::class => fn(DefaultContainer $container)
3545
=> new HotelProjection($container->connection()),
36-
SendCheckInEmailProcessor::class => fn(DefaultContainer $container)
37-
=> new SendCheckInEmailProcessor($container->get('mailer')),
46+
SendEmailProcessor::class => fn(DefaultContainer $container)
47+
=> new SendEmailProcessor($container->get('mailer')),
3848
]
3949
);
4050

51+
$container->get(SchemaDirector::class)->create();
52+
4153
$hotelRepository = $container->repository(Hotel::class);
4254
```
4355

4456
### Laminas Service Manager
4557

58+
Factories can also be used with other PSR-11 compatible libraries.
59+
Here is an example with [Laminas](https://docs.laminas.dev/laminas-servicemanager/).
60+
61+
```bash
62+
composer require laminas/laminas-servicemanager
63+
```
64+
65+
We only have to specify the factories and pass the configuration.
66+
4667
```php
4768
use Laminas\ServiceManager\ServiceManager;
4869
use Patchlevel\EventSourcing\Repository\RepositoryManager;
@@ -52,29 +73,23 @@ use Patchlevel\EventSourcingPsrContainer\Factory\ConnectionFactory;
5273
use Patchlevel\EventSourcingPsrContainer\Factory\RepositoryManagerFactory;
5374
use Patchlevel\EventSourcingPsrContainer\Factory\SchemaDirectorFactory;
5475

55-
$config = (new ConfigBuilder())
56-
->singleTable()
57-
->databaseUrl('sqlite:///:memory:')
58-
->addAggregatePath(__DIR__ . '/Aggregate')
59-
->addEventPath(__DIR__ . '/Events')
60-
->addProcessor(SendEmailProcessor::class)
61-
->addProjector(ProfileProjection::class)
62-
->build();
63-
6476
$serviceManager = new ServiceManager([
6577
'services' => [
6678
'config' => [
67-
'event_sourcing' => $config
79+
'event_sourcing' => $eventSourcingConfig
6880
],
6981
SendEmailProcessor::class => new SendEmailProcessor()
7082
],
7183
'factories' => [
7284
'event_sourcing.connection' => new ConnectionFactory(),
7385
RepositoryManager::class => new RepositoryManagerFactory(),
7486
SchemaDirector::class => new SchemaDirectorFactory(),
75-
ProfileProjection::class => static fn (ServiceManager $container) => new ProfileProjection($container->get('event_sourcing.connection')),
87+
HotelProjection::class => static fn (ServiceManager $container) => new HotelProjection($container->get('event_sourcing.connection')),
7688
],
7789
]);
7890

91+
$serviceManager->get(SchemaDirector::class)->create();
92+
7993
$repositoryManager = $serviceManager->get(RepositoryManager::class);
94+
$hotelRepository = $repositoryManager->get(Hotel::class);
8095
```

psalm.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
</projectFiles>
1717

1818
<plugins>
19-
<pluginClass class="Patchlevel\EventSourcingPsalmPlugin\Plugin"/>
2019
<pluginClass class="Psalm\PhpUnitPlugin\Plugin"/>
21-
<pluginClass class="Cspray\Phinal\Plugin"/>
2220
</plugins>
2321
</psalm>

src/ConfigBuilder.php

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,28 @@
44

55
namespace Patchlevel\EventSourcingPsrContainer;
66

7+
use Patchlevel\EventSourcingPsrContainer\Factory\AggregateRootRegistryFactory;
8+
use Patchlevel\EventSourcingPsrContainer\Factory\ConnectionFactory;
9+
use Patchlevel\EventSourcingPsrContainer\Factory\EventBusFactory;
10+
use Patchlevel\EventSourcingPsrContainer\Factory\EventSerializerFactory;
11+
use Patchlevel\EventSourcingPsrContainer\Factory\ProjectorRepositoryFactory;
12+
use Patchlevel\EventSourcingPsrContainer\Factory\StoreFactory;
13+
714
/**
15+
* @psalm-import-type Config from AggregateRootRegistryFactory as AggregateConfig
16+
* @psalm-import-type Config from ConnectionFactory as ConnectionConfig
17+
* @psalm-import-type Config from EventBusFactory as EventBusConfig
18+
* @psalm-import-type Config from EventSerializerFactory as EventConfig
19+
* @psalm-import-type Config from ProjectorRepositoryFactory as ProjectionConfig
20+
* @psalm-import-type Config from StoreFactory as StoreConfig
21+
*
822
* @psalm-type Config = array{
9-
* event_bus: ?array{type: string, service: string},
10-
* projection: array{projectionist: bool},
11-
* watch_server: array{enabled: bool, host: string},
12-
* connection: ?array{service: ?string, url: ?string},
13-
* store: array{type: string, merge_orm_schema: bool},
14-
* aggregates: list<string>,
15-
* events: list<string>,
16-
* snapshot_stores: array<string, array{type: string, service: string}>,
17-
* migration: array{path: string, namespace: string},
18-
* clock: array{freeze: ?string, service: ?string}
23+
* event_bus: EventBusConfig,
24+
* projection: ProjectionConfig,
25+
* connection: ConnectionConfig,
26+
* store: StoreConfig,
27+
* aggregate: AggregateConfig,
28+
* event: EventConfig
1929
* }
2030
*/
2131
final class ConfigBuilder
@@ -137,7 +147,9 @@ public function build(): array
137147
'event_bus' => [
138148
'listeners' => $this->processors,
139149
],
140-
'projectors' => $this->projectors,
150+
'projection' => [
151+
'projectors' => $this->projectors
152+
],
141153
];
142154
}
143155
}

src/Factory/AggregateRootRegistryFactory.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,24 @@
44

55
namespace Patchlevel\EventSourcingPsrContainer\Factory;
66

7+
use Patchlevel\EventSourcing\Aggregate\AggregateRoot;
78
use Patchlevel\EventSourcing\Metadata\AggregateRoot\AggregateRootRegistry;
89
use Patchlevel\EventSourcing\Metadata\AggregateRoot\AttributeAggregateRootRegistryFactory;
910
use Psr\Container\ContainerInterface;
1011

1112
/**
1213
* @psalm-type Config = array{
1314
* paths: list<string>,
14-
* classes: list<string>,
15+
* classes: array<string, class-string<AggregateRoot>>,
1516
* }
17+
*
18+
* @extends Factory<Config>
1619
*/
1720
final class AggregateRootRegistryFactory extends Factory
1821
{
19-
protected function createWithConfig(ContainerInterface $container): AggregateRootRegistry
22+
public function __invoke(ContainerInterface $container): AggregateRootRegistry
2023
{
21-
$config = $this->retrieveConfig($container, 'aggregate');
24+
$config = $this->sectionConfig($container);
2225

2326
$aggregateRootRegistry = new AggregateRootRegistry($config['classes']);
2427

@@ -39,4 +42,9 @@ protected function defaultConfig(): array
3942
'classes' => [],
4043
];
4144
}
45+
46+
protected function section(): string
47+
{
48+
return 'aggregate';
49+
}
4250
}

src/Factory/ConnectionFactory.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,28 @@
88
use Doctrine\DBAL\DriverManager;
99
use Psr\Container\ContainerInterface;
1010

11+
/**
12+
* @psalm-type Config = array{
13+
* url: string
14+
* }
15+
*
16+
* @extends Factory<Config>
17+
*/
1118
final class ConnectionFactory extends Factory
1219
{
1320
public const SERVICE_NAME = 'event_sourcing.connection';
1421

15-
protected function createWithConfig(ContainerInterface $container): Connection
22+
public function __invoke(ContainerInterface $container): Connection
1623
{
17-
$config = $this->retrieveConfig($container, 'connection');
24+
$config = $this->sectionConfig($container);
1825

1926
return DriverManager::getConnection([
2027
'url' => $config['url'],
2128
]);
2229
}
30+
31+
protected function section(): string
32+
{
33+
return 'connection';
34+
}
2335
}

src/Factory/EventBusFactory.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,18 @@
1313

1414
use function array_map;
1515

16+
/**
17+
* @psalm-type Config = array{
18+
* listeners: list<string>
19+
* }
20+
*
21+
* @extends Factory<Config>
22+
*/
1623
final class EventBusFactory extends Factory
1724
{
18-
protected function createWithConfig(ContainerInterface $container): EventBus
25+
public function __invoke(ContainerInterface $container): EventBus
1926
{
20-
$config = $this->retrieveConfig($container, 'event_bus');
27+
$config = $this->sectionConfig($container);
2128

2229
$listeners = array_map(static fn (string $id): Listener => $container->get($id), $config['listeners']);
2330

@@ -32,10 +39,18 @@ protected function createWithConfig(ContainerInterface $container): EventBus
3239
return new DefaultEventBus($listeners);
3340
}
3441

42+
/**
43+
* @return Config
44+
*/
3545
protected function defaultConfig(): array
3646
{
3747
return [
3848
'listeners' => [],
3949
];
4050
}
51+
52+
protected function section(): string
53+
{
54+
return 'event_bus';
55+
}
4156
}

src/Factory/EventSerializerFactory.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,34 @@
88
use Patchlevel\EventSourcing\Serializer\EventSerializer;
99
use Psr\Container\ContainerInterface;
1010

11+
/**
12+
* @psalm-type Config = array{
13+
* paths: list<string>
14+
* }
15+
*
16+
* @extends Factory<Config>
17+
*/
1118
final class EventSerializerFactory extends Factory
1219
{
13-
protected function createWithConfig(ContainerInterface $container): EventSerializer
20+
public function __invoke(ContainerInterface $container): EventSerializer
1421
{
15-
$config = $this->retrieveConfig($container, 'event');
22+
$config = $this->sectionConfig($container);
1623

1724
return DefaultEventSerializer::createFromPaths($config['paths']);
1825
}
1926

27+
/**
28+
* @return Config
29+
*/
2030
protected function defaultConfig(): array
2131
{
2232
return [
2333
'paths' => [],
2434
];
2535
}
36+
37+
protected function section(): string
38+
{
39+
return 'event';
40+
}
2641
}

src/Factory/Factory.php

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,41 @@
1010
use function array_replace_recursive;
1111
use function is_array;
1212

13+
/**
14+
* @template C as array
15+
*/
1316
abstract class Factory
1417
{
1518
final public function __construct()
1619
{
1720
}
1821

19-
public function __invoke(ContainerInterface $container): mixed
22+
abstract public function __invoke(ContainerInterface $container): mixed;
23+
24+
protected function section(): ?string
2025
{
21-
return $this->createWithConfig($container);
26+
return null;
2227
}
2328

24-
abstract protected function createWithConfig(ContainerInterface $container): mixed;
25-
2629
/**
27-
* @return array<string, mixed>
30+
* @return C
2831
*/
2932
protected function defaultConfig(): array
3033
{
3134
return [];
3235
}
3336

34-
protected function retrieveConfig(ContainerInterface $container, string $section): array
37+
/**
38+
* @return C
39+
*/
40+
protected function sectionConfig(ContainerInterface $container): array
3541
{
42+
$section = $this->section();
43+
44+
if ($section === null) {
45+
return $this->defaultConfig();
46+
}
47+
3648
$applicationConfig = $container->has('config') ? $container->get('config') : [];
3749

3850
if (!is_array($applicationConfig)) {

src/Factory/ProjectorRepositoryFactory.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,26 @@
1111

1212
use function array_map;
1313

14+
/**
15+
* @psalm-type Config = array{
16+
* projectors: list<string>
17+
* }
18+
*
19+
* @extends Factory<Config>
20+
*/
1421
final class ProjectorRepositoryFactory extends Factory
1522
{
16-
protected function createWithConfig(ContainerInterface $container): ProjectorRepository
23+
public function __invoke(ContainerInterface $container): ProjectorRepository
1724
{
18-
$config = $this->retrieveConfig($container, 'projectors');
25+
$config = $this->sectionConfig($container);
1926

2027
return new InMemoryProjectorRepository(
21-
array_map(static fn (string $id): Projector => $container->get($id), $config)
28+
array_map(static fn (string $id): Projector => $container->get($id), $config['projectors'])
2229
);
2330
}
31+
32+
protected function section(): string
33+
{
34+
return 'projection';
35+
}
2436
}

0 commit comments

Comments
 (0)