Se você está desenvolvendo sua aplicação utilizando o Zend Framework 2 e se deparou com o problema de não conseguir obter informações específicas via RouteMatch
de uma rota em string
que tem em mãos, talvez este post possa te ajudar.
Cenário
O cenário que encontrei era o seguinte: Ao desenvolver um módulo ACL customizado, precisava verificar em certas ocasiões se um determinado “recurso” estava permitido para o perfil do usuário autenticado.
Para manter um certo padrão, dei preferência em manter a mesma sintaxe da utilizada pelo ViewHelper
para gerar URLs. Se você não está lembrado ou não conhece, confira um exemplo abaixo:
<a href="<?php echo $this->url('myroute', array('myparam' => 1));">Link</a>
Como minhas regras de ACL se baseavam em nomes de Controller
e em suas respectivas Action
, eis que surge um problemão. O motivo é: ambas as informações podem ser obtidas através de uma rota a partir do RouteMatch
. Por padrão dá para obter o RouteMatch
correspondente à URL atual em um MvcEvent
, algo como o trecho a seguir.
public function onBootstrap(MvcEvent $e)
{
$match = $e->getRouteMatch();
}
Tendo o RouteMatch
é possível obter o nome do Controller
via o método getParam('controller')
e o nome da Action
via o método getParam('action')
.
A API do Router
A primeira coisa que vem à cabeça é correr para o StackOverflow e Google caçando algo relacionado à API do Router interno do Zend Framework. O problema é que você se deparará com o seguinte: o único método que obtém um RouteMatch
recebe como parâmetro um Request
… WTF?
Vamos destrinchar um pouco disso, confira abaixo a interface RouteInterface
, que é o “contrato” dos Routers do Zend Framework 2:
interface RouteInterface
{
public static function factory(array $options = array());
public function match(Request $request);
public function assemble(array $params = array(), array $options = array());
}
Os métodos que são pertinentes a nós são os dois últimos:
match(Request $request)
- Verifica nas rotas disponíveis a que corresponde à requisição e retorna umRouteMatch
com as principais informações da rota encontradaassemble(...)
- “Casa” parâmetros correspondentes a uma rota, como, por exemplo, um nome, podendo também fornecer informações extras referentes a subrotas, e retorna a URI da rota encontrada.
Obtendo o RouteMatch
Depois de explicar o propósito dos dois métodos da API RouteInterface
talvez você já tenha pensado na solução que vou propor, se não pensou tudo bem, aqui vou explicá-la um pouco melhor.
Primeiramente será necessário obter o Router
.
$router = $this->getServiceLocator()->get('Router');
Logo no início descrevi que usaria uma API similar a do ViewHelper
de URLs, que usa o nome da rota. Portanto o próximo passo é obter a URI correspondente a esse nome de rota através do método assemble()
.
$routeUri = $router->assemble('myroute');
Isso é necessário porque para obter o RouteMatch
precisaremos construir um Request
correspondente à URI que desejamos obter as informações.
use Zend\Http\PhpEnvironment\Request;
$request = new Request();
$request->setUri($routeUri);
Pronto, agora já é possível obter o que precisamos da rota a partir de um RouteMatch
.
$routeMatch = $router->match($request);
Coisas como o nome do Controller
, Action
e parâmetros extras agora estão disponíveis.
$controllerName = $routeMatch->getParam('controller');
$actionName = $routeMatch->getParam('action');
Para validar com os seus privilégios de ACL, apesar de não ser o escopo deste post, já pode usar algo como o código abaixo.
if ($myAcl->isAllowed($user->getRole(), $controllerName, $actionName)) {
// allowed
} else {
// restricted
}
Mais informações
- http://framework.zend.com/manual/2.3/en/modules/zend.mvc.routing.html
- http://stackoverflow.com/a/24011876
Até a próxima!