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
:
<?php | |
/** | |
* Application entry point | |
* | |
* Example - run a particular store or website: | |
* -------------------------------------------- | |
* require __DIR__ . '/app/bootstrap.php'; | |
* $params = $_SERVER; | |
* $params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE] = 'website2'; | |
* $params[\Magento\Store\Model\StoreManager::PARAM_RUN_TYPE] = 'website'; | |
* $bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $params); | |
* \/** @var \Magento\Framework\App\Http $app *\/ | |
* $app = $bootstrap->createApplication('Magento\Framework\App\Http'); | |
* $bootstrap->run($app); | |
* -------------------------------------------- | |
* | |
* Copyright © 2015 Magento. All rights reserved. | |
* See COPYING.txt for license details. | |
*/ | |
try { | |
require __DIR__ . '/app/bootstrap.php'; | |
} catch (\Exception $e) { | |
echo <<<HTML | |
<div style="font:12px/1.35em arial, helvetica, sans-serif;"> | |
<div style="margin:0 0 25px 0; border-bottom:1px solid #ccc;"> | |
<h3 style="margin:0;font-size:1.7em;font-weight:normal;text-transform:none;text-align:left;color:#2f2f2f;"> | |
Autoload error</h3> | |
</div> | |
<p>{$e->getMessage()}</p> | |
</div> | |
HTML; | |
exit(1); | |
} | |
$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER); | |
/** @var \Magento\Framework\App\Http $app */ | |
$app = $bootstrap->createApplication('Magento\Framework\App\Http'); | |
$bootstrap->run($app); |
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:
<?php | |
/** | |
* Copyright © 2015 Magento. All rights reserved. | |
* See COPYING.txt for license details. | |
*/ | |
/** | |
* Environment initialization | |
*/ | |
error_reporting(E_ALL); | |
#ini_set('display_errors', 1); | |
umask(0); | |
/* PHP version validation */ | |
if (version_compare(phpversion(), '5.5.0', '<') === true) { | |
if (PHP_SAPI == 'cli') { | |
echo 'Magento supports PHP 5.5.0 or later. ' . | |
'Please read http://devdocs.magento.com/guides/v1.0/install-gde/system-requirements.html'; | |
} else { | |
echo <<<HTML | |
<div style="font:12px/1.35em arial, helvetica, sans-serif;"> | |
<p>Magento supports PHP 5.5.0 or later. Please read | |
<a target="_blank" href="http://devdocs.magento.com/guides/v1.0/install-gde/system-requirements.html"> | |
Magento System Requirements</a>. | |
</div> | |
HTML; | |
} | |
exit(1); | |
} | |
require_once __DIR__ . '/autoload.php'; | |
require_once BP . '/app/functions.php'; | |
if (!empty($_SERVER['MAGE_PROFILER']) | |
&& isset($_SERVER['HTTP_ACCEPT']) | |
&& strpos($_SERVER['HTTP_ACCEPT'], 'text/html') !== false | |
) { | |
\Magento\Framework\Profiler::applyConfig( | |
$_SERVER['MAGE_PROFILER'], | |
BP, | |
!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' | |
); | |
} | |
date_default_timezone_set('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 = MagentoFrameworkAppBootstrap::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 MagentoFrameworkAppHttp, substituto da classe Mage_Core_Model_App do Magento 1, e chamar o método run, passando como referência a classe MagentoFrameworkAppHttp
criada:
... /** @var MagentoFrameworkAppHttp $app */ $app = $bootstrap->createApplication('MagentoFrameworkAppHttp'); $bootstrap->run($app); ...
Agora todo o controle da inicialização da aplicação está nas mãos da classe MagentoFrameworkAppBootstrap.
<?php | |
... | |
/** | |
* Runs an application | |
* | |
* @param \Magento\Framework\AppInterface $application | |
* @return void | |
*/ | |
public function run(AppInterface $application) | |
{ | |
try { | |
try { | |
\Magento\Framework\Profiler::start('magento'); | |
$this->initErrorHandler(); | |
$this->initObjectManager(); | |
$this->assertMaintenance(); | |
$this->assertInstalled(); | |
$response = $application->launch(); | |
$response->sendResponse(); | |
\Magento\Framework\Profiler::stop('magento'); | |
} catch (\Exception $e) { | |
\Magento\Framework\Profiler::stop('magento'); | |
if (!$application->catchException($this, $e)) { | |
throw $e; | |
} | |
} | |
} catch (\Exception $e) { | |
$this->terminate($e); | |
} | |
} | |
... |
Este método segue os seguintes passos:
Inicializa um profiler:
... MagentoFrameworkProfiler::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:
<?php | |
... | |
/** | |
* Run application | |
* | |
* @throws \InvalidArgumentException | |
* @return ResponseInterface | |
*/ | |
public function launch() | |
{ | |
$areaCode = $this->_areaList->getCodeByFrontName($this->_request->getFrontName()); | |
$this->_state->setAreaCode($areaCode); | |
$this->_objectManager->configure($this->_configLoader->load($areaCode)); | |
/** @var \Magento\Framework\App\FrontControllerInterface $frontController */ | |
$frontController = $this->_objectManager->get('Magento\Framework\App\FrontControllerInterface'); | |
$result = $frontController->dispatch($this->_request); | |
// TODO: Temporary solution until all controllers return ResultInterface (MAGETWO-28359) | |
if ($result instanceof ResultInterface) { | |
$this->registry->register('use_page_cache_plugin', true, true); | |
$result->renderResult($this->_response); | |
} elseif ($result instanceof HttpInterface) { | |
$this->_response = $result; | |
} else { | |
throw new \InvalidArgumentException('Invalid return type'); | |
} | |
// This event gives possibility to launch something before sending output (allow cookie setting) | |
$eventParams = ['request' => $this->_request, 'response' => $this->_response]; | |
$this->_eventManager->dispatch('controller_front_send_response_before', $eventParams); | |
return $this->_response; | |
} | |
... |
Neste método, se tratando do principal do request flow, duas linhas se destacam:
... /** @var MagentoFrameworkAppFrontControllerInterface $frontController */ $frontController = $this-&amp;amp;amp;amp;amp;amp;gt;_objectManager-&amp;amp;amp;amp;amp;amp;gt;get('MagentoFrameworkAppFrontControllerInterface'); $result = $frontController-&amp;amp;amp;amp;amp;amp;gt;dispatch($this-&amp;amp;amp;amp;amp;amp;gt;_request); ...
Estas linhas são responsáveis por instanciar a classe MagentoFrameworkAppFrontController
, localizada em lib/internal/Magento/Framework/App/FrontController.php
e chamar o método dispatch()
da mesma:
<?php | |
/** | |
* Front controller responsible for dispatching application requests | |
* | |
* Copyright © 2015 Magento. All rights reserved. | |
* See COPYING.txt for license details. | |
*/ | |
namespace Magento\Framework\App; | |
class FrontController implements FrontControllerInterface | |
{ | |
/** | |
* @var RouterList | |
*/ | |
protected $_routerList; | |
/** | |
* @var \Magento\Framework\App\Response\Http | |
*/ | |
protected $response; | |
/** | |
* @param RouterList $routerList | |
* @param \Magento\Framework\App\Response\Http $response | |
*/ | |
public function __construct( | |
RouterList $routerList, | |
\Magento\Framework\App\Response\Http $response | |
) { | |
$this->_routerList = $routerList; | |
$this->response = $response; | |
} | |
/** | |
* Perform action and generate response | |
* | |
* @param RequestInterface $request | |
* @return ResponseInterface|\Magento\Framework\Controller\ResultInterface | |
* @throws \LogicException | |
*/ | |
public function dispatch(RequestInterface $request) | |
{ | |
\Magento\Framework\Profiler::start('routers_match'); | |
$routingCycleCounter = 0; | |
$result = null; | |
while (!$request->isDispatched() && $routingCycleCounter++ < 100) { | |
/** @var \Magento\Framework\App\RouterInterface $router */ | |
foreach ($this->_routerList as $router) { | |
try { | |
$actionInstance = $router->match($request); | |
if ($actionInstance) { | |
$request->setDispatched(true); | |
$this->response->setNoCacheHeaders(); | |
if ($actionInstance instanceof \Magento\Framework\App\Action\AbstractAction) { | |
$result = $actionInstance->dispatch($request); | |
} else { | |
$result = $actionInstance->execute(); | |
} | |
break; | |
} | |
} catch (\Magento\Framework\Exception\NotFoundException $e) { | |
$request->initForward(); | |
$request->setActionName('noroute'); | |
$request->setDispatched(false); | |
break; | |
} | |
} | |
} | |
\Magento\Framework\Profiler::stop('routers_match'); | |
if ($routingCycleCounter > 100) { | |
throw new \LogicException('Front controller reached 100 router match iterations'); | |
} | |
return $result; | |
} | |
} |
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 view – app/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á MagentoCustomerControllerAccountLogin, 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 MagentoFrameworkViewResultPage
que, por sua vez, extende a classe MagentoFrameworkViewResultLayout
. 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 MagentoFrameworkViewResultLayout **/ /** * Render current layout * * @param ResponseInterface $response * @return $this */ public function renderResult(ResponseInterface $response) { MagentoFrameworkProfiler::start('LAYOUT'); MagentoFrameworkProfiler::start('layout_render'); $this->applyHttpHeaders($response); $this->render($response); $this->eventManager->dispatch('layout_render_before'); $this->eventManager->dispatch('layout_render_before_' . $this->request->getFullActionName()); MagentoFrameworkProfiler::stop('layout_render'); MagentoFrameworkProfiler::stop('LAYOUT'); return $this; } ...
Retornando o objeto MagentoFrameworkAppResponseHttp
para o método MagentoFrameworkAppBootstrap::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
Olá tiago olhei sua pagina acredito que possa me ajudar
Hoje estou montando minha loja magento V 2.1.4 e esta neste provisorio dominio . americanbrasil.lpcdev.com.br que é de um desenvolvedor .
Estou com algumas dificuldades em encontrar APi Correios que funcione corretamente e Demais Api .
Será que com sua experiencia poderia me indicar algum local onde eu possa encontrar varias Api podem ser pagas não tem problema .
Preciso de um ERP tambem , aguardo desde já suas respostas .
Att
ilcimar Canibal
LikeLike
Olá Ilcimar, tudo bem?
Acredito que este link possa lhe ajudar: Correios Offline & Online.
Abraços,
– Tiago
LikeLike