-
-
Save yvoyer/c2c016b7fe5288554e3f6c432acafd65 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
abstract class EventStreamEntity | |
{ | |
/** | |
* @var Event[] | |
*/ | |
protected $events = []; | |
/** | |
* @return Event[] | |
*/ | |
public function collectUncommitedEvents() { } | |
} | |
class Employee extends EventStreamEntity | |
{ | |
public function createOffer(OfferId $offerId, CustomerId $customerId) | |
{ | |
$offer = Offer::PendingOffer(); | |
$this->events[] = new OfferWasCreated($offerId, $customerId); | |
return $offer; | |
} | |
} | |
class OfferId | |
{ | |
} | |
class Offer extends EventStreamEntity | |
{ | |
const STATE_PENDING = 1; | |
const STATE_CUSTOMER_EVALUATION = 2; | |
const STATE_CUSTOMER_AGREE = 3; | |
private $state; | |
/** | |
* @var Customer|null | |
*/ | |
private $owner; | |
/** | |
* @var Employee | |
*/ | |
private $employee; | |
public function __construct(Employee $employee) | |
{ | |
$this->state = self::STATE_PENDING; | |
$this->employee = $employee; | |
} | |
public function notifyEmployee() | |
{ | |
// change state, do something else? | |
} | |
/** | |
* @return EmployeeId | |
*/ | |
public function responsible() | |
{ | |
return $this->employee->getIdentity(); | |
} | |
public function sendToCustomer(Customer $customer) | |
{ | |
$this->state = self::STATE_CUSTOMER_EVALUATION; | |
$this->owner = $customer; | |
$this->events[] = new OfferWasSentToCustomer($this->getIdentity(), $customer->getIdentity()); | |
} | |
public function isOwnedBy(CustomerId $id) | |
{ | |
return $this->owner instanceof Customer && $this->owner->matchIdentity($id); | |
} | |
public function agree() | |
{ | |
$this->state = self::STATE_CUSTOMER_AGREE; | |
} | |
public function isAgreed() | |
{ | |
return $this->state === self::STATE_CUSTOMER_AGREE; | |
} | |
public static function PendingOffer(Employee $responsible) | |
{ | |
return new self($responsible); | |
} | |
public static function SentOffer(Employee $responsible, Customer $customer) | |
{ | |
$offer = self::PendingOffer($responsible); | |
$offer->sendToCustomer($customer); | |
return $offer; | |
} | |
} | |
class CustomerId | |
{ | |
} | |
class Customer extends EventStreamEntity | |
{ | |
private $id; | |
public function getIdentity() | |
{ | |
return new CustomerId($this->id); | |
} | |
public function agreeToOffer(OfferId $offerId) | |
{ | |
$offer = $this->getOffer($offerId); | |
if ($offer->isOwnedBy($this->getIdentity())) { | |
// exception | |
} | |
if ($offer->isAgreed()) { // could be avoided with StatePattern | |
// exception | |
} | |
$offer->agree(); | |
$this->events[] = new CustomerAgreedToOffer($this->getIdentity(), $offerId); | |
} | |
/** | |
* @param OfferId $id | |
* | |
* @return Offer | |
* @throws EntityNotFOundException | |
*/ | |
private function getOffer(OfferId $id) | |
{ | |
} | |
} | |
class CustomerAgreedToOffer | |
{ | |
public $customerId; | |
public $offerId; | |
} | |
class CreateOfferHandler | |
{ | |
public function handle($command) | |
{ | |
/** | |
* @var Employee $employee | |
*/ | |
$employee = $this->employeeRepository->findByIdentity($command->employeeId); | |
$offer = $employee->createOffer($this->identityGenerator->generateOfferId(), $command->customerId); | |
$this->offerRepository->saveOffer($offer); | |
$this->eventPublisher->publish($employee->collectUncommitedEvents()); | |
} | |
} | |
class OfferWasCreated // event | |
{ | |
public $offerId; | |
public $customerId; | |
public function __construct() | |
{ | |
} | |
} | |
class SendOfferToCustomer // event listener | |
{ | |
/** | |
* I put this process in an event, since the send to customer seemed to be happening only when order was created | |
* Also adding an event enables you to plug any other listeners to this event | |
*/ | |
public function onOfferWasCreated(OfferWasCreated $event) | |
{ | |
/** | |
* @var $offer Offer | |
*/ | |
$offer = $this->offerRepository->findOfferByIdentity($event->offerId); | |
$offer->sendToCustomer($event->customerId); | |
$this->offerRepository->saveOffer($offer); | |
$this->eventPublisher->publish($offer->collectUncommitedEvents()); | |
} | |
} | |
// Customer talks to Employee. Employee logs in, creates an offer, sends it to Customer | |
// in OfferController | |
function () { // create offer action | |
$handler = new CreateOfferHandler(); // or message bus, depends on your implementation | |
$handler->handle(new CreateOfferCommand()); // using form and all symfony ways | |
} | |
class AgreeToOfferHandler // command handler | |
{ | |
public function handle($command) | |
{ | |
/** | |
* @var $customer Customer | |
*/ | |
$customer = $this->customerRepository->findCustomer($command->customerId); | |
$customer->agreeToOffer($command->offerId); | |
$this->customerRepository->saveOffer($customer); | |
$this->eventPublisher->publish($customer->collectUncommitedEvents()); | |
} | |
} | |
class OfferAgreedNotifier | |
{ | |
public function onCustomerAgreedToOffer(CustomerAgreedToOffer $event) | |
{ | |
/** | |
* @var $offer Offer | |
*/ | |
$offer = $this->offerRepository->findOffer($event->offerId); | |
$offer->notifyEmployee(); | |
$this->notifier->notifyEmployee($offer->responsible()); // ??? Email or other? | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment