Auto Routing Bundle - and parameters? (Symfony CMF) - php

I was successful with getting Symfony CMF and Auto Routing Bundle (and a custom contoller) to load documents in the following manner (path):
.../category/article-name
This works fine. But I need something like this, easily achieved by standard Symfony2:
.../category/article-name/{page}
Where page is passed to a controller as a parameter,
eg. $page = 2 -> controller processes content of the Article document to display only given page
or $page = null -> (so no {page} parameter at all) - as above, but displayed is page default that is 1
How to make routing-auto bundle of the Symfony CMF to use parameters in routes?
So that the basic path is exactly as it is configured as in this Auto Routing Bundle configuration, but additionally I can use parameters passed to a controller, so that additional decisions can be made upon them. Any hints? Thanks!
My config for auto routing:
MyApp\MyCmsBundle\Document\Article:
content_path:
#fixed path of all categories and therefore articles
articles_categories_path:
provider: [specified, { path: /cms/routes }]
exists_action: use
not_exists_action: throw_exception
#category path
category_path:
provider: [content_method, { method: getRouteNodeCategory }]
exists_action: use
not_exists_action: throw_exception
#article name
content_name:
provider: [content_method, { method: getTitle }]
exists_action: [auto_increment, { pattern: -%d }]
not_exists_action: create
MyApp\MyCmsBundle\Document\ArticlesCategory:
content_path:
#fixed path of all categories and therefore articles
articles_categories_path:
provider: [specified, { path: /cms/routes }]
exists_action: use
not_exists_action: throw_exception
#category name
content_name:
provider: [content_method, { method: getTitle }]
exists_action: use
not_exists_action: create
getRouteNodeCategory() of the Article Document just returns a parents (i.e. category) name. Here's part of this document content:
public function getRouteNodeCategory()
{
return $this->parent->getTitle();
}

This is not currently possible in the RoutingAutoBundle but it could be easily implemented.
The RoutingAutoBundle creates Route documents which extend the CMF's Route object. These Route objects do support variable patterns which allow you to specify dynamic paramters:
https://github.com/symfony-cmf/RoutingBundle/blob/1.2/Model/Route.php#L53
So we would just need to extend the mapping to include details on dynamic (variable) parameters in the URL.
Note also that the a new version of the routing auto bundle will soon be released which features a much better configuration format.
If you could create an issue detailing your use case, we will try and implement it for the 1.0 release.

Related

Routing order symfony 4

I want to have a url with a wildcard at the end site.com/{username} after trying to match url's like site.com/photos and site.com/blog. I'm using annotations and have two controllers.
I found an answer here Ordering of routes using annotations
But the folder structure is different in version 4 and in the answer they are using YAML while I'm using annotations, so I don't fully understand where to put what.
Video Controller
/**
* #Route("/videos", name="videos")
*/
public function index()
{
// Show video homepage
}
User Controller
/**
* #Route("/{username}", name="profile")
*/
public function index()
{
// Hello {username} !
}
In this order, site.com/videos reaches User controller instead of videos. Do I have to switch to manually putting all URL structures in yaml format or is there a way to set priority in annotations?
So far the only method I found was to create a controller starting with the letter "Z", and putting the action/route in there, that seems to run the route last.
The question you linked to is actually very relevant. You are asking just the same as the other guy:
But how can you do this if you define your routes as annotations in your controllers? Is there any way to specify the ordering of this routes in this case?
In Symfony 4, your config/routes.yaml is probably empty and config/routes/annotations.yaml probably like this:
controllers:
resource: ../../src/Controller/
type: annotation
You can replace the above YAML with this – notice that the order does matter:
Video:
resource: App\Controller\VideoController
type: annotation
User:
resource: App\Controller\UserController
type: annotation
Then site.com/videos reaches the video controller first.
You have to define your routes with yml/xml to be able to fully configure their order.
If you really want to use annotation you could add a prefix like user-:
/**
* #Route("/user-{username}", name="profile")
*/
public function index()
{
// Hello {username} !
}

Symfony 2 dynamic routing (e.g. for stores)

