123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- <?php
- namespace Illuminate\Support\Testing\Fakes;
- use Closure;
- use Illuminate\Container\Container;
- use Illuminate\Contracts\Events\Dispatcher;
- use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
- use Illuminate\Support\Arr;
- use Illuminate\Support\Str;
- use Illuminate\Support\Traits\ForwardsCalls;
- use Illuminate\Support\Traits\ReflectsClosures;
- use PHPUnit\Framework\Assert as PHPUnit;
- use ReflectionFunction;
- class EventFake implements Dispatcher, Fake
- {
- use ForwardsCalls, ReflectsClosures;
- /**
- * The original event dispatcher.
- *
- * @var \Illuminate\Contracts\Events\Dispatcher
- */
- public $dispatcher;
- /**
- * The event types that should be intercepted instead of dispatched.
- *
- * @var array
- */
- protected $eventsToFake = [];
- /**
- * The event types that should be dispatched instead of intercepted.
- *
- * @var array
- */
- protected $eventsToDispatch = [];
- /**
- * All of the events that have been intercepted keyed by type.
- *
- * @var array
- */
- protected $events = [];
- /**
- * Create a new event fake instance.
- *
- * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher
- * @param array|string $eventsToFake
- * @return void
- */
- public function __construct(Dispatcher $dispatcher, $eventsToFake = [])
- {
- $this->dispatcher = $dispatcher;
- $this->eventsToFake = Arr::wrap($eventsToFake);
- }
- /**
- * Specify the events that should be dispatched instead of faked.
- *
- * @param array|string $eventsToDispatch
- * @return $this
- */
- public function except($eventsToDispatch)
- {
- $this->eventsToDispatch = array_merge(
- $this->eventsToDispatch,
- Arr::wrap($eventsToDispatch)
- );
- return $this;
- }
- /**
- * Assert if an event has a listener attached to it.
- *
- * @param string $expectedEvent
- * @param string|array $expectedListener
- * @return void
- */
- public function assertListening($expectedEvent, $expectedListener)
- {
- foreach ($this->dispatcher->getListeners($expectedEvent) as $listenerClosure) {
- $actualListener = (new ReflectionFunction($listenerClosure))
- ->getStaticVariables()['listener'];
- $normalizedListener = $expectedListener;
- if (is_string($actualListener) && Str::contains($actualListener, '@')) {
- $actualListener = Str::parseCallback($actualListener);
- if (is_string($expectedListener)) {
- if (Str::contains($expectedListener, '@')) {
- $normalizedListener = Str::parseCallback($expectedListener);
- } else {
- $normalizedListener = [
- $expectedListener,
- method_exists($expectedListener, 'handle') ? 'handle' : '__invoke',
- ];
- }
- }
- }
- if ($actualListener === $normalizedListener ||
- ($actualListener instanceof Closure &&
- $normalizedListener === Closure::class)) {
- PHPUnit::assertTrue(true);
- return;
- }
- }
- PHPUnit::assertTrue(
- false,
- sprintf(
- 'Event [%s] does not have the [%s] listener attached to it',
- $expectedEvent,
- print_r($expectedListener, true)
- )
- );
- }
- /**
- * Assert if an event was dispatched based on a truth-test callback.
- *
- * @param string|\Closure $event
- * @param callable|int|null $callback
- * @return void
- */
- public function assertDispatched($event, $callback = null)
- {
- if ($event instanceof Closure) {
- [$event, $callback] = [$this->firstClosureParameterType($event), $event];
- }
- if (is_int($callback)) {
- return $this->assertDispatchedTimes($event, $callback);
- }
- PHPUnit::assertTrue(
- $this->dispatched($event, $callback)->count() > 0,
- "The expected [{$event}] event was not dispatched."
- );
- }
- /**
- * Assert if an event was dispatched a number of times.
- *
- * @param string $event
- * @param int $times
- * @return void
- */
- public function assertDispatchedTimes($event, $times = 1)
- {
- $count = $this->dispatched($event)->count();
- PHPUnit::assertSame(
- $times, $count,
- "The expected [{$event}] event was dispatched {$count} times instead of {$times} times."
- );
- }
- /**
- * Determine if an event was dispatched based on a truth-test callback.
- *
- * @param string|\Closure $event
- * @param callable|null $callback
- * @return void
- */
- public function assertNotDispatched($event, $callback = null)
- {
- if ($event instanceof Closure) {
- [$event, $callback] = [$this->firstClosureParameterType($event), $event];
- }
- PHPUnit::assertCount(
- 0, $this->dispatched($event, $callback),
- "The unexpected [{$event}] event was dispatched."
- );
- }
- /**
- * Assert that no events were dispatched.
- *
- * @return void
- */
- public function assertNothingDispatched()
- {
- $count = count(Arr::flatten($this->events));
- PHPUnit::assertSame(
- 0, $count,
- "{$count} unexpected events were dispatched."
- );
- }
- /**
- * Get all of the events matching a truth-test callback.
- *
- * @param string $event
- * @param callable|null $callback
- * @return \Illuminate\Support\Collection
- */
- public function dispatched($event, $callback = null)
- {
- if (! $this->hasDispatched($event)) {
- return collect();
- }
- $callback = $callback ?: fn () => true;
- return collect($this->events[$event])->filter(
- fn ($arguments) => $callback(...$arguments)
- );
- }
- /**
- * Determine if the given event has been dispatched.
- *
- * @param string $event
- * @return bool
- */
- public function hasDispatched($event)
- {
- return isset($this->events[$event]) && ! empty($this->events[$event]);
- }
- /**
- * Register an event listener with the dispatcher.
- *
- * @param \Closure|string|array $events
- * @param mixed $listener
- * @return void
- */
- public function listen($events, $listener = null)
- {
- $this->dispatcher->listen($events, $listener);
- }
- /**
- * Determine if a given event has listeners.
- *
- * @param string $eventName
- * @return bool
- */
- public function hasListeners($eventName)
- {
- return $this->dispatcher->hasListeners($eventName);
- }
- /**
- * Register an event and payload to be dispatched later.
- *
- * @param string $event
- * @param array $payload
- * @return void
- */
- public function push($event, $payload = [])
- {
- //
- }
- /**
- * Register an event subscriber with the dispatcher.
- *
- * @param object|string $subscriber
- * @return void
- */
- public function subscribe($subscriber)
- {
- $this->dispatcher->subscribe($subscriber);
- }
- /**
- * Flush a set of pushed events.
- *
- * @param string $event
- * @return void
- */
- public function flush($event)
- {
- //
- }
- /**
- * Fire an event and call the listeners.
- *
- * @param string|object $event
- * @param mixed $payload
- * @param bool $halt
- * @return array|null
- */
- public function dispatch($event, $payload = [], $halt = false)
- {
- $name = is_object($event) ? get_class($event) : (string) $event;
- if ($this->shouldFakeEvent($name, $payload)) {
- $this->fakeEvent($event, $name, func_get_args());
- } else {
- return $this->dispatcher->dispatch($event, $payload, $halt);
- }
- }
- /**
- * Determine if an event should be faked or actually dispatched.
- *
- * @param string $eventName
- * @param mixed $payload
- * @return bool
- */
- protected function shouldFakeEvent($eventName, $payload)
- {
- if ($this->shouldDispatchEvent($eventName, $payload)) {
- return false;
- }
- if (empty($this->eventsToFake)) {
- return true;
- }
- return collect($this->eventsToFake)
- ->filter(function ($event) use ($eventName, $payload) {
- return $event instanceof Closure
- ? $event($eventName, $payload)
- : $event === $eventName;
- })
- ->isNotEmpty();
- }
- /**
- * Push the event onto the fake events array immediately or after the next database transaction.
- *
- * @param string|object $event
- * @param string $name
- * @param array $arguments
- * @return void
- */
- protected function fakeEvent($event, $name, $arguments)
- {
- if ($event instanceof ShouldDispatchAfterCommit && Container::getInstance()->bound('db.transactions')) {
- return Container::getInstance()->make('db.transactions')
- ->addCallback(fn () => $this->events[$name][] = $arguments);
- }
- $this->events[$name][] = $arguments;
- }
- /**
- * Determine whether an event should be dispatched or not.
- *
- * @param string $eventName
- * @param mixed $payload
- * @return bool
- */
- protected function shouldDispatchEvent($eventName, $payload)
- {
- if (empty($this->eventsToDispatch)) {
- return false;
- }
- return collect($this->eventsToDispatch)
- ->filter(function ($event) use ($eventName, $payload) {
- return $event instanceof Closure
- ? $event($eventName, $payload)
- : $event === $eventName;
- })
- ->isNotEmpty();
- }
- /**
- * Remove a set of listeners from the dispatcher.
- *
- * @param string $event
- * @return void
- */
- public function forget($event)
- {
- //
- }
- /**
- * Forget all of the queued listeners.
- *
- * @return void
- */
- public function forgetPushed()
- {
- //
- }
- /**
- * Dispatch an event and call the listeners.
- *
- * @param string|object $event
- * @param mixed $payload
- * @return mixed
- */
- public function until($event, $payload = [])
- {
- return $this->dispatch($event, $payload, true);
- }
- /**
- * Handle dynamic method calls to the dispatcher.
- *
- * @param string $method
- * @param array $parameters
- * @return mixed
- */
- public function __call($method, $parameters)
- {
- return $this->forwardCallTo($this->dispatcher, $method, $parameters);
- }
- }
|