Thiago Cantero

Tecnologia e Entretenimento

Arquitetura de SoftwareDesenvolvimento WebLaravellinguagem de programaçãoOpensourcePHPProgramação

Ciclo de Vida de uma Aplicação Laravel

Olá, mundo! Tudo bem?

Hoje venho aqui explanar um pouco sobre o ciclo de vida do Framework Laravel, este amplamente utilizado em projetos mundo afora e, confesso que adotei ele pela alta produtividade, segurança e customização.

Aconselho a quem adotar, seja qualquer framework, entender a linguagem. Aqui no caso o PHP, no entanto isso vale para todas as outras Linguagens, como C#, Java, Rust, GO, Python, e por ai vai. É de suma importância conhecer, para tanto empenha-se na tecnologia em que tem mais afinidade para melhor conduzir sua curva de aprendizado, em posts futuros, falarei sobre o .NET para Web, utilizando o Linux. Nestas futuras observações, levarei conceitos que pormenorizam as suas respectivas funcionalidades/características.

Como explanei acima, para melhor conhecer o framework, nada melhor do que entender o seu Ciclo de vida (básico) de funcionamento, abaixo de maneira adaptada segue como ele segue cada passo, da requisição do Browser, até na resposta da view.

 

1º Passo – endpoint index.php:

Nosso ponto inicial se dá no arquivo disponível em  public/index.php, que serve como nosso endpoint, com o objetivo de atender todas as requisições do Framework, além de acionar todas as eventuais bibliotecas obtidas do composer.

<?php

use Illuminate\Contracts\Http\Kernel;
use Illuminate\Http\Request;

define('LARAVEL_START', microtime(true));

/*
|--------------------------------------------------------------------------
| Check If The Application Is Under Maintenance
|--------------------------------------------------------------------------
|
| If the application is in maintenance / demo mode via the "down" command
| we will load this file so that any pre-rendered content can be shown
| instead of starting the framework, which could cause an exception.
|
*/

if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
    require $maintenance;
}

/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| this application. We just need to utilize it! We'll simply require it
| into the script here so we don't need to manually load our classes.
|
*/

require __DIR__.'/../vendor/autoload.php';

/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request using
| the application's HTTP kernel. Then, we will send the response back
| to this client's browser, allowing them to enjoy our application.
|
*/

$app = require_once __DIR__.'/../bootstrap/app.php';

$kernel = $app->make(Kernel::class);

$response = $kernel->handle(
    $request = Request::capture()
)->send();

$kernel->terminate($request, $response);

Como podemos observar, ele inicialmente faz uma checagem se a aplicação está em manutenção, posteriormente registra o Autoloader na memória e, por fim, faz a aplicação rodar com todas as bibliotecas que eventulamente possua.

2º Passo – HTTP Kernel:

Em sua trajetória a requisição – outrora enviada pelo cliente – é direcionada ao Kernel Http (quando as requisições surgem de eventos do Browser, AJAX, etc)  ou na utilização do Artisan CLI, será feita a Requisição no Kernel Console.

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array<int, class-string|string>
     */
    protected $middleware = [
        // \App\Http\Middleware\TrustHosts::class,
        \App\Http\Middleware\TrustProxies::class,
        \Fruitcake\Cors\HandleCors::class,
        \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    ];

    /**
     * The application's route middleware groups.
     *
     * @var array<string, array<int, class-string|string>>
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array<string, class-string|string>
     */
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    ];
}

O Código acima, demonstra toda a stack que provê o framework, com as funcionalidades de Middlewares como criação de Sessões, Autenticação, Confirmações de Senha, dentre qualquer outra requisição possível que seja feita através dos verbos HTTP. Aqui também configuram os bootstrappers de tratamentos de erros, detecta o ambiente da aplicação (desenvolvimento, teste, produção e etc.)

3º Passo – Service Providers (Provedores de Serviços):

Agora o Kernel Htpp exerce uma das premissas mais significativas de bootstrapping, que é o carregamento dos Provedores de Serviços (Service Providers), aqui carregam as filas, validações, roteamento da aplicação, além do Banco de Dados, na figura do ORM Eloquent. Se você não faz a mínima ideia do que seja ORM, clique aqui e aqui também.

As definições se localizam na pasta config/app.php.

