master

laravel/framework

Last updated at: 29/12/2023 09:23

DownCommand.php

TLDR

The DownCommand.php file is part of the Illuminate\Foundation\Console namespace in the Demo Projects project. This file contains the DownCommand class that is responsible for putting the application into maintenance or demo mode. It provides methods for executing the console command, getting the payload to be placed in the "down" file, getting the paths that should be excluded from maintenance mode, getting the path that users should be redirected to, prerendering a specified view, getting the number of seconds the client should wait before retrying their request, and getting the secret phrase that may be used to bypass maintenance mode.

Methods

handle

The handle method executes the console command. It checks if the application is already in maintenance mode and activates the maintenance mode if it is not. It writes the maintenance file payload to the storage directory, dispatches the MaintenanceModeEnabled event, and displays relevant information about the maintenance mode.

getDownFilePayload

The getDownFilePayload method returns an array of data that will be placed in the "down" file. It includes the paths that should be excluded from maintenance mode, the redirect path for users, the retry time, the refresh time, the secret phrase, the status code, and the prerendered template view.

excludedPaths

The excludedPaths method retrieves the paths that should be excluded from maintenance mode. It uses the PreventRequestsDuringMaintenance middleware to get the excluded paths.

redirectPath

The redirectPath method retrieves the path that users should be redirected to during maintenance mode. It checks if the --redirect option is provided and trims it if necessary.

prerenderView

The prerenderView method prerenders a specified view so that it can be rendered even before loading Composer. It registers the error view paths and renders the view with the specified options.

getRetryTime

The getRetryTime method retrieves the number of seconds the client should wait before retrying their request. It checks the --retry option and returns the value if it is a positive integer.

getSecret

The getSecret method retrieves the secret phrase that may be used to bypass maintenance mode. It checks various conditions and returns the appropriate value.

Classes

No classes in this file.

<?php

namespace Illuminate\Foundation\Console;

use App\Http\Middleware\PreventRequestsDuringMaintenance;
use Exception;
use Illuminate\Console\Command;
use Illuminate\Foundation\Events\MaintenanceModeEnabled;
use Illuminate\Foundation\Exceptions\RegisterErrorViewPaths;
use Illuminate\Support\Str;
use Symfony\Component\Console\Attribute\AsCommand;
use Throwable;

#[AsCommand(name: 'down')]
class DownCommand extends Command
{
    /**
     * The console command signature.
     *
     * @var string
     */
    protected $signature = 'down {--redirect= : The path that users should be redirected to}
                                 {--render= : The view that should be prerendered for display during maintenance mode}
                                 {--retry= : The number of seconds after which the request may be retried}
                                 {--refresh= : The number of seconds after which the browser may refresh}
                                 {--secret= : The secret phrase that may be used to bypass maintenance mode}
                                 {--with-secret : Generate a random secret phrase that may be used to bypass maintenance mode}
                                 {--status=503 : The status code that should be used when returning the maintenance mode response}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Put the application into maintenance / demo mode';

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        try {
            if ($this->laravel->maintenanceMode()->active()) {
                $this->components->info('Application is already down.');

                return 0;
            }

            $downFilePayload = $this->getDownFilePayload();

            $this->laravel->maintenanceMode()->activate($downFilePayload);

            file_put_contents(
                storage_path('framework/maintenance.php'),
                file_get_contents(__DIR__.'/stubs/maintenance-mode.stub')
            );

            $this->laravel->get('events')->dispatch(new MaintenanceModeEnabled());

            $this->components->info('Application is now in maintenance mode.');

            if ($downFilePayload['secret'] !== null) {
                $this->components->info('You may bypass maintenance mode via ['.config('app.url')."/{$downFilePayload['secret']}].");
            }
        } catch (Exception $e) {
            $this->components->error(sprintf(
                'Failed to enter maintenance mode: %s.',
                $e->getMessage(),
            ));

            return 1;
        }
    }

    /**
     * Get the payload to be placed in the "down" file.
     *
     * @return array
     */
    protected function getDownFilePayload()
    {
        return [
            'except' => $this->excludedPaths(),
            'redirect' => $this->redirectPath(),
            'retry' => $this->getRetryTime(),
            'refresh' => $this->option('refresh'),
            'secret' => $this->getSecret(),
            'status' => (int) $this->option('status', 503),
            'template' => $this->option('render') ? $this->prerenderView() : null,
        ];
    }

    /**
     * Get the paths that should be excluded from maintenance mode.
     *
     * @return array
     */
    protected function excludedPaths()
    {
        try {
            return $this->laravel->make(PreventRequestsDuringMaintenance::class)->getExcludedPaths();
        } catch (Throwable) {
            return [];
        }
    }

    /**
     * Get the path that users should be redirected to.
     *
     * @return string
     */
    protected function redirectPath()
    {
        if ($this->option('redirect') && $this->option('redirect') !== '/') {
            return '/'.trim($this->option('redirect'), '/');
        }

        return $this->option('redirect');
    }

    /**
     * Prerender the specified view so that it can be rendered even before loading Composer.
     *
     * @return string
     */
    protected function prerenderView()
    {
        (new RegisterErrorViewPaths)();

        return view($this->option('render'), [
            'retryAfter' => $this->option('retry'),
        ])->render();
    }

    /**
     * Get the number of seconds the client should wait before retrying their request.
     *
     * @return int|null
     */
    protected function getRetryTime()
    {
        $retry = $this->option('retry');

        return is_numeric($retry) && $retry > 0 ? (int) $retry : null;
    }

    /**
     * Get the secret phrase that may be used to bypass maintenance mode.
     *
     * @return string|null
     */
    protected function getSecret()
    {
        return match (true) {
            ! is_null($this->option('secret')) => $this->option('secret'),
            $this->option('with-secret') => Str::random(),
            default => null,
        };
    }
}