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

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.
}
}

Related

No route found for "GET /Index" when generating Symfony controller

I am using generate:controller to create a new controller in my Symfony 3 application. But the route is not getting found.
Here is the input/output of the command ...
First, you need to give the controller name you want to generate.
You must use the shortcut notation like AcmeBlogBundle:Post
Controller name: ApplicationSonataPageBundle:Page
Determine the format to use for the routing.
Routing format (php, xml, yml, annotation) [annotation]: yml
Determine the format to use for templating.
Template format (twig, php) [twig]:
Instead of starting with a blank controller, you can add some actions now. An action
is a PHP function or method that executes, for example, when a given route is matched.
Actions should be suffixed by Action.
New action name (press <return> to stop adding actions): IndexAction
Action route [/Index]:
Template name (optional) [ApplicationSonataPageBundle:Page:index.html.twig]:
New action name (press <return> to stop adding actions):
Summary before generation
You are going to generate a "ApplicationSonataPageBundle:Page" controller
using the "yml" format for the routing and the "twig" format
for templating
Do you confirm generation [yes]?
... and here is the content of the new controller class:
namespace Application\Sonata\PageBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class PageController extends Controller
{
public function IndexAction()
{
return $this->render('ApplicationSonataPageBundle:Page:index.html.twig', array(
// ...
));
}
}
... which is not called. I instead receive the following error in the browser:
No route found for "GET /Index"
Is there an additional step I need to do before seeing my action?
What I have tried: I have so far tried every other type of routing (xml, php, yml) without success.
There are a couple of things to check:
Make sure your routes are included inside config/routes.yml
https://symfony.com/doc/3.3/routing.html
https://symfony.com/doc/3.3/routing.html#loading-routes
https://symfony.com/doc/3.3/routing/external_resources.html
Also make sure your bundle is loaded in the kernel: app/AppKernel.php
https://symfony.com/doc/3.3/page_creation.html#bundles-configuration
Another thing I notice, your action/route is capitalized. I'm not sure if this effects things but the common practice is camelCasing so you would have indexAction rather than IndexAction
There is also a command to show routes that are available I believe it is something like php bin/console routes:debug if you run php bin/console it should show you available commands
For what it's worth: I ended up just giving up and copying the following:
_index:
path: /Index
defaults: { _controller: ApplicationSonataPageBundle:Page:Index }
... from the generated yml file into my app's main routing.yml file.

Is it possible to override a route handler in Symfony2?

Say a template application is created with Symfony2. It contains a product description page and the route is created/handled as following:
class ProductController extends Controller
{
/**
* #Route("/product/{id}")
*/
public function showDecription($id)
{
// ...
}
}
Custom applications are created based on the template application. In other words, the template application provides 'a default value'.
Is it possible to override the route handler in a custom application without modifying the code of the template application? If the route needs to be declared in a different way in the template application in order to be overridable, that's ok. How should one proceed in this case?
Symfony guide has the following information on overriding a route:
Routing
Routing is never automatically imported in Symfony. If you want to
include the routes from any bundle, then they must be manually
imported from somewhere in your application (e.g.
app/config/routing.yml).
The easiest way to "override" a bundle's routing is to never import it
at all. Instead of importing a third-party bundle's routing, simply
copy that routing file into your application, modify it, and import it
instead.
The main routing file is app/config/routing.yml. I suggest you to create 2 more files: app/config/routing_default.yml and app/config/routing_override.yml and then edit your app/config/routing.yml as
override:
resource: routing_override.yml
default:
resource: routing_default.yml
Now in routing default you can add all default applications routes. And in override one - all additional ones.
Also route names in override and default should not be the same. If you want to override route by name you should change the order of includes.

Symfony, dynamic routing

