Check if route exists in Symfony 4 - php

How can I test whether a given route exists in Symfony 4 by using the route name.
routes.yaml
home:
path: /
controller: App\Controller\Home::index
methods: [GET]
login:
path: /login
controller: App\Controller\Login::index
methods: [GET]
Controller (making up an exists() method here)
$routes->exists('home'); // true
$routes->exists('login'); // true
$routes->exists('foo'); // false

From the Symfony 4 Documentation...
Check if a Route Exists
In highly dynamic applications, it may be necessary to check whether a route exists before using it to generate a URL. In those cases, don't use the getRouteCollection() method because that regenerates the routing cache and slows down the application.
Instead, try to generate the URL and catch the RouteNotFoundException thrown when the route doesn't exist:
use Symfony\Component\Routing\Exception\RouteNotFoundException;
// ...
try {
$url = $generator->generate($dynamicRouteName, $parameters);
} catch (RouteNotFoundException $e) {
// the route is not defined...
}
You can put that code inside a function and return whatever you need.

Related

Advanced routing in Symfony v3

I'm after a custom routing method so I can have below links to be handled by single controller action:
/q-query_term
/category-category_name/city-city_name/q-query_term
/city-city_name/category-category_name/q-query_term
/city-city_name/q-query_term
/category-category_name/q-query_term
/city-city_name
/category-category_name
Is it possible even possible? I don't use SensioExtraBundle so routes has to be written down in yaml.
For instance in Zend Framework 2 it is possible quite easily, because I can write a class, which would handle the routing as a wish. Don't know how to achieve the same in Symfony though, any help would be appreciated.
The only way I can come up with is to create a custom route loader, calculate all route permutations and return that collection, but don't know if it the best solution possible.
This question is unique, because I need to use single route name instead of specyfing tens of different route definitions.
A simple solution would be to define the route as catch-all …
# Resources/config/routing.yml
catch_all:
path: /{path}
defaults: { _controller: FooBarBundle:Catchall:dispatcher, path : "" }
requirements:
path: ".*"
… and do all further processing in the controller:
# Controller/CatchallController.php
class CatchallController extends Controller
{
public function dispatcherAction(Request $request, string $path)
{
if (/* path matches pattern 1 */)
return $this->doQuery($request, $path);
elseif (/* path matches pattern 2 */)
return $this->doCategoryCityQuery($request, $path);
// ... and so on
else
return new Response("Page not found", 404);
}
private function doQuery($request, $path)
{
// do stuff and return a Response object
}
private function doCategoryCityQuery($request, $path)
{
// do stuff and return a Response object
}
}

Symfony routing: how to redirect from UUID to custom slug

I have an entity that is reachable both using http://example.com/company/d9c363ae-a1b7-11e6-a66d-9e9923e30d94/ and http://example.com/company/custom-domain.com.
Now, the Company can have a slug, but can also not have one.
So, I'd like to check if it has a domain set and if it has and if the URL is based on UUID, I want to redirect it to the version with the slug. If it hasn't a domain set, I simply show the page using the UUID.
I've done this following this Symfony's tutorial:
# routing.yml
redirect_company_to_domain:
path: /company/{domain_host_or_id}
defaults: { _controller: AppBundle:Company:redirectToDomain }
requirements:
url: .*/$
methods: [GET]
And in my controller I have write this method:
/**
* Redirect the URLs with a trailing slash to the version without it.
*
* #param Request $request
*
* #return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function redirectToDomainAction(Company $company, Request $request)
{
die(dump($company));
}
The problem is that the controller is never called.
What am I missing or doing wrong? Why the path is never intercepted by the route?
Maybe because I've mixed annotations and configuration in routing.yml? Because the routes of the CompanyController is all set using annotations.
But using app/console debug:router I can see correctly the route set:
redirect_company_to_domain GET ANY ANY /company/{domain_host_or_id}
Also, I'm sure the method described in the tutorial works as I've implemented it to remove trailing slashes.
I don't understand why it isn't working to make this redirect.
I think because you've specified the parameter (in brackets) incorrectly.
Can you try this instead:
redirect_company_to_domain:
path: /company/{domain_host_or_id}
defaults: { _controller: AppBundle:Company:redirectToDomain }
requirements:
domain_host_or_id: .*/$
methods: [GET]
I think that's the problem, but I'm not 100% certain. Can you try it out and let us know?

Symfony2 Controller for Uri is not callable but the Uri is ok, what's happen?

I have a little problem, I've just found this problem in other users, but the solution is not working for me, because apparently my code is right:
I have this route:
rs_shoppingcart:
pattern: /carrito
defaults: { _controller: rsBundle:Default:shoppingcart}
And this is the Controller:
public function shoppingcartAction(){ ...
...
if($peticion->getMethod() == 'POST'){
...
And basicly, It's a form, first time I can go to the "carrito" route, but when I submit the form, It give me the next error:
The controller for URI "/carrito" is not callable.
What do you thing?
Thank you in advance
Probably the problem occurs in this line:
defaults: { _controller: rsBundle:Default:shoppingcart}
in reBundle a namespace is missing - you should add ther the parent directory of your bundle. In example - GeneralRsBundle:Default:shoppingcart
Make sure shoppingcart matches the string (not ignoring case) before Action in your Controller method.

need some help about codeigniter route

Is there a way to make the route in codeigniter work like that in symfony?
Cause in there you can rename the route path and it still wouldn't affect your output cause what you call is the route name not the route path unlike in codeigniter.
For example, in symfony, routes are set like this:
news_index:
path: /news
defaults: { _controller: CmsBundle:News:index }
news_view:
path: /news/view/{id}
defaults: { _controller: CmsBundle:News:view }
and then I can access that in my template by calling the route name, not the route path
<?php
// outputs: /news
echo $view['router']->generate('news_index');
// outputs: /news/view/1
echo $view['router']->generate('news_view',array('id' => $news_id));
?>
so if I change the route path it wouldn't affect the way i call it in my code because i'm calling the route name, all it will do is change the output:
news_index:
path: /articles
defaults: { _controller: CmsBundle:News:index }
news_view:
path: /articles/item/{id}
defaults: { _controller: CmsBundle:News:view }
still same code but output is changed
<?php
// outputs: /articles
echo $view['router']->generate('news_index');
// outputs: /articles/item/1
echo $view['router']->generate('news_view',array('id' => $news_id));
?>
while in codeigniter, if i set my route like this:
$route['news'] = 'NewsController';
$route['news/view/(:num)'] = 'NewsController/view/$1';
the only way i know to call it is by the route path:
<?php
echo anchor('news');
echo anchor('news/view'.$news_id);
?>
and if I change my path, I would have to change what I wrote in view as well. That would be a hassle. So I'm wondering if there could be a way to make it work like in symfony. I would appreciate it if anyone could help me. And I apologize if my explanation is not clear. English is not my mother tongue :)
There is blog post available from #kennyk that describes his approach to symfony-like named routes using a router extension.
The article is called Easy Reverse Routing with CodeIgniter.
I guess that's what you're looking for.

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