Magento 2 – Request Flow (Bootstrapping)

Primeiramente meu olá à você que está lendo este artigo.

Acredito que se você chegou até aqui esteja interessado em aprender um pouco mais sobre o Magento 2. Pois bem, eu também estou interessadíssimo em aprender sempre mais sobre o Magento 2.

O Magento 1 se tornou, entre todos estes anos, a principal plataforma de e-commerce do mercado mundial e isso chamou muito a atenção de nós, desenvolvedores, e de profissionais que trabalham, direta ou indiretamente, com o Magento. Chamou tanto a atenção que agora o mercado está se preparando para usar fortemente a nova versão do Magento Commerce, a versão 2, e nós, desenvolvedores, precisamos estar sempre atualizados sobre as novidades em torno do Magento para podermos utilizá-las sempre que necessário, seja para um freela ou para um projeto em sua empresa.

Pelo pouco que estudei a plataforma pude perceber que ela é simplesmente sensacional em alguns quesitos o muito atualizada em relação ás plataformas do mercado atualmente. Muitas das novidades do mercado de desenvolvimento web estão implementadas na plataforma como, por exemplo, o uso de composer para gerenciar as dependências PHP do seu projeto, a utilização dos namespaces, disponíveis desde a versão 5.3 do PHP, a inclusão de jQuery como biblioteca de javascript nativa, a possibilidade da utilização das Traits, disponíveis desde a versão 5.4 do PHP, enfim, se você quiser saber um pouco mais sobre algumas das diferenças, você pode ler este post.

Neste post quero falar apenas sobre o Request Flow do Magento 2.

O que é Request Flow?

Request Flow, ou em português Fluxo de Requisição, que também pode ser conhecido como Application Bootstrap, nada mais é do que o fluxo da requisição dentro da aplicação, ou seja, é todo o processo que ocorre dentro da plataforma desde quando ela recebe a requisição (chamada de URL) pelo arquivo index.php, responsável por inicializar a aplicação, até o momento que o usuário pode ver o resultado da página no navegador.

Aonde Tudo Começa

Como dito logo acima, assim como é em várias outras plataformas e frameworks web, tudo se inicia pelo arquivo index.php:

Perceba que no arquivo index.php, mais precisamente na linha 22, é chamado o arquivo app/bootstrap.php que tem a responsabilidade de incluir os arquivos app/autoload.php e app/functions.php e configurar o timezone padrão do Magento para UTC:

O arquivo app/autoload.php tem a responsabilidade de fazer a inclusão de todos os arquivos necessários para o autoload das classes dentro da pasta vendor para que tudo funcione corretamente no momento de instanciar novos objetos. Já o arquivo app/functions.php é responsável por adicionar o método de tradução __ (isso mesmo, são dois underscores) que tanto conhecemos no Magento 1.

Com o autoload inicializado, o próximo passo é criar uma instância do bootstrap:

...

$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);

...

Esta chamada faz com que o ObjectManager do Magento seja iniciado. Não entrarei em detalhes sobre o que é o ObjectManager no Magento 2 neste post, vale á pena dedicar um post só para isso, e é o que farei.

O próximo passo é criar uma instância da classe Magento\Framework\App\Http, substituto da classe Mage_Core_Model_App do Magento 1, e chamar o método run, passando como referência a classe Magento\Framework\App\Http criada:

...

/** @var \Magento\Framework\App\Http $app */
$app = $bootstrap->createApplication('Magento\Framework\App\Http');
$bootstrap->run($app);

...

Agora todo o controle da inicialização da aplicação está nas mãos da classe Magento\Framework\App\Bootstrap.

Este método segue os seguintes passos:

Inicializa um profiler:

...

\Magento\Framework\Profiler::start('magento');

...

Inicializa a classe responsável por tratamento de erros:

...

$this->initErrorHandler();

...

Inicializa o ObjectManager, caso o mesmo não esteja inicializado:

...

$this->initObjectManager();

...

Verifica se o Magento está em estado de manutenção:

...

$this->assertMaintenance();

...

Verifica se o Magento já está instalado e se a instalação está correta:

...

$this->assertInstalled();

...

E finalmente inicia a aplicação:

...

$response = $application->launch();

...

Podemos ver o método launch() melhor aqui:

Neste método, se tratando do principal do request flow, duas linhas se destacam:

...
/** @var \Magento\Framework\App\FrontControllerInterface $frontController */
$frontController = $this->_objectManager->get('Magento\Framework\App\FrontControllerInterface');
$result = $frontController->dispatch($this->_request);
...

Estas linhas são responsáveis por instanciar a classe Magento\Framework\App\FrontController, localizada em lib/internal/Magento/Framework/App/FrontController.php e chamar o método dispatch() da mesma:

