Skip to content

Commit 56d4913

Browse files
committed
:neckbeard: Let's glu all the stuff
1 parent c851714 commit 56d4913

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+414
-152
lines changed

.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ before_script:
77
- composer install --prefer-dist --optimize-autoloader
88

99
script:
10+
- bin/console server:run &> /dev/null &
1011
- vendor/bin/behat -f progress
1112
- vendor/bin/phpspec run --format=dot

app/AppKernel.php

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Symfony\Component\HttpKernel\Kernel;
66
use Symfony\Component\Routing\RouteCollectionBuilder;
77
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
8+
use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
89

910
class AppKernel extends Kernel
1011
{
@@ -33,6 +34,13 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load
3334
{
3435
$loader->load(__DIR__.'/services/');
3536
$loader->load(__DIR__.'/config/config.yml');
37+
$c->addCompilerPass(
38+
new RegisterListenersPass(
39+
'event_dispatcher.parked_life',
40+
'event_listener.parked_life',
41+
'event_subscriber.parked_life'
42+
)
43+
);
3644
}
3745

3846
public function getRootDir()

app/config/config.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
parameters:
2-
exception_http_code_map: []
2+
exception_http_code_map:
3+
Shouze\ParkedLife\App\Exception\NotFoundResource: 404
34
show_exception_token: t0kt0k
45

56
framework:

app/config/routing.yml

+12
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,15 @@ register_vehicle:
33
defaults:
44
_controller: vehicle_controller.ui.parked_life:registerVehicle
55
methods: [POST]
6+
7+
park_vehicle:
8+
path: /users/{userId}/vehicles/location
9+
defaults:
10+
_controller: vehicle_controller.ui.parked_life:parkVehicle
11+
methods: [POST]
12+
13+
list_vehicles:
14+
path: /users/{userId}/vehicles
15+
defaults:
16+
_controller: vehicle_controller.ui.parked_life:listVehicles
17+
methods: [GET]

app/services/adapters.xml

+22-8
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,29 @@
55
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
66

77
<services>
8+
<service id="projector.adapters.parked_life" class="Shouze\ParkedLife\Adapters\JsonProjector">
9+
<argument>%kernel.root_dir%/../var/eventstore</argument>
10+
<argument type="service" id="serializer.parked_life" />
11+
</service>
812
<service id="event_store_vehicle_fleet_repository.adapters.parked_life" class="Shouze\ParkedLife\Adapters\EventStoreVehicleFleetRepository">
913
<argument type="service" id="event_store.adapters.parked_life" />
1014
</service>
1115
<service id="event_store.adapters.parked_life" class="Shouze\ParkedLife\Adapters\FilesystemEventStore">
1216
<argument>%kernel.root_dir%/../var/eventstore</argument>
13-
<argument type="service">
14-
<service class="Shouze\ParkedLife\EventSourcing\EventSerializer">
15-
<argument type="service">
16-
<service class="Shouze\ParkedLife\Domain\EventMapping" />
17-
</argument>
18-
<argument type="service" id="serializer.parked_life" />
19-
</service>
20-
</argument>
17+
<argument type="service" id="event_serializer.parked_life" />
2118
<argument type="service">
2219
<service class="Shouze\ParkedLife\Ports\FileHelper" />
2320
</argument>
21+
<argument type="service" id="symfony_event_bus.parked_life" />
2422
</service>
2523

24+
<service id="event_serializer.parked_life" class="Shouze\ParkedLife\EventSourcing\EventSerializer" public="false">
25+
<argument type="service">
26+
<service class="Shouze\ParkedLife\Domain\EventMapping" />
27+
</argument>
28+
<argument type="service" id="serializer.parked_life" />
29+
</service>
30+
2631
<service id="serializer.parked_life" class="Symfony\Component\Serializer\Serializer" public="false">
2732
<argument type="collection">
2833
<argument type="service">
@@ -40,5 +45,14 @@
4045
</argument>
4146
</argument>
4247
</service>
48+
49+
<service id="symfony_event_bus.parked_life" class="Shouze\ParkedLife\Adapters\SymfonyEventBus">
50+
<argument type="service" id="event_dispatcher.parked_life" />
51+
<argument type="service" id="event_serializer.parked_life" />
52+
</service>
53+
54+
<service id="event_dispatcher.parked_life" class="Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher">
55+
<argument type="service" id="service_container" />
56+
</service>
4357
</services>
4458
</container>

app/services/app.xml

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
<service id="vehicle_service.app.parked_life" class="Shouze\ParkedLife\App\VehicleService">
99
<argument type="service" id="event_store_vehicle_fleet_repository.adapters.parked_life" />
1010
<tag name="tactician.handler" command="Shouze\ParkedLife\App\Command\RegisterVehicle" />
11+
<tag name="tactician.handler" command="Shouze\ParkedLife\App\Command\ParkVehicle" />
12+
</service>
13+
14+
<service id="vehicle_query_service.app.parked_life" class="Shouze\ParkedLife\App\VehicleQueryService">
15+
<argument type="service" id="projector.adapters.parked_life" />
1116
</service>
1217

1318
<service id="command_inflector.parked_life" class="Shouze\ParkedLife\Ports\CommandClassAsMethodInflector" public="false" />

app/services/projections.xml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
6+
7+
<services>
8+
<service id="vehicle_fleet_projector.projections.parked_life" class="Shouze\ParkedLife\Domain\ReadModel\VehicleFleetProjector">
9+
<argument type="service" id="projector.adapters.parked_life" />
10+
<tag name="event_listener.parked_life" event="vehicle_was_registered.fleet.parkedlife" method="projectVehicleWasRegistred" />
11+
<tag name="event_listener.parked_life" event="vehicle_was_parked.fleet.parkedlife" method="projectVehicleWasParked" />
12+
</service>
13+
</services>
14+
</container>

app/services/ui.xml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<services>
88
<service id="vehicle_controller.ui.parked_life" class="Shouze\ParkedLife\Ui\Controller\VehicleController">
99
<argument type="service" id="tactician.commandbus" />
10+
<argument type="service" id="vehicle_query_service.app.parked_life" />
1011
</service>
1112

1213
<service id="json_body_listener.ui" class="Rezzza\SymfonyRestApiJson\JsonBodyListener">

behat.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ default:
77
web:
88
filters: { tags: "critical,ui" }
99
contexts:
10-
- WebContext
10+
- WebContext:
11+
eventStore: "@event_store.adapters.parked_life"
1112
- Rezzza\RestApiBehatExtension\RestApiContext
1213
- Rezzza\RestApiBehatExtension\Json\JsonContext
1314

@@ -16,3 +17,4 @@ default:
1617
rest:
1718
base_url: http://localhost:8000/
1819
store_response: true
20+
Behat\Symfony2Extension: ~

features/bootstrap/DomainContext.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class DomainContext implements Context
2929
*/
3030
public function __construct()
3131
{
32-
$this->userId = Domain\UserId::fromString(ShortUuid::uuid4());
32+
$this->userId = ShortUuid::uuid4();
3333
$this->asserter = new asserter\generator;
3434
}
3535

@@ -91,7 +91,7 @@ public function theKnownLocationOfMyVehicleShouldBe($platenumber, Domain\Locatio
9191
private function reconstituteVehicleFleetFromHistory()
9292
{
9393
if (count($this->pastChanges) <= 0) {
94-
return Domain\VehicleFleet::ofUser(new Domain\UserId($this->userId));
94+
return Domain\VehicleFleet::ofUser($this->userId);
9595
}
9696

9797
return Domain\VehicleFleet::reconstituteFromHistory(EventSourcing\AggregateHistory::fromEvents($this->pastChanges));

features/bootstrap/WebContext.php

+52-29
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use Behat\Behat\Tester\Exception\PendingException;
44
use Behat\Behat\Context\Context;
55
use Behat\Gherkin\Node\PyStringNode;
6+
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
67
use Behat\Gherkin\Node\TableNode;
78
use PascalDeVink\ShortUuid\ShortUuid;
89
use Rezzza\RestApiBehatExtension\Rest\RestApiBrowser;
@@ -20,41 +21,45 @@ class WebContext implements Context
2021

2122
private $restApiBrowser;
2223

23-
public function __construct(RestApiBrowser $restApiBrowser)
24+
private $jsonContext;
25+
26+
public function __construct(EventSourcing\EventStore $eventStore, RestApiBrowser $restApiBrowser)
2427
{
25-
$serializer = new EventSourcing\EventSerializer(
26-
new Domain\EventMapping,
27-
new Symfony\Component\Serializer\Serializer(
28-
[
29-
new Symfony\Component\Serializer\Normalizer\PropertyNormalizer(
30-
null,
31-
new Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter
32-
)
33-
],
34-
[ new Symfony\Component\Serializer\Encoder\JsonEncoder ]
35-
)
36-
);
37-
$this->eventStore = new Adapters\FilesystemEventStore(
38-
__DIR__.'/../../var/eventstore',
39-
$serializer,
40-
new Ports\FileHelper
41-
);
28+
$this->eventStore = $eventStore;
4229
$this->restApiBrowser = $restApiBrowser;
4330
$this->restApiBrowser->setRequestHeader('Content-Type', 'application/json');
4431
$this->restApiBrowser->setRequestHeader('X-Show-Exception-Token', 't0kt0k');
4532
$this->userId = ShortUuid::uuid4();
4633
}
4734

35+
/**
36+
* @BeforeScenario
37+
*/
38+
public function gatherContexts(BeforeScenarioScope $scope)
39+
{
40+
$environment = $scope->getEnvironment();
41+
42+
$this->jsonContext = $environment->getContext('Rezzza\RestApiBehatExtension\Json\JsonContext');
43+
}
44+
45+
/**
46+
* @Transform :location
47+
*/
48+
public function castLocation($location)
49+
{
50+
return Domain\Location::fromString($location);
51+
}
52+
4853
/**
4954
* @Given I registred my vehicle with platenumber :platenumber
5055
*/
5156
public function iRegistredMyVehicleWithPlatenumber($platenumber)
5257
{
5358
$this->eventStore->commit(
54-
new EventSourcing\EventStream(
55-
new EventSourcing\EventStreamId('vehicle-fleet_'.$this->userId),
59+
new EventSourcing\Stream(
60+
new EventSourcing\StreamName('vehicle_fleet-'.$this->userId),
5661
new \ArrayIterator([
57-
new Domain\VehicleWasRegistered($platenumber, $this->userId)
62+
new Domain\VehicleWasRegistered($this->userId, $platenumber)
5863
])
5964
)
6065
);
@@ -63,9 +68,17 @@ public function iRegistredMyVehicleWithPlatenumber($platenumber)
6368
/**
6469
* @When I park my vehicle with platenumber :platenumber at location :location
6570
*/
66-
public function iParkMyVehicleWithPlatenumberAtLocation($platenumber, $location)
71+
public function iParkMyVehicleWithPlatenumberAtLocation($platenumber, Domain\Location $location)
6772
{
68-
throw new PendingException();
73+
// Endpoint should be improve to follow REST
74+
$this->restApiBrowser->sendRequest(
75+
'POST',
76+
sprintf('/users/%s/vehicles/location', $this->userId),
77+
json_encode([
78+
'platenumber' => $platenumber,
79+
'location' => $location,
80+
])
81+
);
6982
}
7083

7184
/**
@@ -84,18 +97,28 @@ public function iRegisterMyVehicleWithPlatenumberDescribedAsInMyVehicleFleet($pl
8497
}
8598

8699
/**
87-
* @Then the vehicle with platenumber :arg1 should be part of my vehicle fleet
100+
* @Then the vehicle with platenumber :platenumber should be part of my vehicle fleet
88101
*/
89-
public function theVehicleWithPlatenumberShouldBePartOfMyVehicleFleet($arg1)
102+
public function theVehicleWithPlatenumberShouldBePartOfMyVehicleFleet($platenumber)
90103
{
91-
throw new PendingException();
104+
$this->restApiBrowser->sendRequest(
105+
'GET',
106+
sprintf('/users/%s/vehicles', $this->userId)
107+
);
108+
// Shoud iterate to be a better assertion
109+
$this->jsonContext->theJsonNodeShouldBeEqualTo('vehicles[0].platenumber', $platenumber);
92110
}
93111

94112
/**
95-
* @Then the known location of my vehicle :arg1 should be :arg2
113+
* @Then the known location of my vehicle :platenumber should be :location
96114
*/
97-
public function theKnownLocationOfMyVehicleShouldBe($arg1, $arg2)
115+
public function theKnownLocationOfMyVehicleShouldBe($platenumber, Domain\Location $location)
98116
{
99-
throw new PendingException();
117+
$this->restApiBrowser->sendRequest(
118+
'GET',
119+
sprintf('/users/%s/vehicles', $this->userId)
120+
);
121+
$this->jsonContext->theJsonNodeShouldBeEqualTo('vehicles[0].location.latitude', $location->getLatitude());
122+
$this->jsonContext->theJsonNodeShouldBeEqualTo('vehicles[0].location.longitude', $location->getLongitude());
100123
}
101124
}

features/register_vehicle.feature

-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,4 @@ Feature: Register vehicle
77
@critical
88
Scenario: Successfully registring of a vehicle
99
When I register my vehicle with platenumber "123 DE 456" described as "My sport car" in my vehicle fleet
10-
Then print response
1110
Then the vehicle with platenumber "123 DE 456" should be part of my vehicle fleet

spec/Domain/VehicleFleetSpec.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class VehicleFleetSpec extends ObjectBehavior
1313
{
1414
public function let()
1515
{
16-
$this->beConstructedWith(new UserId('123'));
16+
$this->beConstructedThrough('ofUser', ['123']);
1717
}
1818

1919
public function it_register_new_vehicle()

spec/Domain/VehicleSpec.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44

55
use Shouze\ParkedLife\Domain\Location;
66
use Shouze\ParkedLife\Domain\Vehicle;
7-
use Shouze\ParkedLife\Domain\UserId;
87
use PhpSpec\ObjectBehavior;
98
use Prophecy\Argument;
109

1110
class VehicleSpec extends ObjectBehavior
1211
{
1312
public function let()
1413
{
15-
$this->beConstructedThrough('register', ['123 DE 456', new UserId('user'), 'Some car description']);
14+
$this->beConstructedThrough('register', ['123 DE 456', 'user', 'Some car description']);
1615
}
1716

1817
public function it_knows_its_platenumber()

src/Adapters/EventStoreVehicleFleetRepository.php

+14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
use Shouze\ParkedLife\Domain\VehicleFleet;
77
use Shouze\ParkedLife\Domain\VehicleFleetRepository;
8+
use Shouze\ParkedLife\EventSourcing\AggregateHistory;
89
use Shouze\ParkedLife\EventSourcing\EventStore;
910
use Shouze\ParkedLife\EventSourcing\Stream;
1011
use Shouze\ParkedLife\EventSourcing\StreamName;
@@ -18,6 +19,19 @@ public function __construct(EventStore $eventStore)
1819
$this->eventStore = $eventStore;
1920
}
2021

22+
public function find($userId)
23+
{
24+
$stream = $this->eventStore->fetch(new StreamName('vehicle_fleet-'.$userId));
25+
26+
if (count($stream) <= 0) {
27+
return null;
28+
}
29+
30+
return VehicleFleet::reconstituteFromHistory(
31+
AggregateHistory::fromEvents($stream->getChanges()->getArrayCopy())
32+
);
33+
}
34+
2135
public function save(VehicleFleet $vehicleFleet)
2236
{
2337
$historyToSave = $vehicleFleet->popRecordedChanges();

0 commit comments

Comments
 (0)