/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php

https://gitlab.com/madwanz64/laravel · PHP · 415 lines · 186 code · 48 blank · 181 comment · 12 complexity · a00a9cb5595c0e0bed583aa36cba3729 MD5 · raw file

  1. <?php
  2. namespace Illuminate\Database\Eloquent\Concerns;
  3. use Illuminate\Contracts\Events\Dispatcher;
  4. use Illuminate\Events\NullDispatcher;
  5. use Illuminate\Support\Arr;
  6. use InvalidArgumentException;
  7. trait HasEvents
  8. {
  9. /**
  10. * The event map for the model.
  11. *
  12. * Allows for object-based events for native Eloquent events.
  13. *
  14. * @var array
  15. */
  16. protected $dispatchesEvents = [];
  17. /**
  18. * User exposed observable events.
  19. *
  20. * These are extra user-defined events observers may subscribe to.
  21. *
  22. * @var array
  23. */
  24. protected $observables = [];
  25. /**
  26. * Register observers with the model.
  27. *
  28. * @param object|array|string $classes
  29. * @return void
  30. *
  31. * @throws \RuntimeException
  32. */
  33. public static function observe($classes)
  34. {
  35. $instance = new static;
  36. foreach (Arr::wrap($classes) as $class) {
  37. $instance->registerObserver($class);
  38. }
  39. }
  40. /**
  41. * Register a single observer with the model.
  42. *
  43. * @param object|string $class
  44. * @return void
  45. *
  46. * @throws \RuntimeException
  47. */
  48. protected function registerObserver($class)
  49. {
  50. $className = $this->resolveObserverClassName($class);
  51. // When registering a model observer, we will spin through the possible events
  52. // and determine if this observer has that method. If it does, we will hook
  53. // it into the model's event system, making it convenient to watch these.
  54. foreach ($this->getObservableEvents() as $event) {
  55. if (method_exists($class, $event)) {
  56. static::registerModelEvent($event, $className.'@'.$event);
  57. }
  58. }
  59. }
  60. /**
  61. * Resolve the observer's class name from an object or string.
  62. *
  63. * @param object|string $class
  64. * @return string
  65. *
  66. * @throws \InvalidArgumentException
  67. */
  68. private function resolveObserverClassName($class)
  69. {
  70. if (is_object($class)) {
  71. return get_class($class);
  72. }
  73. if (class_exists($class)) {
  74. return $class;
  75. }
  76. throw new InvalidArgumentException('Unable to find observer: '.$class);
  77. }
  78. /**
  79. * Get the observable event names.
  80. *
  81. * @return array
  82. */
  83. public function getObservableEvents()
  84. {
  85. return array_merge(
  86. [
  87. 'retrieved', 'creating', 'created', 'updating', 'updated',
  88. 'saving', 'saved', 'restoring', 'restored', 'replicating',
  89. 'deleting', 'deleted', 'forceDeleted',
  90. ],
  91. $this->observables
  92. );
  93. }
  94. /**
  95. * Set the observable event names.
  96. *
  97. * @param array $observables
  98. * @return $this
  99. */
  100. public function setObservableEvents(array $observables)
  101. {
  102. $this->observables = $observables;
  103. return $this;
  104. }
  105. /**
  106. * Add an observable event name.
  107. *
  108. * @param array|mixed $observables
  109. * @return void
  110. */
  111. public function addObservableEvents($observables)
  112. {
  113. $this->observables = array_unique(array_merge(
  114. $this->observables, is_array($observables) ? $observables : func_get_args()
  115. ));
  116. }
  117. /**
  118. * Remove an observable event name.
  119. *
  120. * @param array|mixed $observables
  121. * @return void
  122. */
  123. public function removeObservableEvents($observables)
  124. {
  125. $this->observables = array_diff(
  126. $this->observables, is_array($observables) ? $observables : func_get_args()
  127. );
  128. }
  129. /**
  130. * Register a model event with the dispatcher.
  131. *
  132. * @param string $event
  133. * @param \Closure|string $callback
  134. * @return void
  135. */
  136. protected static function registerModelEvent($event, $callback)
  137. {
  138. if (isset(static::$dispatcher)) {
  139. $name = static::class;
  140. static::$dispatcher->listen("eloquent.{$event}: {$name}", $callback);
  141. }
  142. }
  143. /**
  144. * Fire the given event for the model.
  145. *
  146. * @param string $event
  147. * @param bool $halt
  148. * @return mixed
  149. */
  150. protected function fireModelEvent($event, $halt = true)
  151. {
  152. if (! isset(static::$dispatcher)) {
  153. return true;
  154. }
  155. // First, we will get the proper method to call on the event dispatcher, and then we
  156. // will attempt to fire a custom, object based event for the given event. If that
  157. // returns a result we can return that result, or we'll call the string events.
  158. $method = $halt ? 'until' : 'dispatch';
  159. $result = $this->filterModelEventResults(
  160. $this->fireCustomModelEvent($event, $method)
  161. );
  162. if ($result === false) {
  163. return false;
  164. }
  165. return ! empty($result) ? $result : static::$dispatcher->{$method}(
  166. "eloquent.{$event}: ".static::class, $this
  167. );
  168. }
  169. /**
  170. * Fire a custom model event for the given event.
  171. *
  172. * @param string $event
  173. * @param string $method
  174. * @return mixed|null
  175. */
  176. protected function fireCustomModelEvent($event, $method)
  177. {
  178. if (! isset($this->dispatchesEvents[$event])) {
  179. return;
  180. }
  181. $result = static::$dispatcher->$method(new $this->dispatchesEvents[$event]($this));
  182. if (! is_null($result)) {
  183. return $result;
  184. }
  185. }
  186. /**
  187. * Filter the model event results.
  188. *
  189. * @param mixed $result
  190. * @return mixed
  191. */
  192. protected function filterModelEventResults($result)
  193. {
  194. if (is_array($result)) {
  195. $result = array_filter($result, function ($response) {
  196. return ! is_null($response);
  197. });
  198. }
  199. return $result;
  200. }
  201. /**
  202. * Register a retrieved model event with the dispatcher.
  203. *
  204. * @param \Closure|string $callback
  205. * @return void
  206. */
  207. public static function retrieved($callback)
  208. {
  209. static::registerModelEvent('retrieved', $callback);
  210. }
  211. /**
  212. * Register a saving model event with the dispatcher.
  213. *
  214. * @param \Closure|string $callback
  215. * @return void
  216. */
  217. public static function saving($callback)
  218. {
  219. static::registerModelEvent('saving', $callback);
  220. }
  221. /**
  222. * Register a saved model event with the dispatcher.
  223. *
  224. * @param \Closure|string $callback
  225. * @return void
  226. */
  227. public static function saved($callback)
  228. {
  229. static::registerModelEvent('saved', $callback);
  230. }
  231. /**
  232. * Register an updating model event with the dispatcher.
  233. *
  234. * @param \Closure|string $callback
  235. * @return void
  236. */
  237. public static function updating($callback)
  238. {
  239. static::registerModelEvent('updating', $callback);
  240. }
  241. /**
  242. * Register an updated model event with the dispatcher.
  243. *
  244. * @param \Closure|string $callback
  245. * @return void
  246. */
  247. public static function updated($callback)
  248. {
  249. static::registerModelEvent('updated', $callback);
  250. }
  251. /**
  252. * Register a creating model event with the dispatcher.
  253. *
  254. * @param \Closure|string $callback
  255. * @return void
  256. */
  257. public static function creating($callback)
  258. {
  259. static::registerModelEvent('creating', $callback);
  260. }
  261. /**
  262. * Register a created model event with the dispatcher.
  263. *
  264. * @param \Closure|string $callback
  265. * @return void
  266. */
  267. public static function created($callback)
  268. {
  269. static::registerModelEvent('created', $callback);
  270. }
  271. /**
  272. * Register a replicating model event with the dispatcher.
  273. *
  274. * @param \Closure|string $callback
  275. * @return void
  276. */
  277. public static function replicating($callback)
  278. {
  279. static::registerModelEvent('replicating', $callback);
  280. }
  281. /**
  282. * Register a deleting model event with the dispatcher.
  283. *
  284. * @param \Closure|string $callback
  285. * @return void
  286. */
  287. public static function deleting($callback)
  288. {
  289. static::registerModelEvent('deleting', $callback);
  290. }
  291. /**
  292. * Register a deleted model event with the dispatcher.
  293. *
  294. * @param \Closure|string $callback
  295. * @return void
  296. */
  297. public static function deleted($callback)
  298. {
  299. static::registerModelEvent('deleted', $callback);
  300. }
  301. /**
  302. * Remove all of the event listeners for the model.
  303. *
  304. * @return void
  305. */
  306. public static function flushEventListeners()
  307. {
  308. if (! isset(static::$dispatcher)) {
  309. return;
  310. }
  311. $instance = new static;
  312. foreach ($instance->getObservableEvents() as $event) {
  313. static::$dispatcher->forget("eloquent.{$event}: ".static::class);
  314. }
  315. foreach (array_values($instance->dispatchesEvents) as $event) {
  316. static::$dispatcher->forget($event);
  317. }
  318. }
  319. /**
  320. * Get the event dispatcher instance.
  321. *
  322. * @return \Illuminate\Contracts\Events\Dispatcher
  323. */
  324. public static function getEventDispatcher()
  325. {
  326. return static::$dispatcher;
  327. }
  328. /**
  329. * Set the event dispatcher instance.
  330. *
  331. * @param \Illuminate\Contracts\Events\Dispatcher $dispatcher
  332. * @return void
  333. */
  334. public static function setEventDispatcher(Dispatcher $dispatcher)
  335. {
  336. static::$dispatcher = $dispatcher;
  337. }
  338. /**
  339. * Unset the event dispatcher for models.
  340. *
  341. * @return void
  342. */
  343. public static function unsetEventDispatcher()
  344. {
  345. static::$dispatcher = null;
  346. }
  347. /**
  348. * Execute a callback without firing any model events for any model type.
  349. *
  350. * @param callable $callback
  351. * @return mixed
  352. */
  353. public static function withoutEvents(callable $callback)
  354. {
  355. $dispatcher = static::getEventDispatcher();
  356. if ($dispatcher) {
  357. static::setEventDispatcher(new NullDispatcher($dispatcher));
  358. }
  359. try {
  360. return $callback();
  361. } finally {
  362. if ($dispatcher) {
  363. static::setEventDispatcher($dispatcher);
  364. }
  365. }
  366. }
  367. }