Skip to content

Commit

Permalink
Merge pull request #80 from conferencetools/validate-basket
Browse files Browse the repository at this point in the history
Refactored creation of basket out into a factory service
  • Loading branch information
carnage authored Dec 12, 2017
2 parents 9be0c85 + 77971d5 commit 8c1bedd
Show file tree
Hide file tree
Showing 14 changed files with 351 additions and 47 deletions.
18 changes: 8 additions & 10 deletions src/Controller/TicketController.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,14 @@ public function selectTicketsAction()
} else {
$command = new ReserveTickets(...$purchases);
}

$this->getCommandBus()->dispatch($command);
/** @var TicketPurchaseCreated $event */
$event = $this->events()->getEventsByType(TicketPurchaseCreated::class)[0];
return $this->redirect()->toRoute('tickets/purchase', ['purchaseId' => $event->getId()]);
try {
$this->getCommandBus()->dispatch($command);
/** @var TicketPurchaseCreated $event */
$event = $this->events()->getEventsByType(TicketPurchaseCreated::class)[0];
return $this->redirect()->toRoute('tickets/purchase', ['purchaseId' => $event->getId()]);
} catch (\DomainException $e) {
$this->flashMessenger()->addErrorMessage($e->getMessage());
}
}
} else {
try {
Expand Down Expand Up @@ -145,11 +148,6 @@ private function validateSelectedTickets($data, $tickets): array
}
}

if ($total < 1) {
$this->flashMessenger()->addErrorMessage('You must specify at least 1 ticket to purchase');
$errors = true;
}

if ($errors) {
throw new \InvalidArgumentException('input contained errors');
}
Expand Down
35 changes: 10 additions & 25 deletions src/Domain/CommandHandler/Ticket.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use ConferenceTools\Tickets\Domain\Command\Ticket\ReserveTickets;
use ConferenceTools\Tickets\Domain\Command\Ticket\TimeoutPurchase;
use ConferenceTools\Tickets\Domain\Model\Ticket\TicketPurchase;
use ConferenceTools\Tickets\Domain\Service\Basket\Factory;
use ConferenceTools\Tickets\Domain\Service\Configuration;
use ConferenceTools\Tickets\Domain\ValueObject\Basket;
use ConferenceTools\Tickets\Domain\ValueObject\TicketReservation;
Expand All @@ -28,31 +29,26 @@ class Ticket extends AbstractMethodNameMessageHandler
* @var GeneratorInterface
*/
private $identityGenerator;
/**
* @var GeneratorInterface
*/
private $ticketIdGenerator;

/**
* @var RepositoryInterface
*/
private $repository;

/**
* @var Configuration
* @var Factory
*/
private $configuration;
private $basketFactory;

public function __construct(
GeneratorInterface $identityGenerator,
GeneratorInterface $ticketIdGenerator,
RepositoryInterface $repository,
Configuration $configuration
Factory $basketFactory
) {

$this->identityGenerator = $identityGenerator;
$this->ticketIdGenerator = $ticketIdGenerator;
$this->repository = $repository;
$this->configuration = $configuration;
$this->basketFactory = $basketFactory;
}

