Batch.php000064400000025417147536114200006312 0ustar00queue = $queue; $this->repository = $repository; $this->id = $id; $this->name = $name; $this->totalJobs = $totalJobs; $this->pendingJobs = $pendingJobs; $this->failedJobs = $failedJobs; $this->failedJobIds = $failedJobIds; $this->options = $options; $this->createdAt = $createdAt; $this->cancelledAt = $cancelledAt; $this->finishedAt = $finishedAt; } /** * Get a fresh instance of the batch represented by this ID. * * @return self */ public function fresh() { return $this->repository->find($this->id); } /** * Add additional jobs to the batch. * * @param \Illuminate\Support\Collection|array $jobs * @return self */ public function add($jobs) { $jobs = Collection::wrap($jobs)->map(function ($job) { if ($job instanceof Closure) { $job = CallQueuedClosure::create($job); } $job->withBatchId($this->id); return $job; }); $this->repository->transaction(function () use ($jobs) { $this->repository->incrementTotalJobs($this->id, count($jobs)); $this->queue->connection($this->options['connection'] ?? null)->bulk( $jobs->all(), $data = '', $this->options['queue'] ?? null ); }); return $this->fresh(); } /** * Get the total number of jobs that have been processed by the batch thus far. * * @return int */ public function processedJobs() { return $this->totalJobs - $this->pendingJobs; } /** * Get the percentage of jobs that have been processed (between 0-100). * * @return int */ public function progress() { return $this->totalJobs > 0 ? round(($this->processedJobs() / $this->totalJobs) * 100) : 0; } /** * Record that a job within the batch finished successfully, executing any callbacks if necessary. * * @param string $jobId * @return void */ public function recordSuccessfulJob(string $jobId) { $counts = $this->decrementPendingJobs($jobId); if ($counts->pendingJobs === 0) { $this->repository->markAsFinished($this->id); } if ($counts->pendingJobs === 0 && $this->hasThenCallbacks()) { $batch = $this->fresh(); collect($this->options['then'])->each(function ($handler) use ($batch) { $this->invokeHandlerCallback($handler, $batch); }); } if ($counts->allJobsHaveRanExactlyOnce() && $this->hasFinallyCallbacks()) { $batch = $this->fresh(); collect($this->options['finally'])->each(function ($handler) use ($batch) { $this->invokeHandlerCallback($handler, $batch); }); } } /** * Decrement the pending jobs for the batch. * * @param string $jobId * @return \Illuminate\Bus\UpdatedBatchJobCounts */ public function decrementPendingJobs(string $jobId) { return $this->repository->decrementPendingJobs($this->id, $jobId); } /** * Determine if the batch has finished executing. * * @return bool */ public function finished() { return ! is_null($this->finishedAt); } /** * Determine if the batch has "success" callbacks. * * @return bool */ public function hasThenCallbacks() { return isset($this->options['then']) && ! empty($this->options['then']); } /** * Determine if the batch allows jobs to fail without cancelling the batch. * * @return bool */ public function allowsFailures() { return Arr::get($this->options, 'allowFailures', false) === true; } /** * Determine if the batch has job failures. * * @return bool */ public function hasFailures() { return $this->failedJobs > 0; } /** * Record that a job within the batch failed to finish successfully, executing any callbacks if necessary. * * @param string $jobId * @param \Throwable $e * @return void */ public function recordFailedJob(string $jobId, $e) { $counts = $this->incrementFailedJobs($jobId); if ($counts->failedJobs === 1 && ! $this->allowsFailures()) { $this->cancel(); } if ($counts->failedJobs === 1 && $this->hasCatchCallbacks()) { $batch = $this->fresh(); collect($this->options['catch'])->each(function ($handler) use ($batch, $e) { $this->invokeHandlerCallback($handler, $batch, $e); }); } if ($counts->allJobsHaveRanExactlyOnce() && $this->hasFinallyCallbacks()) { $batch = $this->fresh(); collect($this->options['finally'])->each(function ($handler) use ($batch, $e) { $this->invokeHandlerCallback($handler, $batch, $e); }); } } /** * Increment the failed jobs for the batch. * * @param string $jobId * @return \Illuminate\Bus\UpdatedBatchJobCounts */ public function incrementFailedJobs(string $jobId) { return $this->repository->incrementFailedJobs($this->id, $jobId); } /** * Determine if the batch has "catch" callbacks. * * @return bool */ public function hasCatchCallbacks() { return isset($this->options['catch']) && ! empty($this->options['catch']); } /** * Determine if the batch has "then" callbacks. * * @return bool */ public function hasFinallyCallbacks() { return isset($this->options['finally']) && ! empty($this->options['finally']); } /** * Cancel the batch. * * @return void */ public function cancel() { $this->repository->cancel($this->id); } /** * Determine if the batch has been cancelled. * * @return bool */ public function canceled() { return $this->cancelled(); } /** * Determine if the batch has been cancelled. * * @return bool */ public function cancelled() { return ! is_null($this->cancelledAt); } /** * Delete the batch from storage. * * @return void */ public function delete() { $this->repository->delete($this->id); } /** * Invoke a batch callback handler. * * @param \Illuminate\Queue\SerializableClosure|callable $handler * @param \Illuminate\Bus\Batch $batch * @param \Throwable|null $e * @return void */ protected function invokeHandlerCallback($handler, Batch $batch, Throwable $e = null) { return $handler instanceof SerializableClosure ? $handler->__invoke($batch, $e) : call_user_func($handler, $batch, $e); } /** * Convert the batch to an array. * * @return array */ public function toArray() { return [ 'id' => $this->id, 'name' => $this->name, 'totalJobs' => $this->totalJobs, 'pendingJobs' => $this->pendingJobs, 'processedJobs' => $this->processedJobs(), 'progress' => $this->progress(), 'failedJobs' => $this->failedJobs, 'options' => $this->options, 'createdAt' => $this->createdAt, 'cancelledAt' => $this->cancelledAt, 'finishedAt' => $this->finishedAt, ]; } /** * Get the JSON serializable representation of the object. * * @return array */ public function jsonSerialize() { return $this->toArray(); } } BatchFactory.php000064400000003324147536114200007633 0ustar00queue = $queue; } /** * Create a new batch instance. * * @param \Illuminate\Bus\BatchRepository $repository * @param string $id * @param string $name * @param int $totalJobs * @param int $pendingJobs * @param int $failedJobs * @param array $failedJobIds * @param array $options * @param \Carbon\CarbonImmutable $createdAt * @param \Carbon\CarbonImmutable|null $cancelledAt * @param \Carbon\CarbonImmutable|null $finishedAt * @return \Illuminate\Bus\Batch */ public function make(BatchRepository $repository, string $id, string $name, int $totalJobs, int $pendingJobs, int $failedJobs, array $failedJobIds, array $options, CarbonImmutable $createdAt, ?CarbonImmutable $cancelledAt, ?CarbonImmutable $finishedAt) { return new Batch($this->queue, $repository, $id, $name, $totalJobs, $pendingJobs, $failedJobs, $failedJobIds, $options, $createdAt, $cancelledAt, $finishedAt); } } BatchRepository.php000064400000004201147536114200010376 0ustar00batchId) { return Container::getInstance()->make(BatchRepository::class)->find($this->batchId); } } /** * Determine if the batch is still active and processing. * * @return bool */ public function batching() { $batch = $this->batch(); return $batch && ! $batch->cancelled(); } /** * Set the batch ID on the job. * * @param string $batchId * @return $this */ public function withBatchId(string $batchId) { $this->batchId = $batchId; return $this; } } BusServiceProvider.php000064400000003632147536114200011051 0ustar00app->singleton(Dispatcher::class, function ($app) { return new Dispatcher($app, function ($connection = null) use ($app) { return $app[QueueFactoryContract::class]->connection($connection); }); }); $this->registerBatchServices(); $this->app->alias( Dispatcher::class, DispatcherContract::class ); $this->app->alias( Dispatcher::class, QueueingDispatcherContract::class ); } /** * Register the batch handling services. * * @return void */ protected function registerBatchServices() { $this->app->singleton(BatchRepository::class, DatabaseBatchRepository::class); $this->app->singleton(DatabaseBatchRepository::class, function ($app) { return new DatabaseBatchRepository( $app->make(BatchFactory::class), $app->make('db')->connection(config('queue.batching.database')), config('queue.batching.table', 'job_batches'), ); }); } /** * Get the services provided by the provider. * * @return array */ public function provides() { return [ Dispatcher::class, DispatcherContract::class, QueueingDispatcherContract::class, BatchRepository::class, ]; } } DatabaseBatchRepository.php000064400000017315147536114200012035 0ustar00factory = $factory; $this->connection = $connection; $this->table = $table; } /** * Retrieve a list of batches. * * @param int $limit * @param mixed $before * @return \Illuminate\Bus\Batch[] */ public function get($limit = 50, $before = null) { return $this->connection->table($this->table) ->orderByDesc('id') ->take($limit) ->when($before, function ($q) use ($before) { return $q->where('id', '<', $before); }) ->get() ->map(function ($batch) { return $this->toBatch($batch); }) ->all(); } /** * Retrieve information about an existing batch. * * @param string $batchId * @return \Illuminate\Bus\Batch|null */ public function find(string $batchId) { $batch = $this->connection->table($this->table) ->where('id', $batchId) ->first(); if ($batch) { return $this->toBatch($batch); } } /** * Store a new pending batch. * * @param \Illuminate\Bus\PendingBatch $batch * @return \Illuminate\Bus\Batch */ public function store(PendingBatch $batch) { $id = (string) Str::orderedUuid(); $this->connection->table($this->table)->insert([ 'id' => $id, 'name' => $batch->name, 'total_jobs' => 0, 'pending_jobs' => 0, 'failed_jobs' => 0, 'failed_job_ids' => '[]', 'options' => serialize($batch->options), 'created_at' => time(), 'cancelled_at' => null, 'finished_at' => null, ]); return $this->find($id); } /** * Increment the total number of jobs within the batch. * * @param string $batchId * @param int $amount * @return void */ public function incrementTotalJobs(string $batchId, int $amount) { $this->connection->table($this->table)->where('id', $batchId)->update([ 'total_jobs' => new Expression('total_jobs + '.$amount), 'pending_jobs' => new Expression('pending_jobs + '.$amount), 'finished_at' => null, ]); } /** * Decrement the total number of pending jobs for the batch. * * @param string $batchId * @param string $jobId * @return \Illuminate\Bus\UpdatedBatchJobCounts */ public function decrementPendingJobs(string $batchId, string $jobId) { $values = $this->updateAtomicValues($batchId, function ($batch) use ($jobId) { return [ 'pending_jobs' => $batch->pending_jobs - 1, 'failed_jobs' => $batch->failed_jobs, 'failed_job_ids' => json_encode(array_values(array_diff(json_decode($batch->failed_job_ids, true), [$jobId]))), ]; }); return new UpdatedBatchJobCounts( $values['pending_jobs'], $values['failed_jobs'] ); } /** * Increment the total number of failed jobs for the batch. * * @param string $batchId * @param string $jobId * @return \Illuminate\Bus\UpdatedBatchJobCounts */ public function incrementFailedJobs(string $batchId, string $jobId) { $values = $this->updateAtomicValues($batchId, function ($batch) use ($jobId) { return [ 'pending_jobs' => $batch->pending_jobs, 'failed_jobs' => $batch->failed_jobs + 1, 'failed_job_ids' => json_encode(array_values(array_unique(array_merge(json_decode($batch->failed_job_ids, true), [$jobId])))), ]; }); return new UpdatedBatchJobCounts( $values['pending_jobs'], $values['failed_jobs'] ); } /** * Update an atomic value within the batch. * * @param string $batchId * @param \Closure $callback * @return int|null */ protected function updateAtomicValues(string $batchId, Closure $callback) { return $this->connection->transaction(function () use ($batchId, $callback) { $batch = $this->connection->table($this->table)->where('id', $batchId) ->lockForUpdate() ->first(); return is_null($batch) ? [] : tap($callback($batch), function ($values) use ($batchId) { $this->connection->table($this->table)->where('id', $batchId)->update($values); }); }); } /** * Mark the batch that has the given ID as finished. * * @param string $batchId * @return void */ public function markAsFinished(string $batchId) { $this->connection->table($this->table)->where('id', $batchId)->update([ 'finished_at' => time(), ]); } /** * Cancel the batch that has the given ID. * * @param string $batchId * @return void */ public function cancel(string $batchId) { $this->connection->table($this->table)->where('id', $batchId)->update([ 'cancelled_at' => time(), 'finished_at' => time(), ]); } /** * Delete the batch that has the given ID. * * @param string $batchId * @return void */ public function delete(string $batchId) { $this->connection->table($this->table)->where('id', $batchId)->delete(); } /** * Execute the given Closure within a storage specific transaction. * * @param \Closure $callback * @return mixed */ public function transaction(Closure $callback) { return $this->connection->transaction(function () use ($callback) { return $callback(); }); } /** * Convert the given raw batch to a Batch object. * * @param object $batch * @return \Illuminate\Bus\Batch */ protected function toBatch($batch) { return $this->factory->make( $this, $batch->id, $batch->name, (int) $batch->total_jobs, (int) $batch->pending_jobs, (int) $batch->failed_jobs, json_decode($batch->failed_job_ids, true), unserialize($batch->options), CarbonImmutable::createFromTimestamp($batch->created_at), $batch->cancelled_at ? CarbonImmutable::createFromTimestamp($batch->cancelled_at) : $batch->cancelled_at, $batch->finished_at ? CarbonImmutable::createFromTimestamp($batch->finished_at) : $batch->finished_at ); } } Dispatcher.php000064400000017136147536114200007356 0ustar00container = $container; $this->queueResolver = $queueResolver; $this->pipeline = new Pipeline($container); } /** * Dispatch a command to its appropriate handler. * * @param mixed $command * @return mixed */ public function dispatch($command) { return $this->queueResolver && $this->commandShouldBeQueued($command) ? $this->dispatchToQueue($command) : $this->dispatchNow($command); } /** * Dispatch a command to its appropriate handler in the current process. * * Queuable jobs will be dispatched to the "sync" queue. * * @param mixed $command * @param mixed $handler * @return mixed */ public function dispatchSync($command, $handler = null) { if ($this->queueResolver && $this->commandShouldBeQueued($command) && method_exists($command, 'onConnection')) { return $this->dispatchToQueue($command->onConnection('sync')); } return $this->dispatchNow($command, $handler); } /** * Dispatch a command to its appropriate handler in the current process without using the synchronous queue. * * @param mixed $command * @param mixed $handler * @return mixed */ public function dispatchNow($command, $handler = null) { $uses = class_uses_recursive($command); if (in_array(InteractsWithQueue::class, $uses) && in_array(Queueable::class, $uses) && ! $command->job) { $command->setJob(new SyncJob($this->container, json_encode([]), 'sync', 'sync')); } if ($handler || $handler = $this->getCommandHandler($command)) { $callback = function ($command) use ($handler) { $method = method_exists($handler, 'handle') ? 'handle' : '__invoke'; return $handler->{$method}($command); }; } else { $callback = function ($command) { $method = method_exists($command, 'handle') ? 'handle' : '__invoke'; return $this->container->call([$command, $method]); }; } return $this->pipeline->send($command)->through($this->pipes)->then($callback); } /** * Attempt to find the batch with the given ID. * * @param string $batchId * @return \Illuminate\Bus\Batch|null */ public function findBatch(string $batchId) { return $this->container->make(BatchRepository::class)->find($batchId); } /** * Create a new batch of queueable jobs. * * @param \Illuminate\Support\Collection|array $jobs * @return \Illuminate\Bus\PendingBatch */ public function batch($jobs) { return new PendingBatch($this->container, Collection::wrap($jobs)); } /** * Create a new chain of queueable jobs. * * @param \Illuminate\Support\Collection|array $jobs * @return \Illuminate\Foundation\Bus\PendingChain */ public function chain($jobs) { $jobs = Collection::wrap($jobs); return new PendingChain($jobs->shift(), $jobs->toArray()); } /** * Determine if the given command has a handler. * * @param mixed $command * @return bool */ public function hasCommandHandler($command) { return array_key_exists(get_class($command), $this->handlers); } /** * Retrieve the handler for a command. * * @param mixed $command * @return bool|mixed */ public function getCommandHandler($command) { if ($this->hasCommandHandler($command)) { return $this->container->make($this->handlers[get_class($command)]); } return false; } /** * Determine if the given command should be queued. * * @param mixed $command * @return bool */ protected function commandShouldBeQueued($command) { return $command instanceof ShouldQueue; } /** * Dispatch a command to its appropriate handler behind a queue. * * @param mixed $command * @return mixed */ public function dispatchToQueue($command) { $connection = $command->connection ?? null; $queue = call_user_func($this->queueResolver, $connection); if (! $queue instanceof Queue) { throw new RuntimeException('Queue resolver did not return a Queue implementation.'); } if (method_exists($command, 'queue')) { return $command->queue($queue, $command); } return $this->pushCommandToQueue($queue, $command); } /** * Push the command onto the given queue instance. * * @param \Illuminate\Contracts\Queue\Queue $queue * @param mixed $command * @return mixed */ protected function pushCommandToQueue($queue, $command) { if (isset($command->queue, $command->delay)) { return $queue->laterOn($command->queue, $command->delay, $command); } if (isset($command->queue)) { return $queue->pushOn($command->queue, $command); } if (isset($command->delay)) { return $queue->later($command->delay, $command); } return $queue->push($command); } /** * Dispatch a command to its appropriate handler after the current process. * * @param mixed $command * @param mixed $handler * @return void */ public function dispatchAfterResponse($command, $handler = null) { $this->container->terminating(function () use ($command, $handler) { $this->dispatchNow($command, $handler); }); } /** * Set the pipes through which commands should be piped before dispatching. * * @param array $pipes * @return $this */ public function pipeThrough(array $pipes) { $this->pipes = $pipes; return $this; } /** * Map a command to a handler. * * @param array $map * @return $this */ public function map(array $map) { $this->handlers = array_merge($this->handlers, $map); return $this; } } Events/BatchDispatched.php000064400000000633147536114200011540 0ustar00batch = $batch; } } LICENSE.md000064400000002063147536114200006154 0ustar00The MIT License (MIT) Copyright (c) Taylor Otwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PendingBatch.php000064400000012376147536114200007617 0ustar00container = $container; $this->jobs = $jobs; } /** * Add a callback to be executed after all jobs in the batch have executed successfully. * * @param callable $callback * @return $this */ public function then($callback) { $this->options['then'][] = $callback instanceof Closure ? new SerializableClosure($callback) : $callback; return $this; } /** * Get the "then" callbacks that have been registered with the pending batch. * * @return array */ public function thenCallbacks() { return $this->options['then'] ?? []; } /** * Add a callback to be executed after the first failing job in the batch. * * @param callable $callback * @return $this */ public function catch($callback) { $this->options['catch'][] = $callback instanceof Closure ? new SerializableClosure($callback) : $callback; return $this; } /** * Get the "catch" callbacks that have been registered with the pending batch. * * @return array */ public function catchCallbacks() { return $this->options['catch'] ?? []; } /** * Add a callback to be executed after the batch has finished executing. * * @param callable $callback * @return $this */ public function finally($callback) { $this->options['finally'][] = $callback instanceof Closure ? new SerializableClosure($callback) : $callback; return $this; } /** * Get the "finally" callbacks that have been registered with the pending batch. * * @return array */ public function finallyCallbacks() { return $this->options['finally'] ?? []; } /** * Indicate that the batch should not be cancelled when a job within the batch fails. * * @param bool $allowFailures * @return $this */ public function allowFailures($allowFailures = true) { $this->options['allowFailures'] = $allowFailures; return $this; } /** * Determine if the pending batch allows jobs to fail without cancelling the batch. * * @return bool */ public function allowsFailures() { return Arr::get($this->options, 'allowFailures', false) === true; } /** * Set the name for the batch. * * @param string $name * @return $this */ public function name(string $name) { $this->name = $name; return $this; } /** * Specify the queue connection that the batched jobs should run on. * * @param string $connection * @return $this */ public function onConnection(string $connection) { $this->options['connection'] = $connection; return $this; } /** * Get the connection used by the pending batch. * * @return string|null */ public function connection() { return $this->options['connection'] ?? null; } /** * Specify the queue that the batched jobs should run on. * * @param string $queue * @return $this */ public function onQueue(string $queue) { $this->options['queue'] = $queue; return $this; } /** * Get the queue used by the pending batch. * * @return string|null */ public function queue() { return $this->options['queue'] ?? null; } /** * Dispatch the batch. * * @return \Illuminate\Bus\Batch * @throws \Throwable */ public function dispatch() { $repository = $this->container->make(BatchRepository::class); try { $batch = $repository->store($this); $batch = $batch->add($this->jobs); } catch (Throwable $e) { if (isset($batch)) { $repository->delete($batch->id); } throw $e; } $this->container->make(EventDispatcher::class)->dispatch( new BatchDispatched($batch) ); return $batch; } } Queueable.php000064400000011331147536114200007167 0ustar00connection = $connection; return $this; } /** * Set the desired queue for the job. * * @param string|null $queue * @return $this */ public function onQueue($queue) { $this->queue = $queue; return $this; } /** * Set the desired connection for the chain. * * @param string|null $connection * @return $this */ public function allOnConnection($connection) { $this->chainConnection = $connection; $this->connection = $connection; return $this; } /** * Set the desired queue for the chain. * * @param string|null $queue * @return $this */ public function allOnQueue($queue) { $this->chainQueue = $queue; $this->queue = $queue; return $this; } /** * Set the desired delay for the job. * * @param \DateTimeInterface|\DateInterval|int|null $delay * @return $this */ public function delay($delay) { $this->delay = $delay; return $this; } /** * Specify the middleware the job should be dispatched through. * * @param array|object $middleware * @return $this */ public function through($middleware) { $this->middleware = Arr::wrap($middleware); return $this; } /** * Set the jobs that should run if this job is successful. * * @param array $chain * @return $this */ public function chain($chain) { $this->chained = collect($chain)->map(function ($job) { return $this->serializeJob($job); })->all(); return $this; } /** * Serialize a job for queuing. * * @param mixed $job * @return string */ protected function serializeJob($job) { if ($job instanceof Closure) { if (! class_exists(CallQueuedClosure::class)) { throw new RuntimeException( 'To enable support for closure jobs, please install the illuminate/queue package.' ); } $job = CallQueuedClosure::create($job); } return serialize($job); } /** * Dispatch the next job on the chain. * * @return void */ public function dispatchNextJobInChain() { if (! empty($this->chained)) { dispatch(tap(unserialize(array_shift($this->chained)), function ($next) { $next->chained = $this->chained; $next->onConnection($next->connection ?: $this->chainConnection); $next->onQueue($next->queue ?: $this->chainQueue); $next->chainConnection = $this->chainConnection; $next->chainQueue = $this->chainQueue; $next->chainCatchCallbacks = $this->chainCatchCallbacks; })); } } /** * Invoke all of the chain's failed job callbacks. * * @param \Throwable $e * @return void */ public function invokeChainCatchCallbacks($e) { collect($this->chainCatchCallbacks)->each(function ($callback) use ($e) { $callback instanceof SerializableClosure ? $callback->__invoke($e) : call_user_func($callback, $e); }); } } UpdatedBatchJobCounts.php000064400000001530147536114200011436 0ustar00pendingJobs = $pendingJobs; $this->failedJobs = $failedJobs; } /** * Determine if all jobs have ran exactly once. * * @return bool */ public function allJobsHaveRanExactlyOnce() { return ($this->pendingJobs - $this->failedJobs) === 0; } } composer.json000064400000001741147536114200007274 0ustar00{ "name": "illuminate/bus", "description": "The Illuminate Bus package.", "license": "MIT", "homepage": "https://laravel.com", "support": { "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, "authors": [ { "name": "Taylor Otwell", "email": "taylor@laravel.com" } ], "require": { "php": "^7.3", "illuminate/collections": "^8.0", "illuminate/contracts": "^8.0", "illuminate/pipeline": "^8.0", "illuminate/support": "^8.0" }, "autoload": { "psr-4": { "Illuminate\\Bus\\": "" } }, "extra": { "branch-alias": { "dev-master": "8.x-dev" } }, "suggest": { "illuminate/queue": "Required to use closures when chaining jobs (^7.0)." }, "config": { "sort-packages": true }, "minimum-stability": "dev" }