Symfony 5.4 debug toolbar not loading because of my dynamic route - php

Im trying to create a cms with Symfony. I want users to be able to create their own pages. I got this all set up but what did not work for me was loading pages with an url that contains a /.
This is my route that does not allow a /:
#[Route('/{slug}', name: 'dynamic_page', defaults: ["slug" => null], methods: ['GET'])]
public function showStoredPage(Page $page)
{
return $this->render('blocks/base.html.twig');
}
If I add requirements: ["slug" => ".+"] to my route, I am able to go to any/route/that/exists with as many slashes as I wish. Which is what I want.
But after adding this I figured that my debug toolbar does not load anymore. The debug bar shows loading... in all pages I have. Also, when looking at the text the symfony built-in server shows in cmd, it keeps looping a request. If I wait long enough the server even crashes because it can never load the toolbar...
How can I make my toolbar load but also keep my route dynamic the way I want it? I'm using Symfony 5.4 with PHP 8+.

It appears this can be solved very easily. I just had to add priority: -1 to my route attribute. Now it looks like this:
#[Route('/{slug}', name: 'dynamic_page', defaults: ["slug" => null], requirements: ["slug" => ".+"], methods: ['GET'], priority: -1)]
Also with the command php bin/console debug:router you can now see the route is on the bottom of the table and the toolbar will load first.

For more control over what the route does, and does not match, without having to rely on the priority setting, you can use a more precise regex. You can use a negative lookahead to define what not to match. All the paths you want to avoid start with '_' so, you could use '(?!_).+' but that will prevent you from matching anything starting with '_'. To only exclude the defined routes use '(?!_(error|wdt|profiler)).+'
#[Route('/{slug}', name: 'dynamic_page', defaults: ["slug" => null], requirements: ["slug" => "(?!_(error|wdt|profiler)).+"], methods: ['GET']]

Related

TYPO3.CMS 9 LTS - cacheable extbase action but no cHash with new routing

Any idea how to solve this? I have an extbase plugin, that has a list and a show action. Both should be cachable and the detail link should not contain a cache hash
I can not achieve this. As soon as i enable the caches i always get the same result for the detail action.
I configured the plugin to be cacheable:
// add detail plugin
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'Vendor.Extension',
'SomePiName',
[
'ControllerName' => 'show',
],
[],
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT
);
The routing config:
routeEnhancers:
MyEnhanceName:
type: Extbase
extension: Extension
plugin: SomePiName
routes:
- { routePath: '/{localized_entry}/{slug}', _controller: 'ControllerName::show', _arguments: {'slug': 'uuid'} }
defaultController: 'ControllerName::show'
aspects:
localized_entry:
type: LocaleModifier
default: 'show'
localeMap:
- locale: 'de_DE.*|de_AT.*|de_CH.*'
value: 'detail'
- locale: 'it_IT.*'
value: 'dettaglio'
slug:
type: customType
My custom aspect works by mapping the foreign uuid on a generated slug, that is stored in a mysql-table i maintain.
I want a deeplink like:
/path/to/page/show/here-comes-the-slug
But i get
/path/to/page/show/here-comes-the-slug?cHash=...
So i added:
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = "tx_extension_somepiname[uuid]";
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = "tx_extension_somepiname[controller]";
$GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParameters'][] = "tx_extension_somepiname[action]";
Now the link looks like:
/path/to/page/show/here-comes-the-slug
But as soon as i activate the caches i always get the same result.
So i need a cache hash calculation but i dont want the fu**er to be in the link...
Links are generated using ContentObjectRenderer->typolink_URL with the config:
[
"parameter" => "t3://myhandler?uuid=someuuid"
]
that handler translates to a subsequent call to ContentObjectRenderer->typolink_URL with the config:
[
"parameter" => "t3://page?uid=someconfiguredpageuid",
"useCacheHash" => 0,
"additionalParams" => "&tx_extension_somepiname[uuid]=uuid&tx_extension_somepiname[controller]=Controller&tx_extension_somepiname[action]=show"
]
So my situation is, that i can EITHER have a cacheHash and a correct result OR nor cacheHash with invalid results.
How is this meant to be done?
You should not exclude parameters that actually distinguish page content from cHash generation. They are really only sane to use with external tracking parameters like fbclid etc.
Also don't use useCacheHash=0 if you rely on caching.
Rather configure the route enhancer to remove the ?cHash.
Okay, i solved this, here the necessary steps:
1) Like Jonas Eberle suggested we remove the extbase arguments from excludedParameters.
2) Configure the details action as cacheable (remove controller->action combination from 2nd array of possible actions in extbase plugin registration / ext_localconf.php)
3) When using a custom aspect, implement the "StaticMappableAspectInterface". I did not find the relevant part in the core but it seems this interface is required! Just have a look at the PersistedAliasMapper.
Now it works...