Routers

Um Router, em poucas palavras, é uma classe responsável por analisar e processar uma requisição. Assim como no Magento 1, no Magento 2 temos, por padrão, alguns Routers configurados para a aplicação funcionar: Base Router, Default Router, Cms Router e UrlRewrite Router. Vamos falar um pouco sobre seus propósitos e como cada uma funciona. Basicamente a sequência de leitura dos routers é:

Base Router → CMS Router → UrlRewrite Router → Default Router

Base Router

Localizado em lib/internal/Magento/Framework/App/Router/Base.php, é o primeiro router do loop e se você é um desenvolvedor Magento 1 saberá que este é basicamente o Standard Router, responsável por rotear as rotas standards, ou seja, as rotas definidas para o frontend da aplicação, como por exemplo a roda customer/account/login.

CMS Router

Localizada em app/code/Magento/Cms/Controller/Router.php, é utilizada para gerenciar as rotas das páginas CMS, e definir o nome do módulo para cms, nome do controller para page e o nome da action para viewapp/code/Magento/Cms/Controller/Page/View.php. Após estas definições, irá definir o parâmetro page_id e então encaminhar a requisição de volta para o Base Router para que o mesmo faça o dispatch da rota corretamente. Isso devido o Base Router só conseguir mapear corretamente rotas no formato modulo/controller/view, portanto quem precisa deixar a rota neste formato é o CMS Router.

UrlRewrite Router

No Magento 2 o UrlRewrite tem seu próprio Router, se você já conhece o Magento 1 saberá que URL Rewrite fazia parte do Standard Router. Está localizado em app/code/Magento/UrlRewrite/Controller/Router.php e utiliza o Url Finder para definir as rotas de URL Rewrite do banco dados. Após a definição da rota, assim como o CMS Router, O UrlRewrite Router faz um forward da requisição para que o Base Router faça o dispatch.

Default Router

Está localizado em lib/internal/Magento/Framework/App/Router/DefaultRouter.php e é o último router do laço. É utilizado apenas quando nenhum dos outros routers conseguem fazer o match da rota. No Magento 2 nós podemos criar handles personalizados para páginas “Não encontradas” e assim mostrar um conteúdo personalizado.

Dispatch de Routers

Quando o Magento chega neste ponto da aplicação, os Routers são iterados e cada um deles irá tentar fazer o dispatch da rota corretamente, ou seja, cada um com sua responsabilidade, tentará encontrar o Controller Action responsável pela lógica da regra de negócio daquela requisição, por exemplo, quando a rota chamada for customer/account/login o Controller Action responsável pela regra de negócio será Magento\Customer\Controller\Account\Login, localizada em app/code/Magento/Customer/Controller/Account/Login.php.

A partir deste momento o fluxo da requisição fica nas mãos do Controller Action do módulo responsável, conforme o exemplo acima, e o mesmo tem como responsabilidade de entregar o resultado da requisição. Podemos ver que o resultado é salvo em uma variável $result que é uma instância da classe Magento\Framework\View\Result\Page que, por sua vez, extende a classe Magento\Framework\View\Result\Layout. Quem for desenvolvedor Magento 1 saberá que este objeto é responsável por fazer a renderização dos Layout Blocks, que nada mais são do que o conteúdo da página montada como um quebra-cabeça.

Então o método renderResult é chamado para fazer a renderização dos blocos:

...
    /** @class \Magento\Framework\View\Result\Layout **/


    /**
     * Render current layout
     *
     * @param ResponseInterface $response
     * @return $this
     */
    public function renderResult(ResponseInterface $response)
    {
        \Magento\Framework\Profiler::start('LAYOUT');
        \Magento\Framework\Profiler::start('layout_render');

        $this->applyHttpHeaders($response);
        $this->render($response);

        $this->eventManager->dispatch('layout_render_before');
        $this->eventManager->dispatch('layout_render_before_' . $this->request->getFullActionName());
        \Magento\Framework\Profiler::stop('layout_render');
        \Magento\Framework\Profiler::stop('LAYOUT');
        return $this;
    }

...

Retornando o objeto Magento\Framework\App\Response\Http para o método Magento\Framework\App\Bootstrap::run() (lembra dele?) e o mesmo simplesmente envia a resposta ao navegador do usuário:

/* ... */
    public function run(AppInterface $application)
    {
        /* ... */
        $response->sendResponse();
        /* ... */
    }
/* ... */

Este é o fluxo base do Request Flow do Magento 2. É realmente bastante parecido com o Request Flow do Magento 1, com conceitos muito próximos.

Aproveitem para dar uma olhada no código e estudar um pouco mais sobre o Magento 2.

Grande abraço,

– Tiago

 

Leave A Reply

Navigate