I want my custom error pages to use my main application base template. By base template uses KnpMenu to build a menu. Parts of the meny are only rendered for privileged users, and do to do that I inject the security component and do checks like this:
if ($security->isGranted('ROLE_COURSES')) {
However, when there's a 404 an exception is thrown in the routing component which is executed before the firewall component is run.
I'm not entirely sure what is actually injected into the menu builder since the security component has not yet run, but regardless, I'm getting another exception when I try to go to a non-existent page in production when that if statement is executed.
What's the recommended approach here? If I have to abandon rendering the menu for my 404's, I guess that's ok, but I was hoping I could still render the menu in its complete form.
I know this is an old issue, but facing this problem myself I fixed it by creating an extra route which matches everything and is the last thing to match of my routes:
pageNotFound:
pattern: /{path}
defaults: { _controller: MyContentBundle:PageNotFound:pageNotFound, path: '' }
requirements:
path: .*
The action is simply:
public function pageNotFoundAction()
{
throw new NotFoundHttpException();
}
Since you are throwing the NotFound exception from a controller, the firewall has already been run and you now have app.user in your custom 404 error page.
There are tonnes about this around the internet, it's related to the routing being loaded before the security context so when the route isn't found the user isn't even created.
A way to use it in your template is to use {% if app.user is not null and is_granted() %} as stated in https://github.com/symfony/symfony-docs/issues/2078.
I assume that could be translated to
if (null !== $securityContext->getToken() && $securityContext->isGranted())
but I haven't tried it so I'm not sure.
Related
I'm trying to use Lexikjwtauthenticator on a Symfony project but I cannot figure out where is the /api/login_check Controller defined.
I'm receiving "Unable to find the controller for path "/api/login_check". The route is wrongly configured." all the times.
The only way to work around this is to define a form_login (other than json_login) configuration inside the login firewall. Is it correct or am I missing something?
Thanks
I discovered that the real problem was caused by using "postman" which apparently sends data as "form" instead of "json".
Modifying security.yaml "json_login" and replacing it with "form_login" (which is documented) everything seems to work fine with Postman.
I still have to try it from my JS front-end.
I'm using the Symfony CMF Routing Bundle to create dynamic routes (I'm using one example here):
$route = new Route('/dynamic-url');
$route->setMethods("GET");
$route->setDefault('_controller', 'AppBundle:MyRoute:getResponse');
$routeCollection->add('my-dynamic-route', $route);
The response is loaded from the getResponseAction() function inside the MyRouteController:
/**
* No annotations here, because I want the url to be dynamic from the database
*/
public function getResponseAction(Request $request) {
return $this->render('dynamic-page-template.html.twig');
}
When I go to '/dynamic-url', it works.
When in another controller, I want to redirect to this dynamic route, like this:
return $this->redirectToRoute('my-dynamic-route');
But I get this error: "None of the chained routers were able to generate route: Route 'my-dynamic-route' not found"
Also interesting: when I go to '/dynamic-url', the dev bar actually says that the Route name is 'my-dynamic-route'.
Edit
When I load all the routes, I don't see my dynamic route names:
$this->get('router')->getRouteCollection();
I think they should be in this list.
Since it's a dynamic route, which wasn't saved anywhere (like routing.yml ) it will be only availabe for Request where it has been defined. So at the end of Request your app will immediately "forget" about new Route generated at runtime.
When I load all the routes, I don't see my dynamic route names:
$this->get('router')->getRouteCollection();
I think they should be in this list.
Actualy No. It depends on where you call $this->get('router')->getRouteCollection();
Just try to call
dump($this->get('router')->getRouteCollection();)
right before the return statement in your Action where you're adding the my-dynamic-route route. I'm sure you'll see your my-dynamic-route in the list of routes, but if you call it anywhere else - you won't see it.
It's less about symfony rather about stateless nature of web (see Why say that HTTP is a stateless protocol?)
I started to think about this and pointed your question to an routing issue on symfony-cmf. You tagged with #symfony-cmf and i think this would be important feature for us.
I also think, when you persist your route with /my-route you should also ask the router for that name (or in case of the CMF with an content object with that a route.)
If you use the CmfRoutingBundle dynamic router, you should persist your routes to doctrine. The idea of dynamic here is that they can be created at runtime, e.g. in an admin interface or elsewhere by code. The DynamicRouter loads routes from the database.
If you use PHPCR-ODM, the route name is the repository id, typically something like /cms/routes/my-route and you can generate it with that name. If you have access to the route object loaded from the database, you can also generate from that, rather than the path. If you have to hardcode a path in your application, its an indication that probably a normally configured route would be better.
If you just add a route to the route collection on the fly, you would have to make sure that happens in each request, its only available when you add it. With the CMF ChainRouter you could register your own router that does that, but i would not know of a good use case for that. Either you know the route, then you can configure it in the routing.xml|yml|php config file. Or routes are loaded dynamically, in which point you should use DynamicRouter, potentially with a custom route loader.
So I use Pubnub for WebRTC in my Symfony 2 application, and all works well, apart from the showing of videos of other users. What happens is that when a user connects, an url gets generated like this one:
mediastream:http://www.domain.com/cd024a62-02fa-42eb-8f52-621074ea887e
These url's are temporary, and the only purpose is to serve as a way to connect video streams. After the WebRTC session the do not exist anymore and they are impossible to predict.
Since the Symfony router cannot find a route to 'http://www.domain.com/cd024a62-02fa-42eb-8f52-621074ea887e', the stream is never showed (www.domain.com is the url to the symfony application in this example).
What I could do is adapt the exisiting scripts so that all video streams look like 'http://www.domain.com/video/cd024a62-02fa-42eb-8f52-621074ea887e', but in that case any route with prefix /video/ should be left alone by Symfony.
Any ideas?
In the end I found a solution. As a last routing rule I added:
display_blob:
defaults: { _controller: Bundlename:Main:blob }
path: /{blob}
Then I created a function in the Main controller:
public function blobAction(Request $request)
{
$path = $request->getUri();
return $this->render($path);
}
Of course I need to do some filtering of the URL itself and check if it really is a stream, but for now I am happy it works.
I'm building a CMS style application with dynamic routing. So far it seems to work fine but the output doesn't honor the environment for WDT, assets and links... it always links to /whatever instead of /app_dev.php/whatever.
Dynamic routing is implemented via kernel.request listener. The relevant code is on gist. Do I need to pass the current environment to Twig at some moment?
Edit:
The problem appears when in DEV mode... no problem when in production mode.
Thanks to #AdrienBrault I finally solved the issue by using a Controller to do the rendering.
In the RequestListener I added a new route to the RouteCollection of the router indicating the controller which will handle the request.
$route = new Route($path, array(
'_controller' => 'CmsBundle:Routing:routing',
));
$this->router->getRouteCollection()->add('cms', $route);
In the controller it was a bit harder to get the original URL, but finally I solved it by querying the routers RouteCollection with the name assigned in the previous add() method.
I am new to symfony2. I started it with some tutorials and then started building SYMBLOG. I have understood it and i am able to add or change the functionality. I have a bit confusion in the workflow, I mean How the files work together to render a page or to produce an output. Can anyone explain me in detail from the beginning how this flow goes on in symfony2. starting from the user request say user enters a url till the symfony2 displays results. please include the routing.yml in the flow. ?
You should check out this link. Symfony - the big picture
It explains in detail all the steps involved from the time you enter the URL in the browser to the page getting rendered.
Basically all requests go to a Front Controller. Its job is to route the requests to the appropriate controller code. It does this with the help of the routes defined in the app/config/routing.yml file. The controllers which are defined in src/<BundleName>/Controller/<name> perform some business logic, like getting data from the Model (Repository) and send that information to the View (Templates). The views are simply HTML code. Symfony uses a templating engine called Twig. Instead of including <?php ... ?> blocks in the HTML code, Symfony passes the data from the controller and it can be easily used inside the view within Twig {% %} or {{ }} blocks.
Simply put, here is the workflow:
Browser sends Request
Request received in front controller web/app_dev.php or web/app.php
Front controller checks the routes defined in app/config/routing.yml and sends the request to the appropriate
controller defined in src/<BundleName>/Controller/<controller_name>
Controller prepares the content that is needed in the HTML (Example - query the database from src/<BundleName>/Repository) and sends the information to the View - src/Resources/views/<twig file name>
The view creates the HTML and sends it back to the controller
The controller creates an HTTP response and sends it back to the browser
There are things like the app/AppKernel that come in between but I have skipped it.
Here are the useful excerpts from the link provided above:
URL:
http://localhost/Symfony/web/app_dev.php/demo/hello/Fabien
What's going on here? Let's dissect the URL:
app_dev.php: This is a front controller. It is the unique entry point of the application and it responds to all user requests;
/demo/hello/Fabien: This is the virtual path to the resource the user wants to access.
Your responsibility as a developer is to write the code that maps the user's request (/demo/hello/Fabien) to the resource associated with it (the Hello Fabien! HTML page).
Routing:
Symfony2 routes the request to the code that handles it by trying to match the requested URL against some configured patterns. By default, these patterns (called routes) are defined in the app/config/routing.yml configuration file. When you're in the dev environment - indicated by the app_dev.php front controller - the app/config/routing_dev.yml configuration file is also loaded. In the Standard Edition, the routes to these "demo" pages are placed in that file:
_welcome:
pattern: /
defaults: { _controller: AcmeDemoBundle:Welcome:index }
Controller:
Symfony2 chooses the controller based on the _controller value from the routing configuration: AcmeDemoBundle:Welcome:index. This string is the controller logical name, and it references the indexAction method from the Acme\DemoBundle\Controller\WelcomeController class:
class WelcomeController extends Controller
{
public function indexAction()
{
return $this->render('AcmeDemoBundle:Welcome:index.html.twig');
}
}
View:
The controller renders the src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig template
{% extends "AcmeDemoBundle::layout.html.twig" %}
{% block title "Hello " ~ name %}
{% block content %}
<h1>Hello {{ name }}!</h1>
{% endblock %}
You may also want to check out the Symfony2 architecture