BusFake.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. <?php
  2. namespace Illuminate\Support\Testing\Fakes;
  3. use Closure;
  4. use Illuminate\Bus\BatchRepository;
  5. use Illuminate\Bus\ChainedBatch;
  6. use Illuminate\Bus\PendingBatch;
  7. use Illuminate\Contracts\Bus\QueueingDispatcher;
  8. use Illuminate\Support\Arr;
  9. use Illuminate\Support\Collection;
  10. use Illuminate\Support\Str;
  11. use Illuminate\Support\Traits\ReflectsClosures;
  12. use PHPUnit\Framework\Assert as PHPUnit;
  13. use RuntimeException;
  14. class BusFake implements Fake, QueueingDispatcher
  15. {
  16. use ReflectsClosures;
  17. /**
  18. * The original Bus dispatcher implementation.
  19. *
  20. * @var \Illuminate\Contracts\Bus\QueueingDispatcher
  21. */
  22. public $dispatcher;
  23. /**
  24. * The job types that should be intercepted instead of dispatched.
  25. *
  26. * @var array
  27. */
  28. protected $jobsToFake = [];
  29. /**
  30. * The job types that should be dispatched instead of faked.
  31. *
  32. * @var array
  33. */
  34. protected $jobsToDispatch = [];
  35. /**
  36. * The fake repository to track batched jobs.
  37. *
  38. * @var \Illuminate\Bus\BatchRepository
  39. */
  40. protected $batchRepository;
  41. /**
  42. * The commands that have been dispatched.
  43. *
  44. * @var array
  45. */
  46. protected $commands = [];
  47. /**
  48. * The commands that have been dispatched synchronously.
  49. *
  50. * @var array
  51. */
  52. protected $commandsSync = [];
  53. /**
  54. * The commands that have been dispatched after the response has been sent.
  55. *
  56. * @var array
  57. */
  58. protected $commandsAfterResponse = [];
  59. /**
  60. * The batches that have been dispatched.
  61. *
  62. * @var array
  63. */
  64. protected $batches = [];
  65. /**
  66. * Indicates if commands should be serialized and restored when pushed to the Bus.
  67. *
  68. * @var bool
  69. */
  70. protected bool $serializeAndRestore = false;
  71. /**
  72. * Create a new bus fake instance.
  73. *
  74. * @param \Illuminate\Contracts\Bus\QueueingDispatcher $dispatcher
  75. * @param array|string $jobsToFake
  76. * @param \Illuminate\Bus\BatchRepository|null $batchRepository
  77. */
  78. public function __construct(QueueingDispatcher $dispatcher, $jobsToFake = [], ?BatchRepository $batchRepository = null)
  79. {
  80. $this->dispatcher = $dispatcher;
  81. $this->jobsToFake = Arr::wrap($jobsToFake);
  82. $this->batchRepository = $batchRepository ?: new BatchRepositoryFake;
  83. }
  84. /**
  85. * Specify the jobs that should be dispatched instead of faked.
  86. *
  87. * @param array|string $jobsToDispatch
  88. * @return $this
  89. */
  90. public function except($jobsToDispatch)
  91. {
  92. $this->jobsToDispatch = array_merge($this->jobsToDispatch, Arr::wrap($jobsToDispatch));
  93. return $this;
  94. }
  95. /**
  96. * Assert if a job was dispatched based on a truth-test callback.
  97. *
  98. * @param string|\Closure $command
  99. * @param callable|int|null $callback
  100. * @return void
  101. */
  102. public function assertDispatched($command, $callback = null)
  103. {
  104. if ($command instanceof Closure) {
  105. [$command, $callback] = [$this->firstClosureParameterType($command), $command];
  106. }
  107. if (is_numeric($callback)) {
  108. return $this->assertDispatchedTimes($command, $callback);
  109. }
  110. PHPUnit::assertTrue(
  111. $this->dispatched($command, $callback)->count() > 0 ||
  112. $this->dispatchedAfterResponse($command, $callback)->count() > 0 ||
  113. $this->dispatchedSync($command, $callback)->count() > 0,
  114. "The expected [{$command}] job was not dispatched."
  115. );
  116. }
  117. /**
  118. * Assert if a job was pushed exactly once.
  119. *
  120. * @param string|\Closure $command
  121. * @param int $times
  122. * @return void
  123. */
  124. public function assertDispatchedOnce($command)
  125. {
  126. $this->assertDispatchedTimes($command, 1);
  127. }
  128. /**
  129. * Assert if a job was pushed a number of times.
  130. *
  131. * @param string|\Closure $command
  132. * @param int $times
  133. * @return void
  134. */
  135. public function assertDispatchedTimes($command, $times = 1)
  136. {
  137. $callback = null;
  138. if ($command instanceof Closure) {
  139. [$command, $callback] = [$this->firstClosureParameterType($command), $command];
  140. }
  141. $count = $this->dispatched($command, $callback)->count() +
  142. $this->dispatchedAfterResponse($command, $callback)->count() +
  143. $this->dispatchedSync($command, $callback)->count();
  144. PHPUnit::assertSame(
  145. $times, $count,
  146. sprintf(
  147. "The expected [{$command}] job was pushed {$count} %s instead of {$times} %s.",
  148. Str::plural('time', $count),
  149. Str::plural('time', $times)
  150. )
  151. );
  152. }
  153. /**
  154. * Determine if a job was dispatched based on a truth-test callback.
  155. *
  156. * @param string|\Closure $command
  157. * @param callable|null $callback
  158. * @return void
  159. */
  160. public function assertNotDispatched($command, $callback = null)
  161. {
  162. if ($command instanceof Closure) {
  163. [$command, $callback] = [$this->firstClosureParameterType($command), $command];
  164. }
  165. PHPUnit::assertTrue(
  166. $this->dispatched($command, $callback)->count() === 0 &&
  167. $this->dispatchedAfterResponse($command, $callback)->count() === 0 &&
  168. $this->dispatchedSync($command, $callback)->count() === 0,
  169. "The unexpected [{$command}] job was dispatched."
  170. );
  171. }
  172. /**
  173. * Assert that no jobs were dispatched.
  174. *
  175. * @return void
  176. */
  177. public function assertNothingDispatched()
  178. {
  179. $commandNames = implode("\n- ", array_keys($this->commands));
  180. PHPUnit::assertEmpty($this->commands, "The following jobs were dispatched unexpectedly:\n\n- $commandNames\n");
  181. }
  182. /**
  183. * Assert if a job was explicitly dispatched synchronously based on a truth-test callback.
  184. *
  185. * @param string|\Closure $command
  186. * @param callable|int|null $callback
  187. * @return void
  188. */
  189. public function assertDispatchedSync($command, $callback = null)
  190. {
  191. if ($command instanceof Closure) {
  192. [$command, $callback] = [$this->firstClosureParameterType($command), $command];
  193. }
  194. if (is_numeric($callback)) {
  195. return $this->assertDispatchedSyncTimes($command, $callback);
  196. }
  197. PHPUnit::assertTrue(
  198. $this->dispatchedSync($command, $callback)->count() > 0,
  199. "The expected [{$command}] job was not dispatched synchronously."
  200. );
  201. }
  202. /**
  203. * Assert if a job was pushed synchronously a number of times.
  204. *
  205. * @param string|\Closure $command
  206. * @param int $times
  207. * @return void
  208. */
  209. public function assertDispatchedSyncTimes($command, $times = 1)
  210. {
  211. $callback = null;
  212. if ($command instanceof Closure) {
  213. [$command, $callback] = [$this->firstClosureParameterType($command), $command];
  214. }
  215. $count = $this->dispatchedSync($command, $callback)->count();
  216. PHPUnit::assertSame(
  217. $times, $count,
  218. sprintf(
  219. "The expected [{$command}] job was synchronously pushed {$count} %s instead of {$times} %s.",
  220. Str::plural('time', $count),
  221. Str::plural('time', $times)
  222. )
  223. );
  224. }
  225. /**
  226. * Determine if a job was dispatched based on a truth-test callback.
  227. *
  228. * @param string|\Closure $command
  229. * @param callable|null $callback
  230. * @return void
  231. */
  232. public function assertNotDispatchedSync($command, $callback = null)
  233. {
  234. if ($command instanceof Closure) {
  235. [$command, $callback] = [$this->firstClosureParameterType($command), $command];
  236. }
  237. PHPUnit::assertCount(
  238. 0, $this->dispatchedSync($command, $callback),
  239. "The unexpected [{$command}] job was dispatched synchronously."
  240. );
  241. }
  242. /**
  243. * Assert if a job was dispatched after the response was sent based on a truth-test callback.
  244. *
  245. * @param string|\Closure $command
  246. * @param callable|int|null $callback
  247. * @return void
  248. */
  249. public function assertDispatchedAfterResponse($command, $callback = null)
  250. {
  251. if ($command instanceof Closure) {
  252. [$command, $callback] = [$this->firstClosureParameterType($command), $command];
  253. }
  254. if (is_numeric($callback)) {
  255. return $this->assertDispatchedAfterResponseTimes($command, $callback);
  256. }
  257. PHPUnit::assertTrue(
  258. $this->dispatchedAfterResponse($command, $callback)->count() > 0,
  259. "The expected [{$command}] job was not dispatched after sending the response."
  260. );
  261. }
  262. /**
  263. * Assert if a job was pushed after the response was sent a number of times.
  264. *
  265. * @param string|\Closure $command
  266. * @param int $times
  267. * @return void
  268. */
  269. public function assertDispatchedAfterResponseTimes($command, $times = 1)
  270. {
  271. $callback = null;
  272. if ($command instanceof Closure) {
  273. [$command, $callback] = [$this->firstClosureParameterType($command), $command];
  274. }
  275. $count = $this->dispatchedAfterResponse($command, $callback)->count();
  276. PHPUnit::assertSame(
  277. $times, $count,
  278. sprintf(
  279. "The expected [{$command}] job was pushed {$count} %s instead of {$times} %s.",
  280. Str::plural('time', $count),
  281. Str::plural('time', $times)
  282. )
  283. );
  284. }
  285. /**
  286. * Determine if a job was dispatched based on a truth-test callback.
  287. *
  288. * @param string|\Closure $command
  289. * @param callable|null $callback
  290. * @return void
  291. */
  292. public function assertNotDispatchedAfterResponse($command, $callback = null)
  293. {
  294. if ($command instanceof Closure) {
  295. [$command, $callback] = [$this->firstClosureParameterType($command), $command];
  296. }
  297. PHPUnit::assertCount(
  298. 0, $this->dispatchedAfterResponse($command, $callback),
  299. "The unexpected [{$command}] job was dispatched after sending the response."
  300. );
  301. }
  302. /**
  303. * Assert if a chain of jobs was dispatched.
  304. *
  305. * @param array $expectedChain
  306. * @return void
  307. */
  308. public function assertChained(array $expectedChain)
  309. {
  310. $command = $expectedChain[0];
  311. $expectedChain = array_slice($expectedChain, 1);
  312. $callback = null;
  313. if ($command instanceof Closure) {
  314. [$command, $callback] = [$this->firstClosureParameterType($command), $command];
  315. } elseif ($command instanceof ChainedBatchTruthTest) {
  316. $instance = $command;
  317. $command = ChainedBatch::class;
  318. $callback = fn ($job) => $instance($job->toPendingBatch());
  319. } elseif (! is_string($command)) {
  320. $instance = $command;
  321. $command = get_class($instance);
  322. $callback = function ($job) use ($instance) {
  323. return serialize($this->resetChainPropertiesToDefaults($job)) === serialize($instance);
  324. };
  325. }
  326. PHPUnit::assertTrue(
  327. $this->dispatched($command, $callback)->isNotEmpty(),
  328. "The expected [{$command}] job was not dispatched."
  329. );
  330. $this->assertDispatchedWithChainOfObjects($command, $expectedChain, $callback);
  331. }
  332. /**
  333. * Assert no chained jobs was dispatched.
  334. *
  335. * @return void
  336. */
  337. public function assertNothingChained()
  338. {
  339. $this->assertNothingDispatched();
  340. }
  341. /**
  342. * Reset the chain properties to their default values on the job.
  343. *
  344. * @param mixed $job
  345. * @return mixed
  346. */
  347. protected function resetChainPropertiesToDefaults($job)
  348. {
  349. return tap(clone $job, function ($job) {
  350. $job->chainConnection = null;
  351. $job->chainQueue = null;
  352. $job->chainCatchCallbacks = null;
  353. $job->chained = [];
  354. });
  355. }
  356. /**
  357. * Assert if a job was dispatched with an empty chain based on a truth-test callback.
  358. *
  359. * @param string|\Closure $command
  360. * @param callable|null $callback
  361. * @return void
  362. */
  363. public function assertDispatchedWithoutChain($command, $callback = null)
  364. {
  365. if ($command instanceof Closure) {
  366. [$command, $callback] = [$this->firstClosureParameterType($command), $command];
  367. }
  368. PHPUnit::assertTrue(
  369. $this->dispatched($command, $callback)->isNotEmpty(),
  370. "The expected [{$command}] job was not dispatched."
  371. );
  372. $this->assertDispatchedWithChainOfObjects($command, [], $callback);
  373. }
  374. /**
  375. * Assert if a job was dispatched with chained jobs based on a truth-test callback.
  376. *
  377. * @param string $command
  378. * @param array $expectedChain
  379. * @param callable|null $callback
  380. * @return void
  381. */
  382. protected function assertDispatchedWithChainOfObjects($command, $expectedChain, $callback)
  383. {
  384. $chain = $expectedChain;
  385. PHPUnit::assertTrue(
  386. $this->dispatched($command, $callback)->filter(function ($job) use ($chain) {
  387. if (count($chain) !== count($job->chained)) {
  388. return false;
  389. }
  390. foreach ($job->chained as $index => $serializedChainedJob) {
  391. if ($chain[$index] instanceof ChainedBatchTruthTest) {
  392. $chainedBatch = unserialize($serializedChainedJob);
  393. if (! $chainedBatch instanceof ChainedBatch ||
  394. ! $chain[$index]($chainedBatch->toPendingBatch())) {
  395. return false;
  396. }
  397. } elseif ($chain[$index] instanceof Closure) {
  398. [$expectedType, $callback] = [$this->firstClosureParameterType($chain[$index]), $chain[$index]];
  399. $chainedJob = unserialize($serializedChainedJob);
  400. if (! $chainedJob instanceof $expectedType) {
  401. throw new RuntimeException('The chained job was expected to be of type '.$expectedType.', '.$chainedJob::class.' chained.');
  402. }
  403. if (! $callback($chainedJob)) {
  404. return false;
  405. }
  406. } elseif (is_string($chain[$index])) {
  407. if ($chain[$index] != get_class(unserialize($serializedChainedJob))) {
  408. return false;
  409. }
  410. } elseif (serialize($chain[$index]) != $serializedChainedJob) {
  411. return false;
  412. }
  413. }
  414. return true;
  415. })->isNotEmpty(),
  416. 'The expected chain was not dispatched.'
  417. );
  418. }
  419. /**
  420. * Create a new assertion about a chained batch.
  421. *
  422. * @param \Closure $callback
  423. * @return \Illuminate\Support\Testing\Fakes\ChainedBatchTruthTest
  424. */
  425. public function chainedBatch(Closure $callback)
  426. {
  427. return new ChainedBatchTruthTest($callback);
  428. }
  429. /**
  430. * Assert if a batch was dispatched based on a truth-test callback.
  431. *
  432. * @param callable $callback
  433. * @return void
  434. */
  435. public function assertBatched(callable $callback)
  436. {
  437. PHPUnit::assertTrue(
  438. $this->batched($callback)->count() > 0,
  439. 'The expected batch was not dispatched.'
  440. );
  441. }
  442. /**
  443. * Assert the number of batches that have been dispatched.
  444. *
  445. * @param int $count
  446. * @return void
  447. */
  448. public function assertBatchCount($count)
  449. {
  450. PHPUnit::assertCount(
  451. $count, $this->batches,
  452. );
  453. }
  454. /**
  455. * Assert that no batched jobs were dispatched.
  456. *
  457. * @return void
  458. */
  459. public function assertNothingBatched()
  460. {
  461. $jobNames = (new Collection($this->batches))
  462. ->map(fn ($batch) => $batch->jobs->map(fn ($job) => get_class($job)))
  463. ->flatten()
  464. ->join("\n- ");
  465. PHPUnit::assertEmpty($this->batches, "The following batched jobs were dispatched unexpectedly:\n\n- $jobNames\n");
  466. }
  467. /**
  468. * Assert that no jobs were dispatched, chained, or batched.
  469. *
  470. * @return void
  471. */
  472. public function assertNothingPlaced()
  473. {
  474. $this->assertNothingDispatched();
  475. $this->assertNothingBatched();
  476. }
  477. /**
  478. * Get all of the jobs matching a truth-test callback.
  479. *
  480. * @param string $command
  481. * @param callable|null $callback
  482. * @return \Illuminate\Support\Collection
  483. */
  484. public function dispatched($command, $callback = null)
  485. {
  486. if (! $this->hasDispatched($command)) {
  487. return new Collection;
  488. }
  489. $callback = $callback ?: fn () => true;
  490. return (new Collection($this->commands[$command]))->filter(fn ($command) => $callback($command));
  491. }
  492. /**
  493. * Get all of the jobs dispatched synchronously matching a truth-test callback.
  494. *
  495. * @param string $command
  496. * @param callable|null $callback
  497. * @return \Illuminate\Support\Collection
  498. */
  499. public function dispatchedSync(string $command, $callback = null)
  500. {
  501. if (! $this->hasDispatchedSync($command)) {
  502. return new Collection;
  503. }
  504. $callback = $callback ?: fn () => true;
  505. return (new Collection($this->commandsSync[$command]))->filter(fn ($command) => $callback($command));
  506. }
  507. /**
  508. * Get all of the jobs dispatched after the response was sent matching a truth-test callback.
  509. *
  510. * @param string $command
  511. * @param callable|null $callback
  512. * @return \Illuminate\Support\Collection
  513. */
  514. public function dispatchedAfterResponse(string $command, $callback = null)
  515. {
  516. if (! $this->hasDispatchedAfterResponse($command)) {
  517. return new Collection;
  518. }
  519. $callback = $callback ?: fn () => true;
  520. return (new Collection($this->commandsAfterResponse[$command]))->filter(fn ($command) => $callback($command));
  521. }
  522. /**
  523. * Get all of the pending batches matching a truth-test callback.
  524. *
  525. * @param callable $callback
  526. * @return \Illuminate\Support\Collection
  527. */
  528. public function batched(callable $callback)
  529. {
  530. if (empty($this->batches)) {
  531. return new Collection;
  532. }
  533. return (new Collection($this->batches))->filter(fn ($batch) => $callback($batch));
  534. }
  535. /**
  536. * Determine if there are any stored commands for a given class.
  537. *
  538. * @param string $command
  539. * @return bool
  540. */
  541. public function hasDispatched($command)
  542. {
  543. return isset($this->commands[$command]) && ! empty($this->commands[$command]);
  544. }
  545. /**
  546. * Determine if there are any stored commands for a given class.
  547. *
  548. * @param string $command
  549. * @return bool
  550. */
  551. public function hasDispatchedSync($command)
  552. {
  553. return isset($this->commandsSync[$command]) && ! empty($this->commandsSync[$command]);
  554. }
  555. /**
  556. * Determine if there are any stored commands for a given class.
  557. *
  558. * @param string $command
  559. * @return bool
  560. */
  561. public function hasDispatchedAfterResponse($command)
  562. {
  563. return isset($this->commandsAfterResponse[$command]) && ! empty($this->commandsAfterResponse[$command]);
  564. }
  565. /**
  566. * Dispatch a command to its appropriate handler.
  567. *
  568. * @param mixed $command
  569. * @return mixed
  570. */
  571. public function dispatch($command)
  572. {
  573. if ($this->shouldFakeJob($command)) {
  574. $this->commands[get_class($command)][] = $this->getCommandRepresentation($command);
  575. } else {
  576. return $this->dispatcher->dispatch($command);
  577. }
  578. }
  579. /**
  580. * Dispatch a command to its appropriate handler in the current process.
  581. *
  582. * Queueable jobs will be dispatched to the "sync" queue.
  583. *
  584. * @param mixed $command
  585. * @param mixed $handler
  586. * @return mixed
  587. */
  588. public function dispatchSync($command, $handler = null)
  589. {
  590. if ($this->shouldFakeJob($command)) {
  591. $this->commandsSync[get_class($command)][] = $this->getCommandRepresentation($command);
  592. } else {
  593. return $this->dispatcher->dispatchSync($command, $handler);
  594. }
  595. }
  596. /**
  597. * Dispatch a command to its appropriate handler in the current process.
  598. *
  599. * @param mixed $command
  600. * @param mixed $handler
  601. * @return mixed
  602. */
  603. public function dispatchNow($command, $handler = null)
  604. {
  605. if ($this->shouldFakeJob($command)) {
  606. $this->commands[get_class($command)][] = $this->getCommandRepresentation($command);
  607. } else {
  608. return $this->dispatcher->dispatchNow($command, $handler);
  609. }
  610. }
  611. /**
  612. * Dispatch a command to its appropriate handler behind a queue.
  613. *
  614. * @param mixed $command
  615. * @return mixed
  616. */
  617. public function dispatchToQueue($command)
  618. {
  619. if ($this->shouldFakeJob($command)) {
  620. $this->commands[get_class($command)][] = $this->getCommandRepresentation($command);
  621. } else {
  622. return $this->dispatcher->dispatchToQueue($command);
  623. }
  624. }
  625. /**
  626. * Dispatch a command to its appropriate handler.
  627. *
  628. * @param mixed $command
  629. * @return mixed
  630. */
  631. public function dispatchAfterResponse($command)
  632. {
  633. if ($this->shouldFakeJob($command)) {
  634. $this->commandsAfterResponse[get_class($command)][] = $this->getCommandRepresentation($command);
  635. } else {
  636. return $this->dispatcher->dispatch($command);
  637. }
  638. }
  639. /**
  640. * Create a new chain of queueable jobs.
  641. *
  642. * @param \Illuminate\Support\Collection|array|null $jobs
  643. * @return \Illuminate\Foundation\Bus\PendingChain
  644. */
  645. public function chain($jobs = null)
  646. {
  647. $jobs = Collection::wrap($jobs);
  648. $jobs = ChainedBatch::prepareNestedBatches($jobs);
  649. return new PendingChainFake($this, $jobs->shift(), $jobs->toArray());
  650. }
  651. /**
  652. * Attempt to find the batch with the given ID.
  653. *
  654. * @param string $batchId
  655. * @return \Illuminate\Bus\Batch|null
  656. */
  657. public function findBatch(string $batchId)
  658. {
  659. return $this->batchRepository->find($batchId);
  660. }
  661. /**
  662. * Create a new batch of queueable jobs.
  663. *
  664. * @param \Illuminate\Support\Collection|array $jobs
  665. * @return \Illuminate\Bus\PendingBatch
  666. */
  667. public function batch($jobs)
  668. {
  669. return new PendingBatchFake($this, Collection::wrap($jobs));
  670. }
  671. /**
  672. * Dispatch an empty job batch for testing.
  673. *
  674. * @param string $name
  675. * @return \Illuminate\Bus\Batch
  676. */
  677. public function dispatchFakeBatch($name = '')
  678. {
  679. return $this->batch([])->name($name)->dispatch();
  680. }
  681. /**
  682. * Record the fake pending batch dispatch.
  683. *
  684. * @param \Illuminate\Bus\PendingBatch $pendingBatch
  685. * @return \Illuminate\Bus\Batch
  686. */
  687. public function recordPendingBatch(PendingBatch $pendingBatch)
  688. {
  689. $this->batches[] = $pendingBatch;
  690. return $this->batchRepository->store($pendingBatch);
  691. }
  692. /**
  693. * Determine if a command should be faked or actually dispatched.
  694. *
  695. * @param mixed $command
  696. * @return bool
  697. */
  698. protected function shouldFakeJob($command)
  699. {
  700. if ($this->shouldDispatchCommand($command)) {
  701. return false;
  702. }
  703. if (empty($this->jobsToFake)) {
  704. return true;
  705. }
  706. return (new Collection($this->jobsToFake))
  707. ->filter(function ($job) use ($command) {
  708. return $job instanceof Closure
  709. ? $job($command)
  710. : $job === get_class($command);
  711. })->isNotEmpty();
  712. }
  713. /**
  714. * Determine if a command should be dispatched or not.
  715. *
  716. * @param mixed $command
  717. * @return bool
  718. */
  719. protected function shouldDispatchCommand($command)
  720. {
  721. return (new Collection($this->jobsToDispatch))
  722. ->filter(function ($job) use ($command) {
  723. return $job instanceof Closure
  724. ? $job($command)
  725. : $job === get_class($command);
  726. })->isNotEmpty();
  727. }
  728. /**
  729. * Specify if commands should be serialized and restored when being batched.
  730. *
  731. * @param bool $serializeAndRestore
  732. * @return $this
  733. */
  734. public function serializeAndRestore(bool $serializeAndRestore = true)
  735. {
  736. $this->serializeAndRestore = $serializeAndRestore;
  737. return $this;
  738. }
  739. /**
  740. * Serialize and unserialize the command to simulate the queueing process.
  741. *
  742. * @param mixed $command
  743. * @return mixed
  744. */
  745. protected function serializeAndRestoreCommand($command)
  746. {
  747. return unserialize(serialize($command));
  748. }
  749. /**
  750. * Return the command representation that should be stored.
  751. *
  752. * @param mixed $command
  753. * @return mixed
  754. */
  755. protected function getCommandRepresentation($command)
  756. {
  757. return $this->serializeAndRestore ? $this->serializeAndRestoreCommand($command) : $command;
  758. }
  759. /**
  760. * Set the pipes commands should be piped through before dispatching.
  761. *
  762. * @param array $pipes
  763. * @return $this
  764. */
  765. public function pipeThrough(array $pipes)
  766. {
  767. $this->dispatcher->pipeThrough($pipes);
  768. return $this;
  769. }
  770. /**
  771. * Determine if the given command has a handler.
  772. *
  773. * @param mixed $command
  774. * @return bool
  775. */
  776. public function hasCommandHandler($command)
  777. {
  778. return $this->dispatcher->hasCommandHandler($command);
  779. }
  780. /**
  781. * Retrieve the handler for a command.
  782. *
  783. * @param mixed $command
  784. * @return mixed
  785. */
  786. public function getCommandHandler($command)
  787. {
  788. return $this->dispatcher->getCommandHandler($command);
  789. }
  790. /**
  791. * Map a command to a handler.
  792. *
  793. * @param array $map
  794. * @return $this
  795. */
  796. public function map(array $map)
  797. {
  798. $this->dispatcher->map($map);
  799. return $this;
  800. }
  801. /**
  802. * Get the batches that have been dispatched.
  803. *
  804. * @return array
  805. */
  806. public function dispatchedBatches()
  807. {
  808. return $this->batches;
  809. }
  810. }