/*
    |--------------------------------------------------------------------------
    | Autoloaded Service Providers
    |--------------------------------------------------------------------------
    |
    | The service providers listed here will be automatically loaded on the
    | request to your application. Feel free to add your own services to
    | this array to grant expanded functionality to your applications.
    |
    */

    'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        Illuminate\Bus\BusServiceProvider::class,
        Illuminate\Cache\CacheServiceProvider::class,
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
        Illuminate\Cookie\CookieServiceProvider::class,
        Illuminate\Database\DatabaseServiceProvider::class,
        Illuminate\Encryption\EncryptionServiceProvider::class,
        Illuminate\Filesystem\FilesystemServiceProvider::class,
        Illuminate\Foundation\Providers\FoundationServiceProvider::class,
        Illuminate\Hashing\HashServiceProvider::class,
        Illuminate\Mail\MailServiceProvider::class,
        Illuminate\Notifications\NotificationServiceProvider::class,
        Illuminate\Pagination\PaginationServiceProvider::class,
        Illuminate\Pipeline\PipelineServiceProvider::class,
        Illuminate\Queue\QueueServiceProvider::class,
        Illuminate\Redis\RedisServiceProvider::class,
        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
        Illuminate\Session\SessionServiceProvider::class,
        Illuminate\Translation\TranslationServiceProvider::class,
        Illuminate\Validation\ValidationServiceProvider::class,
        Illuminate\View\ViewServiceProvider::class,

        /*
         * Package Service Providers...
         */

        /*
         * Application Service Providers...
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        // App\Providers\BroadcastServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,

    ],

Acima um trecho do Array Associativo que traz os serviços essenciais para o funcionamento da aplicação, como no esquema do desenho, a coluna do meio em que está o HTTP Kernel, atua como uma espinha dorsal da aplicação, acionando a classe de Service Providers, para atuar senão na função das mais importantes, as Rotas da aplicação. Disponível na pasta App/Providers/RouteServiceProvider.

<?php

namespace App\Providers;

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;

class RouteServiceProvider extends ServiceProvider
{
    /**
     * The path to the "home" route for your application.
     *
     * This is used by Laravel authentication to redirect users after login.
     *
     * @var string
     */
    public const HOME = '/home';

    /**
     * The controller namespace for the application.
     *
     * When present, controller route declarations will automatically be prefixed with this namespace.
     *
     * @var string|null
     */
    // protected $namespace = 'App\\Http\\Controllers';

    /**
     * Define your route model bindings, pattern filters, etc.
     *
     * @return void
     */
    public function boot()
    {
        $this->configureRateLimiting();

        $this->routes(function () {
            Route::prefix('api')
                ->middleware('api')
                ->namespace($this->namespace)
                ->group(base_path('routes/api.php'));

            Route::middleware('web')
                ->namespace($this->namespace)
                ->group(base_path('routes/web.php'));
        });
    }

    /**
     * Configure the rate limiters for the application.
     *
     * @return void
     */
    protected function configureRateLimiting()
    {
        RateLimiter::for('api', function (Request $request) {
            return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
        });
    }
}

Como podemos observar, ela injeta muitas dependências do Framewok, herda a Superclasse ServiceProvider e possui a função boot() em que constrói os objetos de rotas e suas peculiaridades.

 

4º Passo – Rotas:

Feita todo o carregamento dos Serviços, a requisição HTTP será despachada e direcionada no arquivo de rotas, disponível em

//Encaminha requisição através do Verbo GET do HTTP, que por sua vez retorna uma View através de uma função anônima
Route::get('/', function () {
    return view('olamundo');
});
//Encminha a requisição por meio do verbo GET do HTTP, para um Controller.
Route::get('/ola-mundo', [\App\Http\Controllers\OlaMundoController::class, 'olaMundo']);

As rotas irão direcionar  as requisições para classes de serviços, views, APIs, etc. Que por fim, irá realizar o “Grand Finale“.

 

5º Passo – Resposta para o Cliente:

Após toda este ciclo – que é realizado em frações de milisegundos : ) – a rota irá acionar a view, api, classe de serviço ou qualquer outra finalidade da aplicação e voltar ao HTTP Kernel que ira manipular, através do método handle () que retornará a resposta para o cliente.

Ufa, tudo isso?! Não, claro que é uma maneira bem superficial de entender e dissertar o Ciclo de Vida de uma Aplicação Laravel, no entanto nos dá muito conhecimento para termos uma real noção do que está nos bastidores, e com a utilização de ferramentas apropriadas, traçar métricas para melhorias de desempenho, segurança, dentre outros provimentos necessários para uma aplicação robusta que o Framework entrega.

A Documentação do Laravel é bem abrangente, no exemplo acima usei a versão 8 e já estamos na versão 9, que exige o PHP 8, não sendo possível rodar em ambientes com compilações inferiores.

É importante também ressaltar de qual maneira você vai querer modelar sua aplicação, pois o framework também lhe dá esta oportunidade, como por exemplo criar uma aplicação baseada em Domain Driven Design, LISKOV Principle, dentre outras boas práticas que você e sua equipe poderão adotar como estratégia e, por sua vez, terão uma melhor documentação e manutenção do código. Do mais fico por aqui.

Boa viagem! ; )

 

“Só obtém algo interessante da vida, da escola, do trabalho, quem lê muito.

E só lê muito quem lê por prazer.”

Professor Pierluigi Piazzi