I have a symfony project with multiple skins/templates that have their own routes, does anyone have an idea for a correct setup?
Every skin/template is its own bundle, since its not just skins and assets, but maybe also services that might exist in some skins.
Hostname decides the skin.
Using a custom RouteLoader to load the route.yml of the target bundle.
The custom RouteLoader does the job--but the generated routes are getting cached, and as far as i understand, there is no way to prevent route caching.
Some suggestions are:
Creating a /{dynamic} route, so manually form routes.. But i dont want to throw away that piece of functionality of the router, or refactor the entire project..
Prefix the routes with the template identifier. This would require me to load all route.yml files, which isnt possible since their share paths.
Anyone? I cant go with multiple projects really, the amount of skins will be around 20-30~.
The reason for this setup is because its a target of Content-as-a-Service .. service, multiple clients use the project as a platform, and their setting decides which templates gets used.
It sounds like you want to dynamically load bundles based on the host name? Not going to happen with Symfony 2 because of the caching. Especially the services.
Your best bet is to setup an app for each skin and then do some url majic to execute the desired app.php file. Clearly since you have defined a bundle for each skin then there is a finite number so having multiple apps should not be much or a burden.
It's possible that you might be able to work around the template issue. You would still need to load all your skin bundles but you could futz around with the template names or paths and probably get something to work.
But services? Unless you start appending host names to service id's then I don't see any work around.
I think it's possible to load dynamically twig templates depending of your user by adding a listener on kernel requests.
I can give you a piece of code which, I hope, could help you :
/**
* On Kernel Request triggers the request to get the user config
* then adds TWIG paths depending on user TemplateName
*/
public function onKernelRequest(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
//$userConfig = Retrieve your user config
if (null === $userConfig->getTemplateConfig()->getTemplate()->getName())
{
throw new TemplateConfigNotFoundException(sprintf("Could not find TemplateConfig for %s", $userConfig->getName()));
}
$template = $userConfig->getTemplateConfig()->getTemplate()->getName();
$path = sprintf('%s/../../%s/Resources/views', __DIR__, ucfirst($template));
if (!is_dir($path)) {
throw new TemplateNotFoundException(sprintf("Could not find template %s", $template));
}
$this->loader->prependPath($path);
$this->loader->addPath(sprintf('%s/../Resources/views/Default', __DIR__));
}
With $this->loader defined as \Twig_Loader_Filesystem in your Listener constructor
Hope it can give you a clue
Symfony2 already supports host aware routing out-of-the-box, like this:
website_customer_1:
path: /
host: customer1.example.com
defaults: { _controller: Customer1Bundle:Main:startPage, theme: template1 }
website_customer_2:
path: /
host: customer2.example.com
defaults: { _controller: Customer1Bundle:Main:startPage, theme: template2 }

cakephp 3 prefix routing

I'm trying to set up a routing prefix in cakephp 3 so any URLs starting with /json/ get the prefix key set and I can change the layout accordingly in the app controller. Other than that, they should use the usual controller and action. I have added the following to routes.php
$routes->prefix('json', function($routes) {
$routes->connect(
'/:controller/:action/*',
[],
['routeClass' => 'InflectedRoute']
);
});
I want to direct all requests with json as first url segment to controller specified in second url segment. e.g. /json/users/add_account_type/ goes to users controller. However when accessing this URL I get the message:
Error: Create the class UsersController below in file:
src/Controller/Json/UsersController.php
whereas I want it to be using
src/Controller/UsersController.php
I think this should be possible but I can't quite see what I'm doing wrong when consulting the book. Have partly based my code on: CakePHP3.x controller name in url when using prefix routing
Thanks a lot in advance
That's simply how prefix routing now works in 3.x, as explained in the docs, prefixes are being mapped to subnamespaces, and thus to separate controllers in subfolders.
http://book.cakephp.org/3.0/en/development/routing.html#prefix-routing
If you'd wanted to change that behavior (I don't really see why), one way would be to implement a custom ControllerFactory dispatcher filter.
http://book.cakephp.org/3.0/en/development/dispatch-filters.html
On a side note, the RequestHandler component supports layout/template switching out of the box, so maybe you should give that a try.
http://book.cakephp.org/3.0/en/controllers/components/request-handling.html
http://book.cakephp.org/3.0/en/views/json-and-xml-views.html
Prefix routing is a way of namespacing parts of your routes to a dedicated controller. It seem that what you want is a scope and not a prefix, for what you describe:
Router::scope('/json', function($routes) {
$routes->fallbacks('InfledtedRoute')
});

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.

Categories