PageRenderTime 45ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php

https://gitlab.com/4gdevs/online-class-record-system
PHP | 499 lines | 221 code | 63 blank | 215 comment | 20 complexity | a382e8e74e5395c2f9b4499fe5d6a55e MD5 | raw file
  1. <?php
  2. namespace Illuminate\Events;
  3. use Exception;
  4. use ReflectionClass;
  5. use Illuminate\Support\Str;
  6. use Illuminate\Container\Container;
  7. use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
  8. use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
  9. use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
  10. use Illuminate\Contracts\Container\Container as ContainerContract;
  11. class Dispatcher implements DispatcherContract
  12. {
  13. /**
  14. * The IoC container instance.
  15. *
  16. * @var \Illuminate\Contracts\Container\Container
  17. */
  18. protected $container;
  19. /**
  20. * The registered event listeners.
  21. *
  22. * @var array
  23. */
  24. protected $listeners = [];
  25. /**
  26. * The wildcard listeners.
  27. *
  28. * @var array
  29. */
  30. protected $wildcards = [];
  31. /**
  32. * The sorted event listeners.
  33. *
  34. * @var array
  35. */
  36. protected $sorted = [];
  37. /**
  38. * The event firing stack.
  39. *
  40. * @var array
  41. */
  42. protected $firing = [];
  43. /**
  44. * The queue resolver instance.
  45. *
  46. * @var callable
  47. */
  48. protected $queueResolver;
  49. /**
  50. * Create a new event dispatcher instance.
  51. *
  52. * @param \Illuminate\Contracts\Container\Container|null $container
  53. * @return void
  54. */
  55. public function __construct(ContainerContract $container = null)
  56. {
  57. $this->container = $container ?: new Container;
  58. }
  59. /**
  60. * Register an event listener with the dispatcher.
  61. *
  62. * @param string|array $events
  63. * @param mixed $listener
  64. * @param int $priority
  65. * @return void
  66. */
  67. public function listen($events, $listener, $priority = 0)
  68. {
  69. foreach ((array) $events as $event) {
  70. if (Str::contains($event, '*')) {
  71. $this->setupWildcardListen($event, $listener);
  72. } else {
  73. $this->listeners[$event][$priority][] = $this->makeListener($listener);
  74. unset($this->sorted[$event]);
  75. }
  76. }
  77. }
  78. /**
  79. * Setup a wildcard listener callback.
  80. *
  81. * @param string $event
  82. * @param mixed $listener
  83. * @return void
  84. */
  85. protected function setupWildcardListen($event, $listener)
  86. {
  87. $this->wildcards[$event][] = $this->makeListener($listener);
  88. }
  89. /**
  90. * Determine if a given event has listeners.
  91. *
  92. * @param string $eventName
  93. * @return bool
  94. */
  95. public function hasListeners($eventName)
  96. {
  97. return isset($this->listeners[$eventName]);
  98. }
  99. /**
  100. * Register an event and payload to be fired later.
  101. *
  102. * @param string $event
  103. * @param array $payload
  104. * @return void
  105. */
  106. public function push($event, $payload = [])
  107. {
  108. $this->listen($event.'_pushed', function () use ($event, $payload) {
  109. $this->fire($event, $payload);
  110. });
  111. }
  112. /**
  113. * Register an event subscriber with the dispatcher.
  114. *
  115. * @param object|string $subscriber
  116. * @return void
  117. */
  118. public function subscribe($subscriber)
  119. {
  120. $subscriber = $this->resolveSubscriber($subscriber);
  121. $subscriber->subscribe($this);
  122. }
  123. /**
  124. * Resolve the subscriber instance.
  125. *
  126. * @param object|string $subscriber
  127. * @return mixed
  128. */
  129. protected function resolveSubscriber($subscriber)
  130. {
  131. if (is_string($subscriber)) {
  132. return $this->container->make($subscriber);
  133. }
  134. return $subscriber;
  135. }
  136. /**
  137. * Fire an event until the first non-null response is returned.
  138. *
  139. * @param string|object $event
  140. * @param array $payload
  141. * @return mixed
  142. */
  143. public function until($event, $payload = [])
  144. {
  145. return $this->fire($event, $payload, true);
  146. }
  147. /**
  148. * Flush a set of pushed events.
  149. *
  150. * @param string $event
  151. * @return void
  152. */
  153. public function flush($event)
  154. {
  155. $this->fire($event.'_pushed');
  156. }
  157. /**
  158. * Get the event that is currently firing.
  159. *
  160. * @return string
  161. */
  162. public function firing()
  163. {
  164. return last($this->firing);
  165. }
  166. /**
  167. * Fire an event and call the listeners.
  168. *
  169. * @param string|object $event
  170. * @param mixed $payload
  171. * @param bool $halt
  172. * @return array|null
  173. */
  174. public function fire($event, $payload = [], $halt = false)
  175. {
  176. // When the given "event" is actually an object we will assume it is an event
  177. // object and use the class as the event name and this event itself as the
  178. // payload to the handler, which makes object based events quite simple.
  179. if (is_object($event)) {
  180. list($payload, $event) = [[$event], get_class($event)];
  181. }
  182. $responses = [];
  183. // If an array is not given to us as the payload, we will turn it into one so
  184. // we can easily use call_user_func_array on the listeners, passing in the
  185. // payload to each of them so that they receive each of these arguments.
  186. if (! is_array($payload)) {
  187. $payload = [$payload];
  188. }
  189. $this->firing[] = $event;
  190. if (isset($payload[0]) && $payload[0] instanceof ShouldBroadcast) {
  191. $this->broadcastEvent($payload[0]);
  192. }
  193. foreach ($this->getListeners($event) as $listener) {
  194. $response = call_user_func_array($listener, $payload);
  195. // If a response is returned from the listener and event halting is enabled
  196. // we will just return this response, and not call the rest of the event
  197. // listeners. Otherwise we will add the response on the response list.
  198. if (! is_null($response) && $halt) {
  199. array_pop($this->firing);
  200. return $response;
  201. }
  202. // If a boolean false is returned from a listener, we will stop propagating
  203. // the event to any further listeners down in the chain, else we keep on
  204. // looping through the listeners and firing every one in our sequence.
  205. if ($response === false) {
  206. break;
  207. }
  208. $responses[] = $response;
  209. }
  210. array_pop($this->firing);
  211. return $halt ? null : $responses;
  212. }
  213. /**
  214. * Broadcast the given event class.
  215. *
  216. * @param \Illuminate\Contracts\Broadcasting\ShouldBroadcast $event
  217. * @return void
  218. */
  219. protected function broadcastEvent($event)
  220. {
  221. if ($this->queueResolver) {
  222. $connection = $event instanceof ShouldBroadcastNow ? 'sync' : null;
  223. $queue = method_exists($event, 'onQueue') ? $event->onQueue() : null;
  224. $this->resolveQueue()->connection($connection)->pushOn($queue, 'Illuminate\Broadcasting\BroadcastEvent', [
  225. 'event' => serialize(clone $event),
  226. ]);
  227. }
  228. }
  229. /**
  230. * Get all of the listeners for a given event name.
  231. *
  232. * @param string $eventName
  233. * @return array
  234. */
  235. public function getListeners($eventName)
  236. {
  237. $wildcards = $this->getWildcardListeners($eventName);
  238. if (! isset($this->sorted[$eventName])) {
  239. $this->sortListeners($eventName);
  240. }
  241. return array_merge($this->sorted[$eventName], $wildcards);
  242. }
  243. /**
  244. * Get the wildcard listeners for the event.
  245. *
  246. * @param string $eventName
  247. * @return array
  248. */
  249. protected function getWildcardListeners($eventName)
  250. {
  251. $wildcards = [];
  252. foreach ($this->wildcards as $key => $listeners) {
  253. if (Str::is($key, $eventName)) {
  254. $wildcards = array_merge($wildcards, $listeners);
  255. }
  256. }
  257. return $wildcards;
  258. }
  259. /**
  260. * Sort the listeners for a given event by priority.
  261. *
  262. * @param string $eventName
  263. * @return array
  264. */
  265. protected function sortListeners($eventName)
  266. {
  267. $this->sorted[$eventName] = [];
  268. // If listeners exist for the given event, we will sort them by the priority
  269. // so that we can call them in the correct order. We will cache off these
  270. // sorted event listeners so we do not have to re-sort on every events.
  271. if (isset($this->listeners[$eventName])) {
  272. krsort($this->listeners[$eventName]);
  273. $this->sorted[$eventName] = call_user_func_array(
  274. 'array_merge', $this->listeners[$eventName]
  275. );
  276. }
  277. }
  278. /**
  279. * Register an event listener with the dispatcher.
  280. *
  281. * @param mixed $listener
  282. * @return mixed
  283. */
  284. public function makeListener($listener)
  285. {
  286. return is_string($listener) ? $this->createClassListener($listener) : $listener;
  287. }
  288. /**
  289. * Create a class based listener using the IoC container.
  290. *
  291. * @param mixed $listener
  292. * @return \Closure
  293. */
  294. public function createClassListener($listener)
  295. {
  296. $container = $this->container;
  297. return function () use ($listener, $container) {
  298. return call_user_func_array(
  299. $this->createClassCallable($listener, $container), func_get_args()
  300. );
  301. };
  302. }
  303. /**
  304. * Create the class based event callable.
  305. *
  306. * @param string $listener
  307. * @param \Illuminate\Container\Container $container
  308. * @return callable
  309. */
  310. protected function createClassCallable($listener, $container)
  311. {
  312. list($class, $method) = $this->parseClassCallable($listener);
  313. if ($this->handlerShouldBeQueued($class)) {
  314. return $this->createQueuedHandlerCallable($class, $method);
  315. } else {
  316. return [$container->make($class), $method];
  317. }
  318. }
  319. /**
  320. * Parse the class listener into class and method.
  321. *
  322. * @param string $listener
  323. * @return array
  324. */
  325. protected function parseClassCallable($listener)
  326. {
  327. $segments = explode('@', $listener);
  328. return [$segments[0], count($segments) == 2 ? $segments[1] : 'handle'];
  329. }
  330. /**
  331. * Determine if the event handler class should be queued.
  332. *
  333. * @param string $class
  334. * @return bool
  335. */
  336. protected function handlerShouldBeQueued($class)
  337. {
  338. try {
  339. return (new ReflectionClass($class))->implementsInterface(
  340. 'Illuminate\Contracts\Queue\ShouldQueue'
  341. );
  342. } catch (Exception $e) {
  343. return false;
  344. }
  345. }
  346. /**
  347. * Create a callable for putting an event handler on the queue.
  348. *
  349. * @param string $class
  350. * @param string $method
  351. * @return \Closure
  352. */
  353. protected function createQueuedHandlerCallable($class, $method)
  354. {
  355. return function () use ($class, $method) {
  356. $arguments = $this->cloneArgumentsForQueueing(func_get_args());
  357. if (method_exists($class, 'queue')) {
  358. $this->callQueueMethodOnHandler($class, $method, $arguments);
  359. } else {
  360. $this->resolveQueue()->push('Illuminate\Events\CallQueuedHandler@call', [
  361. 'class' => $class, 'method' => $method, 'data' => serialize($arguments),
  362. ]);
  363. }
  364. };
  365. }
  366. /**
  367. * Clone the given arguments for queueing.
  368. *
  369. * @param array $arguments
  370. * @return array
  371. */
  372. protected function cloneArgumentsForQueueing(array $arguments)
  373. {
  374. return array_map(function ($a) {
  375. return is_object($a) ? clone $a : $a;
  376. }, $arguments);
  377. }
  378. /**
  379. * Call the queue method on the handler class.
  380. *
  381. * @param string $class
  382. * @param string $method
  383. * @param array $arguments
  384. * @return void
  385. */
  386. protected function callQueueMethodOnHandler($class, $method, $arguments)
  387. {
  388. $handler = (new ReflectionClass($class))->newInstanceWithoutConstructor();
  389. $handler->queue($this->resolveQueue(), 'Illuminate\Events\CallQueuedHandler@call', [
  390. 'class' => $class, 'method' => $method, 'data' => serialize($arguments),
  391. ]);
  392. }
  393. /**
  394. * Remove a set of listeners from the dispatcher.
  395. *
  396. * @param string $event
  397. * @return void
  398. */
  399. public function forget($event)
  400. {
  401. unset($this->listeners[$event], $this->sorted[$event]);
  402. }
  403. /**
  404. * Forget all of the pushed listeners.
  405. *
  406. * @return void
  407. */
  408. public function forgetPushed()
  409. {
  410. foreach ($this->listeners as $key => $value) {
  411. if (Str::endsWith($key, '_pushed')) {
  412. $this->forget($key);
  413. }
  414. }
  415. }
  416. /**
  417. * Get the queue implementation from the resolver.
  418. *
  419. * @return \Illuminate\Contracts\Queue\Queue
  420. */
  421. protected function resolveQueue()
  422. {
  423. return call_user_func($this->queueResolver);
  424. }
  425. /**
  426. * Set the queue resolver implementation.
  427. *
  428. * @param callable $resolver
  429. * @return $this
  430. */
  431. public function setQueueResolver(callable $resolver)
  432. {
  433. $this->queueResolver = $resolver;
  434. return $this;
  435. }
  436. }