Is it possible to construct a Symfony path using only parameters?

I would like to reduce the number of repetitive code and give a canonical URL in my Drupal 8 application. Since the routing system is built on Symfony, I included it in the title.
I am constructing paths under routes in my mymodule.routing.yml file. I want to match a specified number of different strings in the first argument, and a slug which can be any string in the second argument. It looks like this:
entity.my_entity.canonical:
path: '/{type}/{slug}'
defaults:
_controller: '\namespace\PostController::show'
requirements:
_permission: 'perm'
type: different|strings|that|can|match|
Now, when I try to access using for example /match/some-slug then it just says "Page not found".
If I something static to the path, for example path: '/j/{type}/{slug}', then it works as expected when I open /j/match/some-slug in the browser.
My boss doesn't like any unnecessary characters in the URL though, so I would like to achieve this by using two parameters, like shown in the first example.
As Yonel mentioned in the comments you can use debug:router to check all your routes. I don't see anything wrong with your code.
Try running bin/console router:match "/match/blaaa" and if you see some controller that isn't the one you want then you'll need to change the route. It shouldn't be the case though because you're getting a 404.
Here's my exact setup that works
routing.yml:
entity.my_entity.canonical:
path: '/{type}/{slug}'
defaults:
_controller: 'MyBundle:Something:foo'
requirements:
type: different|strings|that|can|match|
Inside MyBundle\SomethingController:
public function fooAction($id)
{
return new Response("bar");
}
Then going to http://localhost/match/fom shows the "bar" response.
I have read the documentation again (RTM), and found out that it is not possible in Drupal 8, while it is possible in Symfony.
Note that the first item of the path must not be dynamic.
Source: Structure of routes in Drupal 8

Unable to remove cached page in Symfony 2.6

I am experiencing a weird behaviour with Symfony 2.6
I have a page that lists my users and its routing is in routing.yml as follows:
nononsense_users_homepage:
path: /{page}/{query}
defaults: { _controller: NononsenseUserBundle:Users:index, page: 1, query: 'q'}
Even if I remove the cache the "hard way" by deleting the app/cache folder it does not matter what I do with the controller I always get the same web page!!
Of course I also used:
php app/console cache:clear
with equivalent results setting the env flag also.
If I replace my routing with, for example:
nononsense_users_homepage:
path: /{page}/{query}
defaults: { _controller: kkkkkkkkk, page: 1, query: 'q'}
The page keeps showing. But if I remove the page or query parts the corresponding twig complains.
I changed other actions and routes in the same bundle and I get the expected results when, for example, I replace a whole action by an exit() call...so it is not I am changing the wrong file :-)
I stopped and run several times the server from the console and I even change browsers and users (you have to be logged to access that page) and nothing changes, there is nothing I can do to get an error page!!!
Nevertheless the action has some DB calls to the UsersRepository and if I include an exit() there I get an empty page as expected.
Does anyone know what I am doing wrong.
If you changed the controller in your routing.yml file and the controller does not change, you are probably using a different route. In dev mode, can you check which route is matched and you will most likely see that a different route is matching causing the error.

Symfony2 routing: How to request that the route will be taken from only one template

I heve an embedded controller in my base template. It's a search bar.
For the search bar controller, I have a route "myProject/search".
What I would like is that this route will be taken only when the template where I am embedding the controller (base.html.twig) will call it, and not when i manually put in the browser: "myproject/search".
Any idea on how to do that.
I think, since some time you can't do it:
http://symfony.com/doc/current/book/templating.html#embedding-controllers
quote from the docs:
Even though this controller will only be used internally, you'll need
to create a route that points to the controller
(...)
Since Symfony 2.0.20/2.1.5, the Twig render tag now takes an absolute
url instead of a controller logical path. This fixes an important
security issue (CVE-2012-6431) reported on the official blog. If your
application uses an older version of Symfony or still uses the
previous render tag syntax, you should upgrade as soon as possible.
Anyway, I guess, you can try do it yourself by passing some "secret" argument to search action when you call it from your template. Next in the action you check if the argument was passed to it, and if not you throw 404.
Another way to achieve your goal is use .htaccess file.
You can restrict your route to a certain method by _method option in your routing configuration:
your_rote:
pattern: /myProject/search
defaults: { _controller: YourBundle:YourController:YourAction }
requirements:
_method: POST

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