Facade.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. <?php
  2. namespace Illuminate\Support\Facades;
  3. use Closure;
  4. use Illuminate\Database\Eloquent\Model;
  5. use Illuminate\Support\Arr;
  6. use Illuminate\Support\Benchmark;
  7. use Illuminate\Support\Collection;
  8. use Illuminate\Support\Js;
  9. use Illuminate\Support\Number;
  10. use Illuminate\Support\Str;
  11. use Illuminate\Support\Testing\Fakes\Fake;
  12. use Illuminate\Support\Uri;
  13. use Mockery;
  14. use Mockery\LegacyMockInterface;
  15. use RuntimeException;
  16. abstract class Facade
  17. {
  18. /**
  19. * The application instance being facaded.
  20. *
  21. * @var \Illuminate\Contracts\Foundation\Application|null
  22. */
  23. protected static $app;
  24. /**
  25. * The resolved object instances.
  26. *
  27. * @var array
  28. */
  29. protected static $resolvedInstance;
  30. /**
  31. * Indicates if the resolved instance should be cached.
  32. *
  33. * @var bool
  34. */
  35. protected static $cached = true;
  36. /**
  37. * Run a Closure when the facade has been resolved.
  38. *
  39. * @param \Closure $callback
  40. * @return void
  41. */
  42. public static function resolved(Closure $callback)
  43. {
  44. $accessor = static::getFacadeAccessor();
  45. if (static::$app->resolved($accessor) === true) {
  46. $callback(static::getFacadeRoot(), static::$app);
  47. }
  48. static::$app->afterResolving($accessor, function ($service, $app) use ($callback) {
  49. $callback($service, $app);
  50. });
  51. }
  52. /**
  53. * Convert the facade into a Mockery spy.
  54. *
  55. * @return \Mockery\MockInterface
  56. */
  57. public static function spy()
  58. {
  59. if (! static::isMock()) {
  60. $class = static::getMockableClass();
  61. return tap($class ? Mockery::spy($class) : Mockery::spy(), function ($spy) {
  62. static::swap($spy);
  63. });
  64. }
  65. }
  66. /**
  67. * Initiate a partial mock on the facade.
  68. *
  69. * @return \Mockery\MockInterface
  70. */
  71. public static function partialMock()
  72. {
  73. $name = static::getFacadeAccessor();
  74. $mock = static::isMock()
  75. ? static::$resolvedInstance[$name]
  76. : static::createFreshMockInstance();
  77. return $mock->makePartial();
  78. }
  79. /**
  80. * Initiate a mock expectation on the facade.
  81. *
  82. * @return \Mockery\Expectation
  83. */
  84. public static function shouldReceive()
  85. {
  86. $name = static::getFacadeAccessor();
  87. $mock = static::isMock()
  88. ? static::$resolvedInstance[$name]
  89. : static::createFreshMockInstance();
  90. return $mock->shouldReceive(...func_get_args());
  91. }
  92. /**
  93. * Initiate a mock expectation on the facade.
  94. *
  95. * @return \Mockery\Expectation
  96. */
  97. public static function expects()
  98. {
  99. $name = static::getFacadeAccessor();
  100. $mock = static::isMock()
  101. ? static::$resolvedInstance[$name]
  102. : static::createFreshMockInstance();
  103. return $mock->expects(...func_get_args());
  104. }
  105. /**
  106. * Create a fresh mock instance for the given class.
  107. *
  108. * @return \Mockery\MockInterface
  109. */
  110. protected static function createFreshMockInstance()
  111. {
  112. return tap(static::createMock(), function ($mock) {
  113. static::swap($mock);
  114. $mock->shouldAllowMockingProtectedMethods();
  115. });
  116. }
  117. /**
  118. * Create a fresh mock instance for the given class.
  119. *
  120. * @return \Mockery\MockInterface
  121. */
  122. protected static function createMock()
  123. {
  124. $class = static::getMockableClass();
  125. return $class ? Mockery::mock($class) : Mockery::mock();
  126. }
  127. /**
  128. * Determines whether a mock is set as the instance of the facade.
  129. *
  130. * @return bool
  131. */
  132. protected static function isMock()
  133. {
  134. $name = static::getFacadeAccessor();
  135. return isset(static::$resolvedInstance[$name]) &&
  136. static::$resolvedInstance[$name] instanceof LegacyMockInterface;
  137. }
  138. /**
  139. * Get the mockable class for the bound instance.
  140. *
  141. * @return string|null
  142. */
  143. protected static function getMockableClass()
  144. {
  145. if ($root = static::getFacadeRoot()) {
  146. return get_class($root);
  147. }
  148. }
  149. /**
  150. * Hotswap the underlying instance behind the facade.
  151. *
  152. * @param mixed $instance
  153. * @return void
  154. */
  155. public static function swap($instance)
  156. {
  157. static::$resolvedInstance[static::getFacadeAccessor()] = $instance;
  158. if (isset(static::$app)) {
  159. static::$app->instance(static::getFacadeAccessor(), $instance);
  160. }
  161. }
  162. /**
  163. * Determines whether a "fake" has been set as the facade instance.
  164. *
  165. * @return bool
  166. */
  167. public static function isFake()
  168. {
  169. $name = static::getFacadeAccessor();
  170. return isset(static::$resolvedInstance[$name]) &&
  171. static::$resolvedInstance[$name] instanceof Fake;
  172. }
  173. /**
  174. * Get the root object behind the facade.
  175. *
  176. * @return mixed
  177. */
  178. public static function getFacadeRoot()
  179. {
  180. return static::resolveFacadeInstance(static::getFacadeAccessor());
  181. }
  182. /**
  183. * Get the registered name of the component.
  184. *
  185. * @return string
  186. *
  187. * @throws \RuntimeException
  188. */
  189. protected static function getFacadeAccessor()
  190. {
  191. throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
  192. }
  193. /**
  194. * Resolve the facade root instance from the container.
  195. *
  196. * @param string $name
  197. * @return mixed
  198. */
  199. protected static function resolveFacadeInstance($name)
  200. {
  201. if (isset(static::$resolvedInstance[$name])) {
  202. return static::$resolvedInstance[$name];
  203. }
  204. if (static::$app) {
  205. if (static::$cached) {
  206. return static::$resolvedInstance[$name] = static::$app[$name];
  207. }
  208. return static::$app[$name];
  209. }
  210. }
  211. /**
  212. * Clear a resolved facade instance.
  213. *
  214. * @param string $name
  215. * @return void
  216. */
  217. public static function clearResolvedInstance($name)
  218. {
  219. unset(static::$resolvedInstance[$name]);
  220. }
  221. /**
  222. * Clear all of the resolved instances.
  223. *
  224. * @return void
  225. */
  226. public static function clearResolvedInstances()
  227. {
  228. static::$resolvedInstance = [];
  229. }
  230. /**
  231. * Get the application default aliases.
  232. *
  233. * @return \Illuminate\Support\Collection
  234. */
  235. public static function defaultAliases()
  236. {
  237. return new Collection([
  238. 'App' => App::class,
  239. 'Arr' => Arr::class,
  240. 'Artisan' => Artisan::class,
  241. 'Auth' => Auth::class,
  242. 'Benchmark' => Benchmark::class,
  243. 'Blade' => Blade::class,
  244. 'Broadcast' => Broadcast::class,
  245. 'Bus' => Bus::class,
  246. 'Cache' => Cache::class,
  247. 'Concurrency' => Concurrency::class,
  248. 'Config' => Config::class,
  249. 'Context' => Context::class,
  250. 'Cookie' => Cookie::class,
  251. 'Crypt' => Crypt::class,
  252. 'Date' => Date::class,
  253. 'DB' => DB::class,
  254. 'Eloquent' => Model::class,
  255. 'Event' => Event::class,
  256. 'File' => File::class,
  257. 'Gate' => Gate::class,
  258. 'Hash' => Hash::class,
  259. 'Http' => Http::class,
  260. 'Js' => Js::class,
  261. 'Lang' => Lang::class,
  262. 'Log' => Log::class,
  263. 'Mail' => Mail::class,
  264. 'Notification' => Notification::class,
  265. 'Number' => Number::class,
  266. 'Password' => Password::class,
  267. 'Process' => Process::class,
  268. 'Queue' => Queue::class,
  269. 'RateLimiter' => RateLimiter::class,
  270. 'Redirect' => Redirect::class,
  271. 'Request' => Request::class,
  272. 'Response' => Response::class,
  273. 'Route' => Route::class,
  274. 'Schedule' => Schedule::class,
  275. 'Schema' => Schema::class,
  276. 'Session' => Session::class,
  277. 'Storage' => Storage::class,
  278. 'Str' => Str::class,
  279. 'Uri' => Uri::class,
  280. 'URL' => URL::class,
  281. 'Validator' => Validator::class,
  282. 'View' => View::class,
  283. 'Vite' => Vite::class,
  284. ]);
  285. }
  286. /**
  287. * Get the application instance behind the facade.
  288. *
  289. * @return \Illuminate\Contracts\Foundation\Application|null
  290. */
  291. public static function getFacadeApplication()
  292. {
  293. return static::$app;
  294. }
  295. /**
  296. * Set the application instance.
  297. *
  298. * @param \Illuminate\Contracts\Foundation\Application|null $app
  299. * @return void
  300. */
  301. public static function setFacadeApplication($app)
  302. {
  303. static::$app = $app;
  304. }
  305. /**
  306. * Handle dynamic, static calls to the object.
  307. *
  308. * @param string $method
  309. * @param array $args
  310. * @return mixed
  311. *
  312. * @throws \RuntimeException
  313. */
  314. public static function __callStatic($method, $args)
  315. {
  316. $instance = static::getFacadeRoot();
  317. if (! $instance) {
  318. throw new RuntimeException('A facade root has not been set.');
  319. }
  320. return $instance->$method(...$args);
  321. }
  322. }