I'm new at Symfony 2, now I'm trying to get a dynamic routing, I mean really dynamic.
For example:
example.com/en/categoryLevel1/categoryLevel2/categoryLevel3/productId-ProductName
OR
example.com/en/categoryLevel1/categoryLevel2/productId-ProductName
OR
example.com/en/categoryLevel1/categoryLevel2/categoryLevel3/
The number of category levels (the category depth) have to be flexible to 100%. It must be possible and able to use one level to twenty levels.
Where is the entry point to setup this (which classes are doing those routing stuff)?
Another example is:
routes on the old page:
example.com/{categoryLvl1}/{categoryLvl2}/.../p-{productId}
at the new page are some changes in the routes:
example.com/{lang}/{catLevel1}/{catLevel2}/.../{productId}-{productName}
how i do the regex, etc.. i know. But i can't find the routing process in symfony (better the pre-routing process). I would like to build an pre-routing class and fallback the "normal" symfony2 routing. i have to match old and new, both are completely dynamic.. the old one is written in ZF1 (pretty easy for me) but symfony2 is a new area for me...
Let's assume you have a bundle that handles this type of URL, you might add the following in the bundle's routing.yml (I prefer yml, YMMV).
YourSomethingBundle_main_any:
pattern: /{request}
defaults: { _controller: YourSomethingBundle:Main:dispatcher }
requirements:
request: ".*"
Important: This is a “catch-all”, letting you process the actual request path in your controller. You should either prefix the pattern path, or load this bundle after all other bundles, or other routes will no longer work.
As per SF2 conventions, you would now have a MainController class with a dispatcherAction method:
<?php
namespace Your\SomethingBundle\Controller;
use \Symfony\Bundle\FrameworkBundle\Controller\Controller;
class MainController extends Controller
{
public function dispatcherAction($request='')
{
$request = preg_split('|/+|', trim($request, '/'));
// ... and so on.
}
}

Getting the file_locator service in symfony2 custom router

I want to create a custom route loader as instructed in http://symfony.com/doc/current/cookbook/routing/custom_route_loader.html.
What I have to do is read the read the routes from an xml file (not in "symfony xml" format) and create the according route collection.However I want to do that using the '#' directive.as in:
xmlRoutes:
resource: '#FooBarBundle/Resources/routes.xml'
But in order to resolve the path to routes.xml I need the 'file_locator' service from the container.is it possible to access services in a custom router class.if not, how can I make a symfony\Component\Config\FileLocator to resolve that path?
Yes you could access the file_locator as it's a service. What you need to do is make your custom_route_loader a service itself (I dind't read the cookbook you linked but I'm pretty sure that they would advice to define it as a service) and inject the file_locator service into it.
So basically you'll do something like
#config.yml
[...]
services:
yourbundlename.custom_route_loader:
class: Path\To\Your\Bundle\CustomRouteLoader
arguments: [ #file_locator ]
And into you CustmRouteLoaderClass
#Path\To\Your\Bundle\CustomRouteLoader
class CustomRouteLoader
{
public function __construct(Symfony\Component\HttpKernel\Config\FileLocator $file_locator) {
$this->file_locator = $file_locator;
[...]
}
[...]
}

Defining default routing for controller/action in symfony 2

If I wanted to make it so that every url call apart from ones I have defined after act upon /ExplicitControllerName/ExplicitActionToRun... how might the routing look like.
for example some pseudo code:
default_pathing:
pattern: /{controller}/{action}
defaults: { _controller: Bundle:Default:index }
So if I went to
www.example.com/Page/About
it would call my controller
class Page extends Controller
{
public AboutAction()
{
// Called by above URL
}
}
This question does not answer: Symfony2 / routing / use parameters as Controller or Action name
Imagine I have 100 pages with lots of sub routing pages doing pretty much the same routing every time. I want to do 1 routing for all those 100 controllers. How would we do this?
P.S I'm really going for something like the C#.NET MVC 4.0 routing in which it allows you to set a routing for a typical setup you might have even if at the very least its for development
Your question is not totally clear but here are some hints.
I can imagine two use cases you're trying to solve:
1) You've a lot of some sort of CMS page, like your about example, these pages don't have much logic and just render some view, in such case you would something like:
class CMSPageController
{
public function renderPage($pageSlug)
{
$page = $this->cmsPageRepository->findBySlug($pageSlug);
// your logic to render the view
}
}
And the according routing configuration:
<route id="cms_page_view" pattern="/cms/{pageSlug}">
<default key="_controller">cms_page.controller.page:renderPage</default>
<requirement key="_method">GET</requirement>
<requirement key="slug">[0-9a-zA-Z\-\.\/]+</requirement>
</route>
2) You have much more complex requirements, and/or follow a specific pattern to name your controller/action, therefore you need to write a custom UrlMatcherInterface implementation. Take a look at the native implementation to know where to start. It would allow you define a fallback.
This can be achieved using either SensioFrameworkExtraBundle's #Route annotation on class- and method-level excessively...
... or more elegant with less annotations using FOSRestBundle's automatic route generation with implicit resource names. Maybe you'll need to correct some of the generated routes using some of FOSRestBundle's manual route definition annotations.
Both methods originally still leave the need to explicitly add the route resources to your app/config/routing.yml.
Example import for #Route
# import routes from a controller directory
blog:
resource: "#SensioBlogBundle/Controller"
type: annotation
Example import for FOSRestBundle
users:
type: rest
resource: Acme\HelloBundle\Controller\UsersController
You could work around having to import all the resources by:
introducing a custom annotation (class-level)
creating a compiler pass or a custom route loader in which you ...
use the Finder to find all controller classes in all bundles with that annotation
finally add all those as resources with type annotation/rest to the route collection in there
If you don't plan to use hundreds of controllers and don't have too much experience with compiler-passes, custom annotations, ... etc. you'll definitely be faster just registering the resources in the routing config.

