-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Messenger] make middlewares truly lazy on a bus #28907
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,28 +11,39 @@ | |
|
||
namespace Symfony\Component\Messenger; | ||
|
||
use Symfony\Component\Messenger\Exception\InvalidArgumentException; | ||
use Symfony\Component\Messenger\Middleware\MiddlewareInterface; | ||
|
||
/** | ||
* @author Samuel Roze <samuel.roze@gmail.com> | ||
* @author Matthias Noback <matthiasnoback@gmail.com> | ||
* @author Nicolas Grekas <p@tchwork.com> | ||
*/ | ||
class MessageBus implements MessageBusInterface | ||
{ | ||
private $middlewareHandlers; | ||
|
||
/** | ||
* @var MiddlewareInterface[]|null | ||
*/ | ||
private $indexedMiddlewareHandlers; | ||
private $middlewareAggregate; | ||
|
||
/** | ||
* @param MiddlewareInterface[]|iterable $middlewareHandlers | ||
*/ | ||
public function __construct(iterable $middlewareHandlers = array()) | ||
{ | ||
$this->middlewareHandlers = $middlewareHandlers; | ||
if ($middlewareHandlers instanceof \IteratorAggregate) { | ||
$this->middlewareAggregate = $middlewareHandlers; | ||
} elseif (\is_array($middlewareHandlers)) { | ||
$this->middlewareAggregate = new \ArrayObject($middlewareHandlers); | ||
} else { | ||
$this->middlewareAggregate = new class() { | ||
public $aggregate; | ||
public $iterator; | ||
|
||
public function getIterator() | ||
{ | ||
return $this->aggregate = new \ArrayObject(iterator_to_array($this->iterator, false)); | ||
} | ||
}; | ||
$this->middlewareAggregate->aggregate = &$this->middlewareAggregate; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you move that to be in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The class is internal, the public properties are not accessible. Adding a constructor would just add unneeded boilerplate. Better not to me. |
||
$this->middlewareAggregate->iterator = $middlewareHandlers; | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -41,24 +52,26 @@ public function __construct(iterable $middlewareHandlers = array()) | |
public function dispatch($message): void | ||
{ | ||
if (!\is_object($message)) { | ||
throw new InvalidArgumentException(sprintf('Invalid type for message argument. Expected object, but got "%s".', \gettype($message))); | ||
throw new \TypeError(sprintf('Invalid argument provided to "%s()": expected object, but got %s.', __METHOD__, \gettype($message))); | ||
} | ||
$middlewareIterator = $this->middlewareAggregate->getIterator(); | ||
nicolas-grekas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
$this->callableForNextMiddleware(0)($message instanceof Envelope ? $message : new Envelope($message)); | ||
} | ||
|
||
private function callableForNextMiddleware(int $index): callable | ||
{ | ||
if (null === $this->indexedMiddlewareHandlers) { | ||
$this->indexedMiddlewareHandlers = \is_array($this->middlewareHandlers) ? array_values($this->middlewareHandlers) : iterator_to_array($this->middlewareHandlers, false); | ||
while ($middlewareIterator instanceof \IteratorAggregate) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sroze i suggested that, see #28907 (comment) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. but maybe we should enforce it resolves once, either here or in the constructor 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's how "foreach" works internally. We must have it to preserve basic PHP semantics of Traversable. |
||
$middlewareIterator = $middlewareIterator->getIterator(); | ||
} | ||
$middlewareIterator->rewind(); | ||
|
||
if (!isset($this->indexedMiddlewareHandlers[$index])) { | ||
return static function () {}; | ||
if (!$middlewareIterator->valid()) { | ||
return; | ||
} | ||
$next = static function (Envelope $envelope) use ($middlewareIterator, &$next) { | ||
$middlewareIterator->next(); | ||
|
||
return function (Envelope $envelope) use ($index) { | ||
$this->indexedMiddlewareHandlers[$index]->handle($envelope, $this->callableForNextMiddleware($index + 1)); | ||
if ($middlewareIterator->valid()) { | ||
$middlewareIterator->current()->handle($envelope, $next); | ||
} | ||
}; | ||
|
||
$middlewareIterator->current()->handle($message instanceof Envelope ? $message : new Envelope($message), $next); | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.