Skip to content

Instantly share code, notes, and snippets.

@yvoyer
Created April 17, 2016 16:05
Show Gist options
  • Save yvoyer/c2c016b7fe5288554e3f6c432acafd65 to your computer and use it in GitHub Desktop.
Save yvoyer/c2c016b7fe5288554e3f6c432acafd65 to your computer and use it in GitHub Desktop.
<?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