Symfony2 Routing annotation gets url encoded - php

I've playing around with annotations in Symfony2.5 and am struggling to output a nice clean url like this:
.../display&type=foo&id=1
What I always get is:
.../display%26type=foo%26id=1
Why is Symfony2 url encoding this?
My controller looks like this:
/**
* Displays content
*
* #Route("/display/type={type}&id={id}", name="content_display")
* #Template(...)
*/
public function displayAction($type, $id = null) {
...
}
my twig template has:
{{ entity.id }}. {{ entity.name }}<br />
So I've tried to add |raw and autoescape off tags described here. But no luck so far, any ideas?
Thanks!

/display/type={type}&id={id}
...is not a valid URL... you'd have to replace that second slash with a ?:
/display?type={type}&id={id}
That said, the route is meant for path replacement -- not parameter replacement.
I'm pretty certain that if you change that to simply /display, when you try to render the URL with your key-value map, then Symfony will add those as parameters, since it can't find those keys in the path itself.
Edit:
Confirmed via the documentation:
The generate method takes an array of wildcard values to generate the
URI. But if you pass extra ones, they will be added to the URI as a
query string.

Related

PHP How to create urls properly?

I have never understood how to create proper URLs. Every time I end up with trying to figure out if I should do ?var=value or &var=value and then if ?var=value already exists then I end up with ?var=value&var=value.
P.S. I am working with Laravel. (So maybe there is a built-in function?)
For example:
I have pagination and my URL could look like this
www.example.com OR
www.example.com?name=John
Then my pagination link is href="?page=2" and I end up with
www.example.com?name=John?page=2
Then I want to navigate to the next page with href="?page=3" and I end up with this. Because it keeps on adding.
www.example.com?name=John?page=2?page=3
What a mess.... is there a function for PHP or Laravel that would create proper URLS? (knowing when to use ? or & and not add existing values all the time but replace them if they exist already.
If you're using Laravel I think you should use some helper functions:
route('user.profile', ['id' => 1]);
It will create url by route name and parameters, It will look like:
http://sitename/user/profile?id=1
And you can find some useful helper functions here
There should be one and only ? in URL's which separates URI and parameters, rest of the key-value pairs are separated by &, and if you need to pass & or ? as a parameter, then you need to encode them.
you could pass an array to http_build_query and it will build the url for you
and in laravel there are url helper functions you can use them with ease.
Laravel come with a route helper which allow you to generage url quickly by passing the name with which you register your route.
Route::get('/', 'HomeController#index')->name('home.route')
Here you can see I pass home.route to the name method which is the name which I use for this route. And when I want to generate the URL for that route in my view I will juste do
{{ route('home.route') }}
If ny route take some parameters like this
Route::get('/person/{id}', 'HomeController#index')->name('home.route')
In view I will generate the url like this
{{ route('home.route', ['id' =>$id]) }}
Because you want juste to make pagination, Laravel comme with a buil in pagination. When you want to paginate something in your views, you must just call the paginate function on your model and laravel will handle all the route for that. For example I you have a Person Model you can do that like this in your controller
$persons = Person::paginate(25)
And in your views to generate pagination for that you will have to do
{{ $persons->links() }}
And that's all

symfony 3 url issue

Hi I'm coming for a very simple question (I think) but i didn't found the answer or a similar case.
I'm using symfony 3 and trying to build a second menu for my administration pannel.
However, I have a problem about how I have to declare the relative url in my "href", For my main menu i used to do like this
{{ url ( 'admin' ) }}
and it worked. The fact is that now I have subfolders and many levels in my url.
The url i try to reach is myapp/admin/gameadmin, this url work when I'm going on it but when i try to put it in 'href' I have an error message which says that the route is not working.
i declared it like that ->
{{ url(admin/gameadmin) }}
I tried with different character -> admin:gameadmin, admin\gameadmin ... etc and with path instead of url i don't know if it's not the good way to declare it or if I have a problem with my controllers.
In my bundle it's organised like that :
->Controllers(folder)
->admin(folder) (You can also find my main controllers on this level)
->admingamecontroller (Where the page I try to reach is routed)
I hope i gave you all the informations, thank you for your help and sorry for my english !
The url parameter is not the the url per se (ie: admin/gameadmin), this is the route name, defined in your routing.yaml file, or in your controller annotation.
If your action is something like this:
/**
* #Route("/admin/gameadmin", name="gameadmin")
*/
public function gameAdminAction()
{
...
}
Then, to generate the route, you have to do this:
{{ url('gameadmin') }}
By doing this, all the links on your website will be up to date if you change the gameadmin url, as long as you don't change the route name.
I suggest you to read this documentation on the Symfony website: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/routing.html
Edit: As pointed by user254319, if you're not using annotations, you'll have to edit your routing.yaml config file.
gameadmin:
path: /admin/gameadmin
controller: App\Controller\Admin\AdminGameController::gameadminAction
The route name is the yaml key: gameadmin.
Related Symfony documentation: https://symfony.com/doc/current/routing.html

Pass two parameters as one to TWIG url

I'm using a framework (specifically EC-Cube3, if interested) that uses a Silex application with TWIG templates.
It has a navigation sidebar that is configured with PHP object arrays. I can inject an item array that looks something like this:
$item = array(
"id" => "item_id"
"url" => "named_url"
);
The url is created in typical Silex fashion:
$app->match('/item', 'Controller::method')->bind('named_url');
The framework eventually uses the url field and evaluates it in TWIG like so:
{{ url(item.url) }}
And this is usually fine! But the problem comes when I have a URL that includes a parameter, like this:
$app->match('/item/{id}', 'Controller::method')->bind('named_url'); // Needs 'id' to be evaluated.
In this scenario, setting the URL by the same array won't work because TWIG's url function needs the id for the second argument.
Since I can't change the application's TWIG files (because then I can't safely update the application), I need to be able to set the item's url to include the id as well.
After investigating, I don't think this is possible. Is it true that this is impossible? Or is there some method that I'm unaware of?
You can use mutiple vars like this
{{ path('path_in_route', {'id': article.id,'slug': article.slug}) }}
And
path_in_route
must be in your router file.
Hope that helps you.
Can you try the following in your Twig file:
{{ url(item.url,{'id': id}) }}
I believe that should work, but not certain.
EDIT #2
What if you use something like this:
$app->match('/item', 'Controller::method($id)')->bind('named_url');
Where $id is the id you need to pass in. I'm not really familiar with Silex, but maybe it's something like that?

How to use multiple routes to one controllerAction with Symfony3

I would like to configure multiple URLs to one Action in Controller (internationalization purposes).
According to this answer it was surely possible in symfony2 to:
Make double annotation route.
Use 3rd party Bundle (for example "BeSimple's").
But I'm using Symfony 3.0.3 which prohibits me from doing so until I change the route's name (example):
/**
* #Route("/welcome", name="welcome", defaults={"_locale" = "en"})
* #Route("/bienvenue", name="welcomeFR", defaults={"_locale" = "fr"})
* #Route("/willkommen", name="welcomeDE", defaults={"_locale" = "de"})
*/
But adding additional "FR/DE" chars to routes change their presence and ruins my URL generating logic in template, I'm forced to make on all links:
{# homepage example #}
{% if _locale = 'en' %}
{{ path('welcome') }} {# Routes from set only for "en" #}
{% elseif _locale = 'fr' %}
{{ path('welcomeFR') }} {# "fr" only links #}
{% endif %} {# and so on #}
Anyone found the proper solution for this problem?
AFAIK, this is the preferred way to point multiple routes to an unique controller action. So, your current problem is to regenerate the current path, depending on which route is being used
Maybe you don't have to modify your logic if you use {{ app.request.get('_route') }} to get the name of your current routing. This way, you could use:
{{ path(app.request.get('_route')) }}
UPDATE:
What about create an action per route and forwarding them to the main language action? Maybe it is not the best practice, but could work fine
/**
* #Route("/welcome", name="welcome", defaults={"_locale" = "en"})
*/
public function welcomeAction()
{
/* code here */
}
/**
* #Route("/bienvenue", name="welcomeFR", defaults={"_locale" = "fr"})
*/
public function welcomeFrAction()
{
$response = $this->forward('AppBundle:ControllerName:welcome');
}
/*
* #Route("/willkommen", name="welcomeDE", defaults={"_locale" = "de"})
*/
public function welcomeDeAction()
{
$response = $this->forward('AppBundle:ControllerName:welcome');
}
After wasting 10 hours on finding solution on Symfony3 I've made those assumptions:
None of the route trick with exactly same "name" wouldn't work,
Any kind like double annotation, double "routing.yml" importing, host based matching gives the same effect - only one route is matched, usually the last one. Would be ("/willkommen", name="welcomeDE") in my example.
Both of the i18n bundles does not work on Symfony3 through the versioning constraints,
Composer wouldn't even let us install the bundle.
Locale Listener and Loader (Routing Component) is dying on caching.
My solution to match the "_locale" and pass it to the LocaleLoader in order to load "routing_en.yml/routing_fr.yml" etc. files respectively is cached on the first match by the Symfony and after that, changing the "_locale" does not affect route's mapping.
In conclusion
Symfony3 seems not supporting route "example" with more than one "url" at all. Through the constraints and caching.
After the disappointment I'm considering going back to Symfony 2.8, have no idea what was pointing Symony's masters to block "double annotation" solution and what is their current idea on links internationalization.
Hope someday it will be possible to achieve with S3, as link i18n is quite common SEO practice.
EDIT: Confirmed, working like a charm on 2.8.5 with BeSimple's i18n.

twig path() function generating different outcome

I am trying to add dynamic links to my twig template by calling path() with a parameter.
{{ path('single_sale_submit_page', {'id': book['id']}) }}
I use annotation in my controller:
#Route("/book/{id}", name="single_sale_submit_page")
This results in the following url: ../book/?id=123456789. I keep getting the error that my controller needs a mandatory parameter, which is of course true cause the generated url has a different syntax(?).
How can I set up twig in a way that the generated url from path() corresponds to
../book/123456789
and not
../book/?id=123456789
EDIT:
This question has somewhat the same question as I have.
Add a default value in the annotation to the controller:
#Route("/boek/{id}", defaults={"id" = 1}, name="single_sale_submit_page")
Clear the cache with:
app/console cache:clear
After reloading the paths generated by path() will correspond to:
../book/123456789
and not:
../book/?id=123456789
I was having the same problem and my mistake was in param name, it was "struct-id", and I needed to remove "-" or change it to "struct_id".

Categories