Documentação do Symfony - versão 3.1
Renderizada do repositório symfony-docs-pt-BR no Github
Um aspecto negativo do nosso framework atual é que, precisamos copiar e colar o
código em front.php
toda vez que criamos um novo site. 40 linhas de código não é
muito, mas seria bom se pudéssemos envolver esse código em uma classe adequada.
Para citar apenas alguns benefícios, isso nos traria melhor reusabilidade e testes
mais fáceis.
Se você olhar atentamente o código, o front.php
tem uma entrada, o
Pedido (Request
), e uma saída, a Resposta (Response
). Nossa classe do framework
seguirá esse princípio simples: a lógica será sobre a criação do Response
associado a um
Request
.
Vamos criar nosso próprio namespace para nosso framework: Simplex
. Mova a
lógica da manipulação do pedido para sua própria classe Simplex\\Framework
:
// example.com/src/Simplex/Framework.php
namespace Simplex;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
class Framework
{
protected $matcher;
protected $resolver;
public function __construct(UrlMatcher $matcher, ControllerResolver $resolver)
{
$this->matcher = $matcher;
$this->resolver = $resolver;
}
public function handle(Request $request)
{
$this->matcher->getContext()->fromRequest($request);
try {
$request->attributes->add($this->matcher->match($request->getPathInfo()));
$controller = $this->resolver->getController($request);
$arguments = $this->resolver->getArguments($request, $controller);
return call_user_func_array($controller, $arguments);
} catch (ResourceNotFoundException $e) {
return new Response('Not Found', 404);
} catch (\Exception $e) {
return new Response('An error occurred', 500);
}
}
}
E, atualize example.com/web/front.php
de acordo:
// example.com/web/front.php
// ...
$request = Request::createFromGlobals();
$routes = include __DIR__.'/../src/app.php';
$context = new Routing\RequestContext();
$matcher = new Routing\Matcher\UrlMatcher($routes, $context);
$resolver = new HttpKernel\Controller\ControllerResolver();
$framework = new Simplex\Framework($matcher, $resolver);
$response = $framework->handle($request);
$response->send();
Para concluir o refatoramento, vamos mover tudo, exceto a definição das rotas,
de example.com/src/app.php
para outro namespace: Calendar
.
Para as classes definidas sob os namespaces Simplex
e Calendar
serem
carregadas automaticamente, atualize o arquivo composer.json
:
1 2 3 4 5 6 7 8 9 10 11 | {
"require": {
"symfony/class-loader": "2.1.*",
"symfony/http-foundation": "2.1.*",
"symfony/routing": "2.1.*",
"symfony/http-kernel": "2.1.*"
},
"autoload": {
"psr-0": { "Simplex": "src/", "Calendar": "src/" }
}
}
|
Note
Para o autoloader
do Composer ser atualizado, execute composer update
.
Mova o controlador para Calendar\\Controller\\LeapYearController
:
// example.com/src/Calendar/Controller/LeapYearController.php
namespace Calendar\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Calendar\Model\LeapYear;
class LeapYearController
{
public function indexAction(Request $request, $year)
{
$leapyear = new LeapYear();
if ($leapyear->isLeapYear($year)) {
return new Response('Yep, this is a leap year!');
}
return new Response('Nope, this is not a leap year.');
}
}
E, mova a função is_leap_year()
para sua própria classe também:
// example.com/src/Calendar/Model/LeapYear.php
namespace Calendar\Model;
class LeapYear
{
public function isLeapYear($year = null)
{
if (null === $year) {
$year = date('Y');
}
return 0 == $year % 400 || (0 == $year % 4 && 0 != $year % 100);
}
}
Não se esqueça de atualizar o arquivo example.com/src/app.php
de acordo:
$routes->add('leap_year', new Routing\Route('/is_leap_year/{year}', array(
'year' => null,
'_controller' => 'Calendar\\Controller\\LeapYearController::indexAction',
)));
Para resumir, aqui está o novo layout dos arquivos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | example.com
├── composer.json
├── composer.lock
├── src
│ ├── app.php
│ └── Simplex
│ └── Framework.php
│ └── Calendar
│ └── Controller
│ │ └── LeapYearController.php
│ └── Model
│ └── LeapYear.php
├── vendor
│ └── autoload.php
└── web
└── front.php
|
É isso! Nossa aplicação agora possui quatro camadas diferentes e cada uma delas tem um objetivo bem definido:
web/front.php
: O front controller
; o único código PHP exposto que
faz a interface com o cliente (ele recebe o Pedido e envia a Resposta) e
fornece o código padrão para inicializar o framework e
a nossa aplicação;src/Simplex
: O código reutilizável do framework que abstrai a manipulação de
dos Pedidos de entrada (a propósito, torna os seus controladores/templates facilmente
testáveis - veremos sobre isso mais tarde);src/Calendar
: Nosso código específico da aplicação (os controladores e o
modelo);src/app.php
: A configuração da aplicação/customização do framework.