EventsDispatcherTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. <?php
  2. namespace Illuminate\Tests\Events;
  3. use Exception;
  4. use Illuminate\Container\Container;
  5. use Illuminate\Events\Dispatcher;
  6. use Mockery as m;
  7. use PHPUnit\Framework\TestCase;
  8. class EventsDispatcherTest extends TestCase
  9. {
  10. protected function tearDown(): void
  11. {
  12. m::close();
  13. }
  14. public function testBasicEventExecution()
  15. {
  16. unset($_SERVER['__event.test']);
  17. $d = new Dispatcher;
  18. $d->listen('foo', function ($foo) {
  19. $_SERVER['__event.test'] = $foo;
  20. });
  21. $response = $d->dispatch('foo', ['bar']);
  22. $this->assertEquals([null], $response);
  23. $this->assertSame('bar', $_SERVER['__event.test']);
  24. // we can still add listeners after the event has fired
  25. $d->listen('foo', function ($foo) {
  26. $_SERVER['__event.test'] .= $foo;
  27. });
  28. $d->dispatch('foo', ['bar']);
  29. $this->assertSame('barbar', $_SERVER['__event.test']);
  30. }
  31. public function testHaltingEventExecution()
  32. {
  33. unset($_SERVER['__event.test']);
  34. $d = new Dispatcher;
  35. $d->listen('foo', function ($foo) {
  36. $this->assertTrue(true);
  37. return 'here';
  38. });
  39. $d->listen('foo', function ($foo) {
  40. throw new Exception('should not be called');
  41. });
  42. $response = $d->dispatch('foo', ['bar'], true);
  43. $this->assertSame('here', $response);
  44. $response = $d->until('foo', ['bar']);
  45. $this->assertSame('here', $response);
  46. }
  47. public function testResponseWhenNoListenersAreSet()
  48. {
  49. $d = new Dispatcher;
  50. $response = $d->dispatch('foo');
  51. $this->assertEquals([], $response);
  52. $response = $d->dispatch('foo', [], true);
  53. $this->assertNull($response);
  54. }
  55. public function testReturningFalseStopsPropagation()
  56. {
  57. unset($_SERVER['__event.test']);
  58. $d = new Dispatcher;
  59. $d->listen('foo', function ($foo) {
  60. return $foo;
  61. });
  62. $d->listen('foo', function ($foo) {
  63. $_SERVER['__event.test'] = $foo;
  64. return false;
  65. });
  66. $d->listen('foo', function ($foo) {
  67. throw new Exception('should not be called');
  68. });
  69. $response = $d->dispatch('foo', ['bar']);
  70. $this->assertSame('bar', $_SERVER['__event.test']);
  71. $this->assertEquals(['bar'], $response);
  72. }
  73. public function testReturningFalsyValuesContinuesPropagation()
  74. {
  75. unset($_SERVER['__event.test']);
  76. $d = new Dispatcher;
  77. $d->listen('foo', function () {
  78. return 0;
  79. });
  80. $d->listen('foo', function () {
  81. return [];
  82. });
  83. $d->listen('foo', function () {
  84. return '';
  85. });
  86. $d->listen('foo', function () {
  87. });
  88. $response = $d->dispatch('foo', ['bar']);
  89. $this->assertEquals([0, [], '', null], $response);
  90. }
  91. public function testContainerResolutionOfEventHandlers()
  92. {
  93. $d = new Dispatcher($container = m::mock(Container::class));
  94. $container->shouldReceive('make')->once()->with(TestEventListener::class)->andReturn(new TestEventListener);
  95. $d->listen('foo', TestEventListener::class.'@onFooEvent');
  96. $response = $d->dispatch('foo', ['foo', 'bar']);
  97. $this->assertEquals(['baz'], $response);
  98. }
  99. public function testContainerResolutionOfEventHandlersWithDefaultMethods()
  100. {
  101. $d = new Dispatcher(new Container);
  102. $d->listen('foo', TestEventListener::class);
  103. $response = $d->dispatch('foo', ['foo', 'bar']);
  104. $this->assertEquals(['baz'], $response);
  105. }
  106. public function testQueuedEventsAreFired()
  107. {
  108. unset($_SERVER['__event.test']);
  109. $d = new Dispatcher;
  110. $d->listen('update', function ($name) {
  111. $_SERVER['__event.test'] = $name;
  112. });
  113. $d->push('update', ['name' => 'taylor']);
  114. $d->listen('update', function ($name) {
  115. $_SERVER['__event.test'] .= '_'.$name;
  116. });
  117. $this->assertFalse(isset($_SERVER['__event.test']));
  118. $d->flush('update');
  119. $d->listen('update', function ($name) {
  120. $_SERVER['__event.test'] .= $name;
  121. });
  122. $this->assertSame('taylor_taylor', $_SERVER['__event.test']);
  123. }
  124. public function testQueuedEventsCanBeForgotten()
  125. {
  126. $_SERVER['__event.test'] = 'unset';
  127. $d = new Dispatcher;
  128. $d->push('update', ['name' => 'taylor']);
  129. $d->listen('update', function ($name) {
  130. $_SERVER['__event.test'] = $name;
  131. });
  132. $d->forgetPushed();
  133. $d->flush('update');
  134. $this->assertSame('unset', $_SERVER['__event.test']);
  135. }
  136. public function testMultiplePushedEventsWillGetFlushed()
  137. {
  138. $_SERVER['__event.test'] = '';
  139. $d = new Dispatcher;
  140. $d->push('update', ['name' => 'taylor ']);
  141. $d->push('update', ['name' => 'otwell']);
  142. $d->listen('update', function ($name) {
  143. $_SERVER['__event.test'] .= $name;
  144. });
  145. $d->flush('update');
  146. $this->assertSame('taylor otwell', $_SERVER['__event.test']);
  147. }
  148. public function testWildcardListeners()
  149. {
  150. unset($_SERVER['__event.test']);
  151. $d = new Dispatcher;
  152. $d->listen('foo.bar', function () {
  153. $_SERVER['__event.test'] = 'regular';
  154. });
  155. $d->listen('foo.*', function () {
  156. $_SERVER['__event.test'] = 'wildcard';
  157. });
  158. $d->listen('bar.*', function () {
  159. $_SERVER['__event.test'] = 'nope';
  160. });
  161. $response = $d->dispatch('foo.bar');
  162. $this->assertEquals([null, null], $response);
  163. $this->assertSame('wildcard', $_SERVER['__event.test']);
  164. }
  165. public function testWildcardListenersWithResponses()
  166. {
  167. unset($_SERVER['__event.test']);
  168. $d = new Dispatcher;
  169. $d->listen('foo.bar', function () {
  170. return 'regular';
  171. });
  172. $d->listen('foo.*', function () {
  173. return 'wildcard';
  174. });
  175. $d->listen('bar.*', function () {
  176. return 'nope';
  177. });
  178. $response = $d->dispatch('foo.bar');
  179. $this->assertEquals(['regular', 'wildcard'], $response);
  180. }
  181. public function testWildcardListenersCacheFlushing()
  182. {
  183. unset($_SERVER['__event.test']);
  184. $d = new Dispatcher;
  185. $d->listen('foo.*', function () {
  186. $_SERVER['__event.test'] = 'cached_wildcard';
  187. });
  188. $d->dispatch('foo.bar');
  189. $this->assertSame('cached_wildcard', $_SERVER['__event.test']);
  190. $d->listen('foo.*', function () {
  191. $_SERVER['__event.test'] = 'new_wildcard';
  192. });
  193. $d->dispatch('foo.bar');
  194. $this->assertSame('new_wildcard', $_SERVER['__event.test']);
  195. }
  196. public function testListenersCanBeRemoved()
  197. {
  198. unset($_SERVER['__event.test']);
  199. $d = new Dispatcher;
  200. $d->listen('foo', function () {
  201. $_SERVER['__event.test'] = 'foo';
  202. });
  203. $d->forget('foo');
  204. $d->dispatch('foo');
  205. $this->assertFalse(isset($_SERVER['__event.test']));
  206. }
  207. public function testWildcardListenersCanBeRemoved()
  208. {
  209. unset($_SERVER['__event.test']);
  210. $d = new Dispatcher;
  211. $d->listen('foo.*', function () {
  212. $_SERVER['__event.test'] = 'foo';
  213. });
  214. $d->forget('foo.*');
  215. $d->dispatch('foo.bar');
  216. $this->assertFalse(isset($_SERVER['__event.test']));
  217. }
  218. public function testWildcardCacheIsClearedWhenListenersAreRemoved()
  219. {
  220. unset($_SERVER['__event.test']);
  221. $d = new Dispatcher;
  222. $d->listen('foo*', function () {
  223. $_SERVER['__event.test'] = 'foo';
  224. });
  225. $d->dispatch('foo');
  226. $this->assertSame('foo', $_SERVER['__event.test']);
  227. unset($_SERVER['__event.test']);
  228. $d->forget('foo*');
  229. $d->dispatch('foo');
  230. $this->assertFalse(isset($_SERVER['__event.test']));
  231. }
  232. public function testListenersCanBeFound()
  233. {
  234. $d = new Dispatcher;
  235. $this->assertFalse($d->hasListeners('foo'));
  236. $d->listen('foo', function () {
  237. //
  238. });
  239. $this->assertTrue($d->hasListeners('foo'));
  240. }
  241. public function testWildcardListenersCanBeFound()
  242. {
  243. $d = new Dispatcher;
  244. $this->assertFalse($d->hasListeners('foo.*'));
  245. $d->listen('foo.*', function () {
  246. //
  247. });
  248. $this->assertTrue($d->hasListeners('foo.*'));
  249. $this->assertTrue($d->hasListeners('foo.bar'));
  250. }
  251. public function testEventPassedFirstToWildcards()
  252. {
  253. $d = new Dispatcher;
  254. $d->listen('foo.*', function ($event, $data) {
  255. $this->assertSame('foo.bar', $event);
  256. $this->assertEquals(['first', 'second'], $data);
  257. });
  258. $d->dispatch('foo.bar', ['first', 'second']);
  259. $d = new Dispatcher;
  260. $d->listen('foo.bar', function ($first, $second) {
  261. $this->assertSame('first', $first);
  262. $this->assertSame('second', $second);
  263. });
  264. $d->dispatch('foo.bar', ['first', 'second']);
  265. }
  266. public function testClassesWork()
  267. {
  268. unset($_SERVER['__event.test']);
  269. $d = new Dispatcher;
  270. $d->listen(ExampleEvent::class, function () {
  271. $_SERVER['__event.test'] = 'baz';
  272. });
  273. $d->dispatch(new ExampleEvent);
  274. $this->assertSame('baz', $_SERVER['__event.test']);
  275. }
  276. public function testClassesWorkWithAnonymousListeners()
  277. {
  278. unset($_SERVER['__event.test']);
  279. $d = new Dispatcher;
  280. $d->listen(function (ExampleEvent $event) {
  281. $_SERVER['__event.test'] = 'qux';
  282. });
  283. $d->dispatch(new ExampleEvent);
  284. $this->assertSame('qux', $_SERVER['__event.test']);
  285. }
  286. public function testEventClassesArePayload()
  287. {
  288. unset($_SERVER['__event.test']);
  289. $d = new Dispatcher;
  290. $d->listen(ExampleEvent::class, function ($payload) {
  291. $_SERVER['__event.test'] = $payload;
  292. });
  293. $d->dispatch($e = new ExampleEvent, ['foo']);
  294. $this->assertSame($e, $_SERVER['__event.test']);
  295. }
  296. public function testInterfacesWork()
  297. {
  298. unset($_SERVER['__event.test']);
  299. $d = new Dispatcher;
  300. $d->listen(SomeEventInterface::class, function () {
  301. $_SERVER['__event.test'] = 'bar';
  302. });
  303. $d->dispatch(new AnotherEvent);
  304. $this->assertSame('bar', $_SERVER['__event.test']);
  305. }
  306. public function testBothClassesAndInterfacesWork()
  307. {
  308. unset($_SERVER['__event.test']);
  309. $_SERVER['__event.test'] = [];
  310. $d = new Dispatcher;
  311. $d->listen(AnotherEvent::class, function ($p) {
  312. $_SERVER['__event.test'][] = $p;
  313. $_SERVER['__event.test1'] = 'fooo';
  314. });
  315. $d->listen(SomeEventInterface::class, function ($p) {
  316. $_SERVER['__event.test'][] = $p;
  317. $_SERVER['__event.test2'] = 'baar';
  318. });
  319. $d->dispatch($e = new AnotherEvent, ['foo']);
  320. $this->assertSame($e, $_SERVER['__event.test'][0]);
  321. $this->assertSame($e, $_SERVER['__event.test'][1]);
  322. $this->assertSame('fooo', $_SERVER['__event.test1']);
  323. $this->assertSame('baar', $_SERVER['__event.test2']);
  324. unset($_SERVER['__event.test1'], $_SERVER['__event.test2']);
  325. }
  326. public function testNestedEvent()
  327. {
  328. $_SERVER['__event.test'] = [];
  329. $d = new Dispatcher;
  330. $d->listen('event', function () use ($d) {
  331. $d->listen('event', function () {
  332. $_SERVER['__event.test'][] = 'fired 1';
  333. });
  334. $d->listen('event', function () {
  335. $_SERVER['__event.test'][] = 'fired 2';
  336. });
  337. });
  338. $d->dispatch('event');
  339. $this->assertSame([], $_SERVER['__event.test']);
  340. $d->dispatch('event');
  341. $this->assertEquals(['fired 1', 'fired 2'], $_SERVER['__event.test']);
  342. }
  343. public function testDuplicateListenersWillFire()
  344. {
  345. $d = new Dispatcher;
  346. $d->listen('event', TestListener::class);
  347. $d->listen('event', TestListener::class);
  348. $d->listen('event', TestListener::class.'@handle');
  349. $d->listen('event', TestListener::class.'@handle');
  350. $d->dispatch('event');
  351. $this->assertEquals(4, TestListener::$counter);
  352. TestListener::$counter = 0;
  353. }
  354. }
  355. class ExampleEvent
  356. {
  357. //
  358. }
  359. interface SomeEventInterface
  360. {
  361. //
  362. }
  363. class AnotherEvent implements SomeEventInterface
  364. {
  365. //
  366. }
  367. class TestEventListener
  368. {
  369. public function handle($foo, $bar)
  370. {
  371. return 'baz';
  372. }
  373. public function onFooEvent($foo, $bar)
  374. {
  375. return 'baz';
  376. }
  377. }
  378. class TestListener
  379. {
  380. public static $counter = 0;
  381. public function handle()
  382. {
  383. self::$counter++;
  384. }
  385. }