123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722 |
- <?php
-
- namespace Illuminate\Console\Scheduling;
-
- use Closure;
- use Cron\CronExpression;
- use Illuminate\Support\Arr;
- use Illuminate\Support\Carbon;
- use GuzzleHttp\Client as HttpClient;
- use Illuminate\Contracts\Mail\Mailer;
- use Symfony\Component\Process\Process;
- use Illuminate\Support\Traits\Macroable;
- use Illuminate\Contracts\Container\Container;
-
- class Event
- {
- use Macroable, ManagesFrequencies;
-
- /**
- * The command string.
- *
- * @var string
- */
- 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
- */
- 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 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
- */
- public $description;
-
- /**
- * The event mutex implementation.
- *
- * @var \Illuminate\Console\Scheduling\EventMutex
- */
- public $mutex;
-
- /**
- * Create a new event instance.
- *
- * @param \Illuminate\Console\Scheduling\Mutex $mutex
- * @param string $command
- * @return void
- */
- public function __construct(EventMutex $mutex, $command)
- {
- $this->mutex = $mutex;
- $this->command = $command;
- $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
- */
- public function run(Container $container)
- {
- if ($this->withoutOverlapping &&
- ! $this->mutex->create($this)) {
- return;
- }
-
- $this->runInBackground
- ? $this->runCommandInBackground($container)
- : $this->runCommandInForeground($container);
- }
-
- /**
- * Get the mutex name for the scheduled command.
- *
- * @return string
- */
- public function mutexName()
- {
- return 'framework'.DIRECTORY_SEPARATOR.'schedule-'.sha1($this->expression.$this->command);
- }
-
- /**
- * Run the command in the foreground.
- *
- * @param \Illuminate\Contracts\Container\Container $container
- * @return void
- */
- protected function runCommandInForeground(Container $container)
- {
- $this->callBeforeCallbacks($container);
-
- (new Process(
- $this->buildCommand(), base_path(), null, null, null
- ))->run();
-
- $this->callAfterCallbacks($container);
- }
-
- /**
- * Run the command in the background.
- *
- * @param \Illuminate\Contracts\Container\Container $container
- * @return void
- */
- protected function runCommandInBackground(Container $container)
- {
- $this->callBeforeCallbacks($container);
-
- (new Process(
- $this->buildCommand(), base_path(), null, null, null
- ))->run();
- }
-
- /**
- * 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 = Carbon::now();
-
- if ($this->timezone) {
- $date->setTimezone($this->timezone);
- }
-
- return CronExpression::factory($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;
- }
-
- /**
- * 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->ensureOutputIsBeingCapturedForEmail();
-
- $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);
- }
-
- /**
- * Ensure that output is being captured for email.
- *
- * @return void
- */
- protected function ensureOutputIsBeingCapturedForEmail()
- {
- 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 = file_exists($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(function () use ($url) {
- (new HttpClient)->get($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(function () use ($url) {
- (new HttpClient)->get($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;
- }
-
- /**
- * State that the command should run in 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->then(function () {
- $this->mutex->forget($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[] = is_callable($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[] = is_callable($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)
- {
- $this->afterCallbacks[] = $callback;
-
- return $this;
- }
-
- /**
- * 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 \DateTime|string $currentTime
- * @param int $nth
- * @param bool $allowCurrentDate
- * @return \Illuminate\Support\Carbon
- */
- public function nextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false)
- {
- return Carbon::instance(CronExpression::factory(
- $this->getExpression()
- )->getNextRunDate($currentTime, $nth, $allowCurrentDate));
- }
-
- /**
- * 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;
- }
- }
|