.. index:: single: Roteamento; Loader de Rota Personalizado Como criar um Loader de Rota personalizado ========================================== Um loader de rota personalizado permite que você adicione rotas a uma aplicação sem incluí-las, por exemplo, num arquivo yaml. Isto é útil quando você tem um bundle, mas não quer adicionar manualmente as rotas ao bundle em ``app/config/routing.yml``. Isso pode ser especialmente importante quando você quer tornar o bundle reutilizável, ou quando o disponibilizar como código aberto, porque iria retardar o processo de instalação e torná-lo suscetível a erros. Alternativamente, você também pode usar um loader de rota personalizado quando quiser que as suas rotas sejam geradas ou localizadas automaticamente com base em alguma convenção ou padrão. Um exemplo é o `FOSRestBundle`_ onde o roteamento é gerado com base nos nomes dos métodos de ação em um controlador. .. note :: Há muitos bundles que usam seus próprios loaders de rotas para realizar casos como os descritos acima, por exemplo `FOSRestBundle`_, `KnpRadBundle`_ e `SonataAdminBundle`_. Carregando Rotas ---------------- As rotas em uma aplicação Symfony são carregadas pelo :class:`Symfony\\Bundle\\FrameworkBundle\\Routing\\DelegatingLoader`. Este loader usa vários outros loaders (delegados) para carregar recursos de diferentes tipos, por exemplo, arquivos YAML ou anotações ``@Route`` e ``@Method`` em arquivos de controlador. Os loaders especializados implementam a :class:`Symfony\\Component\\Config\\Loader\\LoaderInterface` e, portanto, tem dois métodos importantes: :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::supports` e :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::load`. Considere essas linhas do ``routing.yml``: .. code-block:: yaml _demo: resource: "@AcmeDemoBundle/Controller/DemoController.php" type: annotation prefix: /demo Quando o loader principal realiza o parse, ele tenta todos os loaders delegados e chama seu método :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::supports` com o determinado recurso (``@AcmeDemoBundle/Controller/DemoController.php``) e tipo (``annotation``) como argumentos. Quando um dos loaders retorna ``true``, seu método :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::load` será chamado, que deve retornar um :class:`Symfony\\Component\\Routing\\RouteCollection` contendo objetos :class:`Symfony\\Component\\Routing\\Route`. Criando um Loader Personalizado ------------------------------- Para carregar rotas de alguma fonte personalizada (ou seja, de algo diferente de anotações, arquivos YAML ou XML), você precisa criar um loader de rota personalizado. Este loader deve implementar a :class:`Symfony\\Component\\Config\\Loader\\LoaderInterface`. O loader de exemplo abaixo, suporta o carregamento de recursos de roteamento com um tipo ``extra``. O tipo ``extra`` não é importante - você pode simplesmente inventar qualquer tipo de recurso que desejar. O próprio nome do recurso não é realmente usado no exemplo:: namespace Acme\DemoBundle\Routing; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\Config\Loader\LoaderResolverInterface; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; class ExtraLoader implements LoaderInterface { private $loaded = false; public function load($resource, $type = null) { if (true === $this->loaded) { throw new \RuntimeException('Do not add the "extra" loader twice'); } $routes = new RouteCollection(); // prepare a new route $pattern = '/extra/{parameter}'; $defaults = array( '_controller' => 'AcmeDemoBundle:Demo:extra', ); $requirements = array( 'parameter' => '\d+', ); $route = new Route($pattern, $defaults, $requirements); // add the new route to the route collection: $routeName = 'extraRoute'; $routes->add($routeName, $route); return $routes; } public function supports($resource, $type = null) { return 'extra' === $type; } public function getResolver() { // needed, but can be blank, unless you want to load other resources // and if you do, using the Loader base class is easier (see below) } public function setResolver(LoaderResolverInterface $resolver) { // same as above } } .. note:: Certifique-se que o controlador que você especificou realmente existe. Agora defina um serviço para o ``ExtraLoader``: .. configuration-block:: .. code-block:: yaml services: acme_demo.routing_loader: class: Acme\DemoBundle\Routing\ExtraLoader tags: - { name: routing.loader } .. code-block:: xml .. code-block:: php use Symfony\Component\DependencyInjection\Definition; $container ->setDefinition( 'acme_demo.routing_loader', new Definition('Acme\DemoBundle\Routing\ExtraLoader') ) ->addTag('routing.loader') ; Observe a tag ``routing.loader``. Todos os serviços com esta tag serão marcados como potenciais loaders de rota e adicionados como roteadores especializados para o :class:`Symfony\\Bundle\\FrameworkBundle\\Routing\\DelegatingLoader`. Usando o Loader Personalizado ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Se você não fez nada mais, seu loader de roteamento personalizado *não* será chamado. Em vez disso, você só precisa adicionar algumas linhas extras para a configuração de roteamento: .. configuration-block:: .. code-block:: yaml # app/config/routing.yml AcmeDemoBundle_Extra: resource: . type: extra .. code-block:: xml .. code-block:: php // app/config/routing.php use Symfony\Component\Routing\RouteCollection; $collection = new RouteCollection(); $collection->addCollection($loader->import('.', 'extra')); return $collection; A parte importante aqui é a chave ``type``. Seu valor deve ser "extra". Este é o tipo que nosso ``ExtraLoader`` suporta e que irá certificar-se que seu método ``load()`` é chamado. A chave ``resource`` é insignificante para o ``ExtraLoader``, então defina ela como ".". .. note :: O cache das rotas definidas usando loaders personalizados será feita automaticamente pelo framework. Assim, sempre que você mudar alguma coisa na classe do loader, não se esqueça de limpar o cache. Loaders mais Avançados ---------------------- Na maioria dos casos é melhor não implementar a :class:`Symfony\\Component\\Config\\Loader\\LoaderInterface` você mesmo, mas estender do :class:`Symfony\\Component\\Config\\Loader\\Loader`. Esta classe sabe como usar um :class:`Symfony\\Component\\Config\\Loader\\LoaderResolver` para carregar os recursos de roteamento secundários. Claro que você ainda precisa implementar :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::supports` e :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::load`. Sempre que quiser carregar outro recurso - por exemplo, um arquivo de configuração Yaml - você pode chamar o :method:`Symfony\\Component\\Config\\Loader\\Loader::import` method:: namespace Acme\DemoBundle\Routing; use Symfony\Component\Config\Loader\Loader; use Symfony\Component\Routing\RouteCollection; class AdvancedLoader extends Loader { public function load($resource, $type = null) { $collection = new RouteCollection(); $resource = '@AcmeDemoBundle/Resources/config/import_routing.yml'; $type = 'yaml'; $importedRoutes = $this->import($resource, $type); $collection->addCollection($importedRoutes); return $collection; } public function supports($resource, $type = null) { return $type === 'advanced_extra'; } } .. note:: O nome e o tipo do recurso da configuração de roteamento importada pode ser qualquer coisa que é normalmente suportada pelo loader de configuração de roteamento (YAML, XML, PHP, anotação, etc.) .. _`FOSRestBundle`: https://github.com/FriendsOfSymfony/FOSRestBundle .. _`KnpRadBundle`: https://github.com/KnpLabs/KnpRadBundle .. _`SonataAdminBundle`: https://github.com/sonata-project/SonataAdminBundle