Facade.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. <?php
  2. namespace Illuminate\Support\Facades;
  3. use Closure;
  4. use Mockery;
  5. use Mockery\LegacyMockInterface;
  6. use RuntimeException;
  7. abstract class Facade
  8. {
  9. /**
  10. * The application instance being facaded.
  11. *
  12. * @var \Illuminate\Contracts\Foundation\Application
  13. */
  14. protected static $app;
  15. /**
  16. * The resolved object instances.
  17. *
  18. * @var array
  19. */
  20. protected static $resolvedInstance;
  21. /**
  22. * Run a Closure when the facade has been resolved.
  23. *
  24. * @param \Closure $callback
  25. * @return void
  26. */
  27. public static function resolved(Closure $callback)
  28. {
  29. $accessor = static::getFacadeAccessor();
  30. if (static::$app->resolved($accessor) === true) {
  31. $callback(static::getFacadeRoot());
  32. }
  33. static::$app->afterResolving($accessor, function ($service) use ($callback) {
  34. $callback($service);
  35. });
  36. }
  37. /**
  38. * Convert the facade into a Mockery spy.
  39. *
  40. * @return \Mockery\MockInterface
  41. */
  42. public static function spy()
  43. {
  44. if (! static::isMock()) {
  45. $class = static::getMockableClass();
  46. return tap($class ? Mockery::spy($class) : Mockery::spy(), function ($spy) {
  47. static::swap($spy);
  48. });
  49. }
  50. }
  51. /**
  52. * Initiate a partial mock on the facade.
  53. *
  54. * @return \Mockery\MockInterface
  55. */
  56. public static function partialMock()
  57. {
  58. $name = static::getFacadeAccessor();
  59. $mock = static::isMock()
  60. ? static::$resolvedInstance[$name]
  61. : static::createFreshMockInstance();
  62. return $mock->makePartial();
  63. }
  64. /**
  65. * Initiate a mock expectation on the facade.
  66. *
  67. * @return \Mockery\Expectation
  68. */
  69. public static function shouldReceive()
  70. {
  71. $name = static::getFacadeAccessor();
  72. $mock = static::isMock()
  73. ? static::$resolvedInstance[$name]
  74. : static::createFreshMockInstance();
  75. return $mock->shouldReceive(...func_get_args());
  76. }
  77. /**
  78. * Create a fresh mock instance for the given class.
  79. *
  80. * @return \Mockery\MockInterface
  81. */
  82. protected static function createFreshMockInstance()
  83. {
  84. return tap(static::createMock(), function ($mock) {
  85. static::swap($mock);
  86. $mock->shouldAllowMockingProtectedMethods();
  87. });
  88. }
  89. /**
  90. * Create a fresh mock instance for the given class.
  91. *
  92. * @return \Mockery\MockInterface
  93. */
  94. protected static function createMock()
  95. {
  96. $class = static::getMockableClass();
  97. return $class ? Mockery::mock($class) : Mockery::mock();
  98. }
  99. /**
  100. * Determines whether a mock is set as the instance of the facade.
  101. *
  102. * @return bool
  103. */
  104. protected static function isMock()
  105. {
  106. $name = static::getFacadeAccessor();
  107. return isset(static::$resolvedInstance[$name]) &&
  108. static::$resolvedInstance[$name] instanceof LegacyMockInterface;
  109. }
  110. /**
  111. * Get the mockable class for the bound instance.
  112. *
  113. * @return string|null
  114. */
  115. protected static function getMockableClass()
  116. {
  117. if ($root = static::getFacadeRoot()) {
  118. return get_class($root);
  119. }
  120. }
  121. /**
  122. * Hotswap the underlying instance behind the facade.
  123. *
  124. * @param mixed $instance
  125. * @return void
  126. */
  127. public static function swap($instance)
  128. {
  129. static::$resolvedInstance[static::getFacadeAccessor()] = $instance;
  130. if (isset(static::$app)) {
  131. static::$app->instance(static::getFacadeAccessor(), $instance);
  132. }
  133. }
  134. /**
  135. * Get the root object behind the facade.
  136. *
  137. * @return mixed
  138. */
  139. public static function getFacadeRoot()
  140. {
  141. return static::resolveFacadeInstance(static::getFacadeAccessor());
  142. }
  143. /**
  144. * Get the registered name of the component.
  145. *
  146. * @return string
  147. *
  148. * @throws \RuntimeException
  149. */
  150. protected static function getFacadeAccessor()
  151. {
  152. throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
  153. }
  154. /**
  155. * Resolve the facade root instance from the container.
  156. *
  157. * @param object|string $name
  158. * @return mixed
  159. */
  160. protected static function resolveFacadeInstance($name)
  161. {
  162. if (is_object($name)) {
  163. return $name;
  164. }
  165. if (isset(static::$resolvedInstance[$name])) {
  166. return static::$resolvedInstance[$name];
  167. }
  168. if (static::$app) {
  169. return static::$resolvedInstance[$name] = static::$app[$name];
  170. }
  171. }
  172. /**
  173. * Clear a resolved facade instance.
  174. *
  175. * @param string $name
  176. * @return void
  177. */
  178. public static function clearResolvedInstance($name)
  179. {
  180. unset(static::$resolvedInstance[$name]);
  181. }
  182. /**
  183. * Clear all of the resolved instances.
  184. *
  185. * @return void
  186. */
  187. public static function clearResolvedInstances()
  188. {
  189. static::$resolvedInstance = [];
  190. }
  191. /**
  192. * Get the application instance behind the facade.
  193. *
  194. * @return \Illuminate\Contracts\Foundation\Application
  195. */
  196. public static function getFacadeApplication()
  197. {
  198. return static::$app;
  199. }
  200. /**
  201. * Set the application instance.
  202. *
  203. * @param \Illuminate\Contracts\Foundation\Application $app
  204. * @return void
  205. */
  206. public static function setFacadeApplication($app)
  207. {
  208. static::$app = $app;
  209. }
  210. /**
  211. * Handle dynamic, static calls to the object.
  212. *
  213. * @param string $method
  214. * @param array $args
  215. * @return mixed
  216. *
  217. * @throws \RuntimeException
  218. */
  219. public static function __callStatic($method, $args)
  220. {
  221. $instance = static::getFacadeRoot();
  222. if (! $instance) {
  223. throw new RuntimeException('A facade root has not been set.');
  224. }
  225. return $instance->$method(...$args);
  226. }
  227. }