/**
Expand All @@ -61,26 +57,15 @@ public function __construct(
*/
protected function handleReserveTickets(ReserveTickets $command)
{
$tickets = [];
foreach ($command->getReservationRequests() as $reservationRequest) {
for ($i = 0; $i < $reservationRequest->getQuantity(); $i++) {
$tickets[] = new TicketReservation($reservationRequest->getTicketType(), $this->ticketIdGenerator->generateIdentity());
}
}

if (count($tickets) === 0) {
throw new \RuntimeException('Must specify at least 1 ticket for purchase');
}

if ($command->hasDiscountCode()) {
$basket = Basket::fromReservationsWithDiscount(
$this->configuration,
$basket = $this->basketFactory->basketWithDiscount(
$command->getDiscountCode(),
...$tickets
...$command->getReservationRequests()
);
} else {
$basket = Basket::fromReservations($this->configuration, ...$tickets);
$basket = $this->basketFactory->basket(...$command->getReservationRequests());
}

$purchase = TicketPurchase::create($this->identityGenerator->generateIdentity(), $basket);

$this->repository->save($purchase);
Expand Down
10 changes: 10 additions & 0 deletions src/Domain/Service/Basket/BasketValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace ConferenceTools\Tickets\Domain\Service\Basket;

use ConferenceTools\Tickets\Domain\ValueObject\Basket;

interface BasketValidator
{
public function validate(Basket $basket): void;
}
79 changes: 79 additions & 0 deletions src/Domain/Service/Basket/Factory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

namespace ConferenceTools\Tickets\Domain\Service\Basket;

use Carnage\Cqrs\Aggregate\Identity\GeneratorInterface;
use ConferenceTools\Tickets\Domain\Service\Configuration;
use ConferenceTools\Tickets\Domain\ValueObject\Basket;
use ConferenceTools\Tickets\Domain\ValueObject\DiscountCode;
use ConferenceTools\Tickets\Domain\ValueObject\TicketReservation;
use ConferenceTools\Tickets\Domain\ValueObject\TicketReservationRequest;

class Factory
{
/**
* @var GeneratorInterface
*/
private $ticketIdGenerator;

/**
* @var Configuration
*/
private $configuration;

/**
* @var BasketValidator
*/
private $basketValidator;

public function __construct(
GeneratorInterface $ticketIdGenerator,
Configuration $configuration,
BasketValidator $basketValidator
) {
$this->ticketIdGenerator = $ticketIdGenerator;
$this->configuration = $configuration;
$this->basketValidator = $basketValidator;
}

public function basket(TicketReservationRequest ...$reservationRequests): Basket
{
$tickets = $this->createTicketReservations(...$reservationRequests);

return Basket::fromReservations(
$this->configuration,
$this->basketValidator,
...$tickets
);
}

public function basketWithDiscount(
DiscountCode $discountCode,
TicketReservationRequest ...$reservationRequests
): Basket {
$tickets = $this->createTicketReservations(...$reservationRequests);

return Basket::fromReservationsWithDiscount(
$this->configuration,
$this->basketValidator,
$discountCode,
...$tickets
);
}

/**
* @return TicketReservation[]
*/
private function createTicketReservations(TicketReservationRequest ...$reservationRequests): array
{
$tickets = [];
foreach ($reservationRequests as $reservationRequest) {
for ($i = 0; $i < $reservationRequest->getQuantity(); $i++) {
$tickets[] = new TicketReservation($reservationRequest->getTicketType(),
$this->ticketIdGenerator->generateIdentity());
}
}

return $tickets;
}
}
15 changes: 15 additions & 0 deletions src/Domain/Service/Basket/ValidateBasket.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace ConferenceTools\Tickets\Domain\Service\Basket;

use ConferenceTools\Tickets\Domain\ValueObject\Basket;

class ValidateBasket implements BasketValidator
{
public function validate(Basket $basket): void
{
if (count($basket->getTickets()) === 0) {
throw new \DomainException('You must choose at least 1 ticket to purchase');
}
}
}
23 changes: 14 additions & 9 deletions src/Domain/ValueObject/Basket.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace ConferenceTools\Tickets\Domain\ValueObject;

use ConferenceTools\Tickets\Domain\Service\Basket\BasketValidator;
use ConferenceTools\Tickets\Domain\Service\Configuration;

class Basket
Expand All @@ -28,16 +29,14 @@ class Basket

private function __construct(TicketReservation ...$tickets)
{
if (count($tickets) === 0) {
throw new \InvalidArgumentException('Must put at least one Ticket reservation into a basket');
}

$this->tickets = $tickets;

}

public static function fromReservations(Configuration $config, TicketReservation ...$tickets)
{
public static function fromReservations(
Configuration $config,
BasketValidator $validator,
TicketReservation ...$tickets
) {
$instance = new self(
...$tickets
);
Expand All @@ -46,14 +45,18 @@ public static function fromReservations(Configuration $config, TicketReservation
$instance->preDiscountTotal = $instance->calculateTotal($zero);

$instance->total = $instance->preDiscountTotal;

$validator->validate($instance);

return $instance;
}

public static function fromReservationsWithDiscount(
Configuration $config,
BasketValidator $validator,
DiscountCode $discountCode,
TicketReservation ...$tickets)
{
TicketReservation ...$tickets
) {
$instance = new self(
...$tickets
);
Expand All @@ -64,6 +67,8 @@ public static function fromReservationsWithDiscount(
$instance->total = $instance->preDiscountTotal->subtract($discountCode->apply($instance));
$instance->discountCode = $discountCode;

$validator->validate($instance);

return $instance;
}

Expand Down
9 changes: 7 additions & 2 deletions src/Service/Factory/CommandHandler/Ticket.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use Carnage\Cqrs\Aggregate\Identity\YouTubeStyleIdentityGenerator;
use ConferenceTools\Tickets\Domain\CommandHandler\Ticket as TicketCommandHandler;
use ConferenceTools\Tickets\Domain\Model\Ticket\TicketPurchase;
use ConferenceTools\Tickets\Domain\Service\Basket\Factory;
use ConferenceTools\Tickets\Domain\Service\Basket\ValidateBasket;
use ConferenceTools\Tickets\Domain\Service\Configuration;
use ConferenceTools\Tickets\Service\Identity\TicketIdentityGenerator;
use Zend\ServiceManager\FactoryInterface;
Expand All @@ -20,9 +22,12 @@ public function createService(ServiceLocatorInterface $serviceLocator)

return new TicketCommandHandler(
new YouTubeStyleIdentityGenerator(),
new TicketIdentityGenerator(),
$repositoryManager->get(TicketPurchase::class),
$mainServiceLocator->get(Configuration::class)
new Factory(
new TicketIdentityGenerator(),
$mainServiceLocator->get(Configuration::class),
new ValidateBasket()
)
);
}
}
Loading

0 comments on commit 8c1bedd

Please sign in to comment.