Routing in Symfony2

How to setup default routing in Symfony2?
In Symfony1 it looked something like this:
homepage:
url: /
param: { module: default, action: index }
default_symfony:
url: /symfony/:action/...
param: { module: default }
default_index:
url: /:module
param: { action: index }
default:
url: /:module/:action/...
I was looking through the cookbook for an answer to this, and think I've found it here. By default, all route parameters have a hidden requirement that they match any character except the / character ([^/]+), but this behaviour can be overridden with the requirements keyword, by forcing it to match any character.
The following should create a default route that catches all others - and as such, should come last in your routing config, as any following routes will never match. To ensure it matches "/" as well, a default value for the url parameter is included.
default_route:
pattern: /{url}
defaults: { _controller: AcmeBundle:Default:index, url: "index" }
requirements:
url: ".+"
I don't think it's possible with the standard routing component.
Take a look to this bundle, it might help :
https://github.com/hidenorigoto/DefaultRouteBundle
// Symfony2 PR10
in routing.yml:
default:
pattern: /{_controller}
It enables you to use this kind of urls: http://localhost/MySuperBundle:MyController:myview
Symfony2 standard routing component does not support it, but this bundle fills the gap Symfony1 left:
https://github.com/LeaseWeb/LswDefaultRoutingBundle
It does what you expect. You can default route a bundle using this syntax:
FosUserBundle:
resource: "#FosUserBundle"
prefix: /
type: default
It scans your bundle and automatically adds routes to your router table that you can debug by executing:
app/console router:debug
Example of automatically added default routes:
[router] Current routes
Name Method Pattern
fos_user.user.login_check ANY /user/login_check.{_format}
fos_user.user.logout ANY /user/logout.{_format}
fos_user.user.login ANY /user/login.{_format}
...
You see that it also supports the automatic "format" selection by using a file extension (html, json or xml).
Here is an example: http://docs.symfony-reloaded.org/master/quick_tour/the_big_picture.html#routing
A route definition has only one mandatory parameter pattern and three optionals parameters defaults, requirements and options.
Here's a route from my own project:
video:
pattern: /watch/{id}/{slug}
defaults: { _controller: SiteBundle:Video:watch }
requirements: { id: "\d+", slug: "[\w-]+"
Alternatively, you can use #Route annotation directly in a controller file. see https://github.com/sensio/SensioFrameworkExtraBundle/blob/master/Resources/doc/annotations/routing.rst
As for the default routes, I think Symfony2 encourages explicit route mapping.
Create a default route is not a good way of programming. Why? Because for this reason was implemented Exception.
Symfony2 is built just to do right things in the right way.
If you want to redirect all "not found" routes you should use exception, like NotFound404 or something similar. You can even customise this page at your own.
One route is for one purpose. Always. Other think is bad.
You could create your own bundle that handled all requests and used URL parameters to construct a string to pass to the controller's forward method. But that's pretty crappy, I'd go with well defined routes, it keeps your URLs cleaner, and decouples the URL and controller names. If you rename a bundle or something, do you then have to refactor your URLs?
If you want to create a "catch all", your best bet would be to hook on the KernelEvents::EXCEPTION event. This event gets triggered whenever an Exception falls through to the HttpKernel, this includes the NotFoundHttpException thrown when the router cannot resolve a route to a Controller.
The effect would be similar to Symfony's stylized 404 page that gets rendered when you send the request through app_dev.php. Instead of returning a 404, you perform whatever logic you're looking to.
It depends... Some of mine look like this:
api_email:
resource: "#MApiBundle/Resources/config/routing_email.yml"
prefix: /
and some look like
api_images:
path: /images/{listingId}/{width}/{fileName}
defaults: { _controller: ApiBundle:Image:view, listingId: null, width: null, fileName: null }
methods: [GET]
requirements:
fileName: .+

Categories