Last active
October 18, 2018 07:21
-
-
Save nicolas-grekas/1d08b6d5ecbb2504b788e378583920a0 to your computer and use it in GitHub Desktop.
A middleware stack that doesn't double the stack size
This file contains hidden or 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 | |
| error_reporting(-1); | |
| require 'vendor/autoload.php'; | |
| interface MessageBusInterface | |
| { | |
| /** | |
| * @param object|Envelope $message | |
| */ | |
| public function dispatch($message, string $name = null): void; | |
| } | |
| interface BusMiddlewareInterface extends MessageBusInterface | |
| { | |
| public function setMiddlewareBus(MiddlewareBusInterface $bus): void; | |
| } | |
| interface MiddlewareBusInterface | |
| { | |
| public function getNextBusDispatcher(): MessageBusInterface; | |
| } | |
| class NullDispatcher implements MessageBusInterface | |
| { | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function dispatch($message, string $name = null): void | |
| { | |
| // no-op | |
| } | |
| } | |
| trait BusMiddlewareTrait | |
| { | |
| private $bus; | |
| public function setMiddlewareBus(MiddlewareBusInterface $bus): void | |
| { | |
| $this->bus = $bus; | |
| } | |
| private function next(): MessageBusInterface | |
| { | |
| try { | |
| return $this->bus ? $this->bus->getNextBusDispatcher() : new NullDispatcher(); | |
| } finally { | |
| $this->bus = null; | |
| } | |
| } | |
| } | |
| class BusMiddleware implements BusMiddlewareInterface | |
| { | |
| use BusMiddlewareTrait; | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function dispatch($message, string $name = null): void | |
| { | |
| dump(1); | |
| $this->next()->dispatch($message, $name); | |
| dump(2); | |
| } | |
| } | |
| class DumpBus implements MessageBusInterface | |
| { | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function dispatch($message, string $name = null): void | |
| { | |
| dump($message); | |
| } | |
| } | |
| /** | |
| * @internal | |
| */ | |
| class MiddlewareAggregate implements \IteratorAggregate | |
| { | |
| private $aggregate; | |
| private $iterator; | |
| public function __construct(&$aggregate, \Traversable $middlewares) | |
| { | |
| $this->aggregate = &$aggregate; | |
| $this->iterator = $middlewares; | |
| $aggregate = $this; | |
| } | |
| public function getIterator() | |
| { | |
| $middlewares = array(); | |
| foreach ($this->iterator as $middleware) { | |
| yield $middlewares[] = $middleware; | |
| } | |
| $this->aggregate = new \ArrayObject($middlewares); | |
| } | |
| } | |
| class MessageBus implements MessageBusInterface, MiddlewareBusInterface | |
| { | |
| private $middlewareAggregate; | |
| private $middlewares; | |
| public function __construct(iterable $middlewares) | |
| { | |
| if (\is_array($middlewares)) { | |
| $this->middlewareAggregate = new \ArrayObject($middlewares); | |
| } else { | |
| new MiddlewareAggregate($this->middlewareAggregate, $middlewares); | |
| } | |
| } | |
| /** | |
| * @param object|Envelope $message | |
| */ | |
| public function dispatch($message, string $name = null): void | |
| { | |
| $bus = clone $this; | |
| foreach ($bus->middlewares = $bus->middlewareAggregate->getIterator() as $middleware) { | |
| if ($middleware instanceof BusMiddlewareInterface) { | |
| $middleware->setMiddlewareBus($bus); | |
| } | |
| $middleware->dispatch($message, $name); | |
| return; | |
| } | |
| } | |
| public function getNextBusDispatcher(): MessageBusInterface | |
| { | |
| if (null === $middlewares = $this->middlewares) { | |
| throw new \LogicException('Cannot get next middleware on uninitialized message bus.'); | |
| } | |
| $middlewares->next(); | |
| if (!$middlewares->valid()) { | |
| return new NullDispatcher(); | |
| } | |
| $middleware = $middlewares->current(); | |
| if ($middleware instanceof BusMiddlewareInterface) { | |
| $middleware->setMiddlewareBus($this); | |
| } else { | |
| $middlewares->next(); | |
| } | |
| return $middleware; | |
| } | |
| } | |
| $bus = new MessageBus(array( | |
| new BusMiddleware(), | |
| new DumpBus(), | |
| )); | |
| $bus->dispatch(123); | |
| $bus->dispatch(234); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment