ManagesEvents.php 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. <?php
  2. namespace Illuminate\View\Concerns;
  3. use Closure;
  4. use Illuminate\Support\Str;
  5. use Illuminate\Contracts\View\View as ViewContract;
  6. trait ManagesEvents
  7. {
  8. /**
  9. * Register a view creator event.
  10. *
  11. * @param array|string $views
  12. * @param \Closure|string $callback
  13. * @return array
  14. */
  15. public function creator($views, $callback)
  16. {
  17. $creators = [];
  18. foreach ((array) $views as $view) {
  19. $creators[] = $this->addViewEvent($view, $callback, 'creating: ');
  20. }
  21. return $creators;
  22. }
  23. /**
  24. * Register multiple view composers via an array.
  25. *
  26. * @param array $composers
  27. * @return array
  28. */
  29. public function composers(array $composers)
  30. {
  31. $registered = [];
  32. foreach ($composers as $callback => $views) {
  33. $registered = array_merge($registered, $this->composer($views, $callback));
  34. }
  35. return $registered;
  36. }
  37. /**
  38. * Register a view composer event.
  39. *
  40. * @param array|string $views
  41. * @param \Closure|string $callback
  42. * @return array
  43. */
  44. public function composer($views, $callback)
  45. {
  46. $composers = [];
  47. foreach ((array) $views as $view) {
  48. $composers[] = $this->addViewEvent($view, $callback, 'composing: ');
  49. }
  50. return $composers;
  51. }
  52. /**
  53. * Add an event for a given view.
  54. *
  55. * @param string $view
  56. * @param \Closure|string $callback
  57. * @param string $prefix
  58. * @return \Closure|null
  59. */
  60. protected function addViewEvent($view, $callback, $prefix = 'composing: ')
  61. {
  62. $view = $this->normalizeName($view);
  63. if ($callback instanceof Closure) {
  64. $this->addEventListener($prefix.$view, $callback);
  65. return $callback;
  66. } elseif (is_string($callback)) {
  67. return $this->addClassEvent($view, $callback, $prefix);
  68. }
  69. }
  70. /**
  71. * Register a class based view composer.
  72. *
  73. * @param string $view
  74. * @param string $class
  75. * @param string $prefix
  76. * @return \Closure
  77. */
  78. protected function addClassEvent($view, $class, $prefix)
  79. {
  80. $name = $prefix.$view;
  81. // When registering a class based view "composer", we will simply resolve the
  82. // classes from the application IoC container then call the compose method
  83. // on the instance. This allows for convenient, testable view composers.
  84. $callback = $this->buildClassEventCallback(
  85. $class, $prefix
  86. );
  87. $this->addEventListener($name, $callback);
  88. return $callback;
  89. }
  90. /**
  91. * Build a class based container callback Closure.
  92. *
  93. * @param string $class
  94. * @param string $prefix
  95. * @return \Closure
  96. */
  97. protected function buildClassEventCallback($class, $prefix)
  98. {
  99. list($class, $method) = $this->parseClassEvent($class, $prefix);
  100. // Once we have the class and method name, we can build the Closure to resolve
  101. // the instance out of the IoC container and call the method on it with the
  102. // given arguments that are passed to the Closure as the composer's data.
  103. return function () use ($class, $method) {
  104. return call_user_func_array(
  105. [$this->container->make($class), $method], func_get_args()
  106. );
  107. };
  108. }
  109. /**
  110. * Parse a class based composer name.
  111. *
  112. * @param string $class
  113. * @param string $prefix
  114. * @return array
  115. */
  116. protected function parseClassEvent($class, $prefix)
  117. {
  118. return Str::parseCallback($class, $this->classEventMethodForPrefix($prefix));
  119. }
  120. /**
  121. * Determine the class event method based on the given prefix.
  122. *
  123. * @param string $prefix
  124. * @return string
  125. */
  126. protected function classEventMethodForPrefix($prefix)
  127. {
  128. return Str::contains($prefix, 'composing') ? 'compose' : 'create';
  129. }
  130. /**
  131. * Add a listener to the event dispatcher.
  132. *
  133. * @param string $name
  134. * @param \Closure $callback
  135. * @return void
  136. */
  137. protected function addEventListener($name, $callback)
  138. {
  139. if (Str::contains($name, '*')) {
  140. $callback = function ($name, array $data) use ($callback) {
  141. return $callback($data[0]);
  142. };
  143. }
  144. $this->events->listen($name, $callback);
  145. }
  146. /**
  147. * Call the composer for a given view.
  148. *
  149. * @param \Illuminate\Contracts\View\View $view
  150. * @return void
  151. */
  152. public function callComposer(ViewContract $view)
  153. {
  154. $this->events->dispatch('composing: '.$view->name(), [$view]);
  155. }
  156. /**
  157. * Call the creator for a given view.
  158. *
  159. * @param \Illuminate\Contracts\View\View $view
  160. * @return void
  161. */
  162. public function callCreator(ViewContract $view)
  163. {
  164. $this->events->dispatch('creating: '.$view->name(), [$view]);
  165. }
  166. }