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.
Related
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 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.
I am totally new to angularjs and i am practicing.
I am a bit stuck with the following, i have a profile page what loads the users details, and i do not really know how to show it, problem is im stuck with the logic.
I created 2 routes for it
Route::get('/(:any)', array('as' => 'profile', 'uses' => 'user#profile'));
Route::get('/details/(:any)', array('as' => 'profile', 'uses' => 'user#details'));
So the url actually looks like this: http://mysite.com/username
So my logic works like this, this route
Route::get('/(:any)', array('as' => 'profile', 'uses' => 'user#profile'));
Returns the profile view
this route would fetch the users data in json
Route::get('/details/(:any)', array('as' => 'profile', 'uses' => 'user#details'));
and what i am stuck with is this
I load the view, http://mysite.com/username i get the profile page,
Laravel view load
public function get_profile($username = '')
{
return View::make('user.profile');
}
Loading the json
public function get_details($username = '')
{
$users = User::where_username($username)->get();
return Response::eloquent($users);
}
angularjs controller
function profileCtrl($scope, $http) {
//here get the url first segment somehow
// and pass it to the get
// example
// urlSegment = username
$http('details/' + username ).success(function(data){
$scope.users = data;
console.debug(data);
});
}
So my question is, am i doing this okay, or im completly not on the right track.
Could someone show me an exampe for this?
Thank you
EDIT
To be more specific, i am trying to create a restful api with angularjs and laravel but im a bit stuck with it. What i do not understand is the routing logic.
example.
mysite.com/username, What type of route logic i need to build up to fetch the data?
Because i explained above, i created 2 routes for it, and i think thats not good.
i am trying to create a restful api with angularjs and laravel but im a bit stuck with it. What i do not understand is the routing logic.
Laravel provides a number of convient ways to create a restful API. It should be noted Laravel is "the restful api" and AngularJS is the client that will use the API to show the results (i.e. be the user front end).
Laravel 4 refers to 'Resource Controllers' to help you build a restful API. Using this picture, you can see how the controller should be laid out, and what each command is specifically required to do:
Just replace "photos" with "user" and that is how the controller will be laid out. If you are using Laravel 4 you can generate a resourceful controller using Artisan:
php artisan controller:make UserController
and it will add each of the functions above ready to go.
Laravel 3 refers to 'Restful Controllers' - but the principle is the same.
If you are interested - Nettuts has a great free tutorial on creating a Restful API with Laravel 4 from scratch. If you follow this tutorial - you will have a full restful API for your user class. It goes into much more detail than is possible in this answer.
For Laravel 4 your routes will be just one line of code:
Route::resource('user', UserController);
Then you will run the follow artisan commands
php artisan controller:make UserController
php composer.phar dump-autoload
Then your User Controller will be ready to go, with all the functions scaffold, and all you need to do is put some base logic in.
edit: I just found another tutorial that explains Laravel 4 resource controllers a bit further.
Angular is a client-side framework running only in the browser. So you simply cannot create a restful API with it. A restful API always runs on the server only, so Laravel should work for that.
The way Angular is meant to be used is that the client requests the content as JSON from a restful API running on the server (with the $http module) and then the HTML is built on the client-side. See what-is-the-point-of-angularjs-routes? I also highly recommend the official tutorial.
I have found that the functional tests in Symfony2 always try to request pages as "http://localhost"
My environment is setup with virtual hosts so I have my application at "http://symfony.dev"
After some testing I have found that if I run:
var_dump($client->getResponse()->getContent());
I will get the page I want, but if I var_dump the $crawler I can see that rather than requesting a page like "http://symfony.dev/page" it requested "http://localhost/page"
That gives a 404 so I am unable to test forms and so on.
Is there anyway to set the base URL to get this to work? Should I instead use something different like Selenium?
I found that I can pass the domain in to the Client. I will just make a base WebTestCase with this functionality so my tests work.
$client = static::createClient(array(), array('HTTP_HOST' => 'symfony.dev'));
$client->followRedirects(true);