%PDF- %PDF-
Direktori : /home/silvzytp/crm-ind-code/vendor/laravel/framework/src/Illuminate/Console/Scheduling/ |
Current File : //home/silvzytp/crm-ind-code/vendor/laravel/framework/src/Illuminate/Console/Scheduling/Event.php |
<?php namespace Illuminate\Console\Scheduling; use Closure; use Cron\CronExpression; use GuzzleHttp\Client as HttpClient; use GuzzleHttp\Exception\TransferException; use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Debug\ExceptionHandler; use Illuminate\Contracts\Mail\Mailer; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Date; use Illuminate\Support\Reflector; use Illuminate\Support\Stringable; use Illuminate\Support\Traits\Macroable; use Illuminate\Support\Traits\ReflectsClosures; use Psr\Http\Client\ClientExceptionInterface; use Symfony\Component\Process\Process; use Throwable; class Event { use Macroable, ManagesFrequencies, ReflectsClosures; /** * The command string. * * @var string|null */ public $command; /** * The cron expression representing the event's frequency. * * @var string */ public $expression = '* * * * *'; /** * The timezone the date should be evaluated on. * * @var \DateTimeZone|string */ public $timezone; /** * The user the command should run as. * * @var string|null */ public $user; /** * The list of environments the command should run under. * * @var array */ public $environments = []; /** * Indicates if the command should run in maintenance mode. * * @var bool */ public $evenInMaintenanceMode = false; /** * Indicates if the command should not overlap itself. * * @var bool */ public $withoutOverlapping = false; /** * Indicates if the command should only be allowed to run on one server for each cron expression. * * @var bool */ public $onOneServer = false; /** * The amount of time the mutex should be valid. * * @var int */ public $expiresAt = 1440; /** * Indicates if the command should run in the background. * * @var bool */ public $runInBackground = false; /** * The array of filter callbacks. * * @var array */ protected $filters = []; /** * The array of reject callbacks. * * @var array */ protected $rejects = []; /** * The location that output should be sent to. * * @var string */ public $output = '/dev/null'; /** * Indicates whether output should be appended. * * @var bool */ public $shouldAppendOutput = false; /** * The array of callbacks to be run before the event is started. * * @var array */ protected $beforeCallbacks = []; /** * The array of callbacks to be run after the event is finished. * * @var array */ protected $afterCallbacks = []; /** * The human readable description of the event. * * @var string|null */ public $description; /** * The event mutex implementation. * * @var \Illuminate\Console\Scheduling\EventMutex */ public $mutex; /** * The mutex name resolver callback. * * @var \Closure|null */ public $mutexNameResolver; /** * The exit status code of the command. * * @var int|null */ public $exitCode; /** * Create a new event instance. * * @param \Illuminate\Console\Scheduling\EventMutex $mutex * @param string $command * @param \DateTimeZone|string|null $timezone * @return void */ public function __construct(EventMutex $mutex, $command, $timezone = null) { $this->mutex = $mutex; $this->command = $command; $this->timezone = $timezone; $this->output = $this->getDefaultOutput(); } /** * Get the default output depending on the OS. * * @return string */ public function getDefaultOutput() { return (DIRECTORY_SEPARATOR === '\\') ? 'NUL' : '/dev/null'; } /** * Run the given event. * * @param \Illuminate\Contracts\Container\Container $container * @return void * * @throws \Throwable */ public function run(Container $container) { if ($this->shouldSkipDueToOverlapping()) { return; } $exitCode = $this->start($container); if (! $this->runInBackground) { $this->finish($container, $exitCode); } } /** * Determine if the event should skip because another process is overlapping. * * @return bool */ public function shouldSkipDueToOverlapping() { return $this->withoutOverlapping && ! $this->mutex->create($this); } /** * Run the command process. * * @param \Illuminate\Contracts\Container\Container $container * @return int * * @throws \Throwable */ protected function start($container) { try { $this->callBeforeCallbacks($container); return $this->execute($container); } catch (Throwable $exception) { $this->removeMutex(); throw $exception; } } /** * Run the command process. * * @param \Illuminate\Contracts\Container\Container $container * @return int */ protected function execute($container) { return Process::fromShellCommandline( $this->buildCommand(), base_path(), null, null, null )->run(); } /** * Mark the command process as finished and run callbacks/cleanup. * * @param \Illuminate\Contracts\Container\Container $container * @param int $exitCode * @return void */ public function finish(Container $container, $exitCode) { $this->exitCode = (int) $exitCode; try { $this->callAfterCallbacks($container); } finally { $this->removeMutex(); } } /** * Call all of the "before" callbacks for the event. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ public function callBeforeCallbacks(Container $container) { foreach ($this->beforeCallbacks as $callback) { $container->call($callback); } } /** * Call all of the "after" callbacks for the event. * * @param \Illuminate\Contracts\Container\Container $container * @return void */ public function callAfterCallbacks(Container $container) { foreach ($this->afterCallbacks as $callback) { $container->call($callback); } } /** * Build the command string. * * @return string */ public function buildCommand() { return (new CommandBuilder)->buildCommand($this); } /** * Determine if the given event should run based on the Cron expression. * * @param \Illuminate\Contracts\Foundation\Application $app * @return bool */ public function isDue($app) { if (! $this->runsInMaintenanceMode() && $app->isDownForMaintenance()) { return false; } return $this->expressionPasses() && $this->runsInEnvironment($app->environment()); } /** * Determine if the event runs in maintenance mode. * * @return bool */ public function runsInMaintenanceMode() { return $this->evenInMaintenanceMode; } /** * Determine if the Cron expression passes. * * @return bool */ protected function expressionPasses() { $date = Date::now(); if ($this->timezone) { $date = $date->setTimezone($this->timezone); } return (new CronExpression($this->expression))->isDue($date->toDateTimeString()); } /** * Determine if the event runs in the given environment. * * @param string $environment * @return bool */ public function runsInEnvironment($environment) { return empty($this->environments) || in_array($environment, $this->environments); } /** * Determine if the filters pass for the event. * * @param \Illuminate\Contracts\Foundation\Application $app * @return bool */ public function filtersPass($app) { foreach ($this->filters as $callback) { if (! $app->call($callback)) { return false; } } foreach ($this->rejects as $callback) { if ($app->call($callback)) { return false; } } return true; } /** * Ensure that the output is stored on disk in a log file. * * @return $this */ public function storeOutput() { $this->ensureOutputIsBeingCaptured(); return $this; } /** * Send the output of the command to a given location. * * @param string $location * @param bool $append * @return $this */ public function sendOutputTo($location, $append = false) { $this->output = $location; $this->shouldAppendOutput = $append; return $this; } /** * Append the output of the command to a given location. * * @param string $location * @return $this */ public function appendOutputTo($location) { return $this->sendOutputTo($location, true); } /** * E-mail the results of the scheduled operation. * * @param array|mixed $addresses * @param bool $onlyIfOutputExists * @return $this * * @throws \LogicException */ public function emailOutputTo($addresses, $onlyIfOutputExists = false) { $this->ensureOutputIsBeingCaptured(); $addresses = Arr::wrap($addresses); return $this->then(function (Mailer $mailer) use ($addresses, $onlyIfOutputExists) { $this->emailOutput($mailer, $addresses, $onlyIfOutputExists); }); } /** * E-mail the results of the scheduled operation if it produces output. * * @param array|mixed $addresses * @return $this * * @throws \LogicException */ public function emailWrittenOutputTo($addresses) { return $this->emailOutputTo($addresses, true); } /** * E-mail the results of the scheduled operation if it fails. * * @param array|mixed $addresses * @return $this */ public function emailOutputOnFailure($addresses) { $this->ensureOutputIsBeingCaptured(); $addresses = Arr::wrap($addresses); return $this->onFailure(function (Mailer $mailer) use ($addresses) { $this->emailOutput($mailer, $addresses, false); }); } /** * Ensure that the command output is being captured. * * @return void */ protected function ensureOutputIsBeingCaptured() { if (is_null($this->output) || $this->output == $this->getDefaultOutput()) { $this->sendOutputTo(storage_path('logs/schedule-'.sha1($this->mutexName()).'.log')); } } /** * E-mail the output of the event to the recipients. * * @param \Illuminate\Contracts\Mail\Mailer $mailer * @param array $addresses * @param bool $onlyIfOutputExists * @return void */ protected function emailOutput(Mailer $mailer, $addresses, $onlyIfOutputExists = false) { $text = is_file($this->output) ? file_get_contents($this->output) : ''; if ($onlyIfOutputExists && empty($text)) { return; } $mailer->raw($text, function ($m) use ($addresses) { $m->to($addresses)->subject($this->getEmailSubject()); }); } /** * Get the e-mail subject line for output results. * * @return string */ protected function getEmailSubject() { if ($this->description) { return $this->description; } return "Scheduled Job Output For [{$this->command}]"; } /** * Register a callback to ping a given URL before the job runs. * * @param string $url * @return $this */ public function pingBefore($url) { return $this->before($this->pingCallback($url)); } /** * Register a callback to ping a given URL before the job runs if the given condition is true. * * @param bool $value * @param string $url * @return $this */ public function pingBeforeIf($value, $url) { return $value ? $this->pingBefore($url) : $this; } /** * Register a callback to ping a given URL after the job runs. * * @param string $url * @return $this */ public function thenPing($url) { return $this->then($this->pingCallback($url)); } /** * Register a callback to ping a given URL after the job runs if the given condition is true. * * @param bool $value * @param string $url * @return $this */ public function thenPingIf($value, $url) { return $value ? $this->thenPing($url) : $this; } /** * Register a callback to ping a given URL if the operation succeeds. * * @param string $url * @return $this */ public function pingOnSuccess($url) { return $this->onSuccess($this->pingCallback($url)); } /** * Register a callback to ping a given URL if the operation fails. * * @param string $url * @return $this */ public function pingOnFailure($url) { return $this->onFailure($this->pingCallback($url)); } /** * Get the callback that pings the given URL. * * @param string $url * @return \Closure */ protected function pingCallback($url) { return function (Container $container, HttpClient $http) use ($url) { try { $http->request('GET', $url); } catch (ClientExceptionInterface|TransferException $e) { $container->make(ExceptionHandler::class)->report($e); } }; } /** * State that the command should run in the background. * * @return $this */ public function runInBackground() { $this->runInBackground = true; return $this; } /** * Set which user the command should run as. * * @param string $user * @return $this */ public function user($user) { $this->user = $user; return $this; } /** * Limit the environments the command should run in. * * @param array|mixed $environments * @return $this */ public function environments($environments) { $this->environments = is_array($environments) ? $environments : func_get_args(); return $this; } /** * State that the command should run even in maintenance mode. * * @return $this */ public function evenInMaintenanceMode() { $this->evenInMaintenanceMode = true; return $this; } /** * Do not allow the event to overlap each other. * * @param int $expiresAt * @return $this */ public function withoutOverlapping($expiresAt = 1440) { $this->withoutOverlapping = true; $this->expiresAt = $expiresAt; return $this->skip(function () { return $this->mutex->exists($this); }); } /** * Allow the event to only run on one server for each cron expression. * * @return $this */ public function onOneServer() { $this->onOneServer = true; return $this; } /** * Register a callback to further filter the schedule. * * @param \Closure|bool $callback * @return $this */ public function when($callback) { $this->filters[] = Reflector::isCallable($callback) ? $callback : function () use ($callback) { return $callback; }; return $this; } /** * Register a callback to further filter the schedule. * * @param \Closure|bool $callback * @return $this */ public function skip($callback) { $this->rejects[] = Reflector::isCallable($callback) ? $callback : function () use ($callback) { return $callback; }; return $this; } /** * Register a callback to be called before the operation. * * @param \Closure $callback * @return $this */ public function before(Closure $callback) { $this->beforeCallbacks[] = $callback; return $this; } /** * Register a callback to be called after the operation. * * @param \Closure $callback * @return $this */ public function after(Closure $callback) { return $this->then($callback); } /** * Register a callback to be called after the operation. * * @param \Closure $callback * @return $this */ public function then(Closure $callback) { $parameters = $this->closureParameterTypes($callback); if (Arr::get($parameters, 'output') === Stringable::class) { return $this->thenWithOutput($callback); } $this->afterCallbacks[] = $callback; return $this; } /** * Register a callback that uses the output after the job runs. * * @param \Closure $callback * @param bool $onlyIfOutputExists * @return $this */ public function thenWithOutput(Closure $callback, $onlyIfOutputExists = false) { $this->ensureOutputIsBeingCaptured(); return $this->then($this->withOutputCallback($callback, $onlyIfOutputExists)); } /** * Register a callback to be called if the operation succeeds. * * @param \Closure $callback * @return $this */ public function onSuccess(Closure $callback) { $parameters = $this->closureParameterTypes($callback); if (Arr::get($parameters, 'output') === Stringable::class) { return $this->onSuccessWithOutput($callback); } return $this->then(function (Container $container) use ($callback) { if ($this->exitCode === 0) { $container->call($callback); } }); } /** * Register a callback that uses the output if the operation succeeds. * * @param \Closure $callback * @param bool $onlyIfOutputExists * @return $this */ public function onSuccessWithOutput(Closure $callback, $onlyIfOutputExists = false) { $this->ensureOutputIsBeingCaptured(); return $this->onSuccess($this->withOutputCallback($callback, $onlyIfOutputExists)); } /** * Register a callback to be called if the operation fails. * * @param \Closure $callback * @return $this */ public function onFailure(Closure $callback) { $parameters = $this->closureParameterTypes($callback); if (Arr::get($parameters, 'output') === Stringable::class) { return $this->onFailureWithOutput($callback); } return $this->then(function (Container $container) use ($callback) { if ($this->exitCode !== 0) { $container->call($callback); } }); } /** * Register a callback that uses the output if the operation fails. * * @param \Closure $callback * @param bool $onlyIfOutputExists * @return $this */ public function onFailureWithOutput(Closure $callback, $onlyIfOutputExists = false) { $this->ensureOutputIsBeingCaptured(); return $this->onFailure($this->withOutputCallback($callback, $onlyIfOutputExists)); } /** * Get a callback that provides output. * * @param \Closure $callback * @param bool $onlyIfOutputExists * @return \Closure */ protected function withOutputCallback(Closure $callback, $onlyIfOutputExists = false) { return function (Container $container) use ($callback, $onlyIfOutputExists) { $output = $this->output && is_file($this->output) ? file_get_contents($this->output) : ''; return $onlyIfOutputExists && empty($output) ? null : $container->call($callback, ['output' => new Stringable($output)]); }; } /** * Set the human-friendly description of the event. * * @param string $description * @return $this */ public function name($description) { return $this->description($description); } /** * Set the human-friendly description of the event. * * @param string $description * @return $this */ public function description($description) { $this->description = $description; return $this; } /** * Get the summary of the event for display. * * @return string */ public function getSummaryForDisplay() { if (is_string($this->description)) { return $this->description; } return $this->buildCommand(); } /** * Determine the next due date for an event. * * @param \DateTimeInterface|string $currentTime * @param int $nth * @param bool $allowCurrentDate * @return \Illuminate\Support\Carbon */ public function nextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false) { return Date::instance((new CronExpression($this->getExpression())) ->getNextRunDate($currentTime, $nth, $allowCurrentDate, $this->timezone)); } /** * Get the Cron expression for the event. * * @return string */ public function getExpression() { return $this->expression; } /** * Set the event mutex implementation to be used. * * @param \Illuminate\Console\Scheduling\EventMutex $mutex * @return $this */ public function preventOverlapsUsing(EventMutex $mutex) { $this->mutex = $mutex; return $this; } /** * Get the mutex name for the scheduled command. * * @return string */ public function mutexName() { $mutexNameResolver = $this->mutexNameResolver; if (! is_null($mutexNameResolver) && is_callable($mutexNameResolver)) { return $mutexNameResolver($this); } return 'framework'.DIRECTORY_SEPARATOR.'schedule-'.sha1($this->expression.$this->command); } /** * Set the mutex name or name resolver callback. * * @param \Closure|string $mutexName * @return $this */ public function createMutexNameUsing(Closure|string $mutexName) { $this->mutexNameResolver = is_string($mutexName) ? fn () => $mutexName : $mutexName; return $this; } /** * Delete the mutex for the event. * * @return void */ protected function removeMutex() { if ($this->withoutOverlapping) { $this->mutex->forget($this); } } }