How to use anchors in Symfony routing? - symfony

I have defined a route as followed in my routing.yml file :
route_name:
path: "/dashboard#messages/{id}"
However when I ask Symfony to generate that route, I get :
/dashboard%23messages/12345
How can I skip the encoding part of the route generation? Or how can I escape the # char in the path definition?
PS : Working with a (big) legacy system, I cannot change the urls.

Available from Symfony 3.2.
Support for anchors has been announced for the routing component using the fragment variable :
$this->get('router')->generate('user_settings', ['_fragment' => 'password']);
Will generate an url : /user/settings#password
For more information view the announcement.

You cannot easily - route parts are encoded unconditionally:
$url = strtr(rawurlencode($url), $this->decodedChars);
see at https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Routing/Generator/UrlGenerator.php#L192
Technically you might have extended the class UrlGenerator class and swap them using router.options.generator_class parameter. Then you could override the doGenerate method and replace %23 -> #.

In twig
<a href="{{ path('user_settings', { '_fragment': 'password' }) }}">

Related

Symfony 3 Translations Custom Domain

I'm trying to add custom domain into the project.
I have regions.locale.yaml file.
I'm trying load it in twig:
{{'united.kingdom'|trans|raw}}
But this doesn't work.
I think it has to be somehow declared that this file exists.
I found this in documentation:
// ...
$translator->addLoader('xlf', new XliffFileLoader());
$translator->addResource('xlf', 'messages.fr.xlf', 'fr_FR');
$translator->addResource('xlf', 'admin.fr.xlf', 'fr_FR', 'admin');
$translator->addResource(
'xlf',
'navigation.fr.xlf',
'fr_FR',
'navigation'
);
But where should I put this to declare my regions.locale.yaml files globally?
Thanks
If you are using Symfony Standard, you don't have to declare your translation files, you just put them in app/Resources/translations.
The key is that when you want to translate using your custom domain, you just specify your domain, like this :
{{'united.kingdom'|trans({}, 'regions')|raw }}
or somewhere else in your code :
$translator->trans('united.kingdom', [], 'regions');

Error parameters Twig with Path() Symfony 2

I got error
No route found for "POST
/module/getinfo/0/0/1454306400000/1455256800000"
The code on index.html.twig:
var desde_=1454306400000;
var hasta_=1455256800000;
var url = "{{ path('module_getinfo') }}"+desde_+"/"+hasta_
to get something like this:
url = /module/getinfo/1454306400000/1455256800000
the routing.yml is:
module_getinfo:
pattern: /getinfo/{desde}/{hasta}/
defaults: { _controller: AcmeDemoBundle:Module/Module:getInfo,desde:0,hasta:0}
I want to create a custom variable on javascript, what can I do ?
Thank you !
PD. Sorry for my english, I'm still learning jejeje
If you don't pass the values of the route placeholders to the path() function, it'll use the default values (both set to 0).
If you can't pass the values, because they are only available in JavaScript, consider using string replacing techniques:
var url = "{{ path('module_getinfo', { desde: '%desde%', hasta: '%hasta%' }) }}"
.replace('%desde%', desde_)
.replace('%hasta%', hasta_)
;
A simple solution is to use what #wouter J said
But a cleaner solution is to use something like fos js routing which allows you to generate the routes from java script

Limit languages in cms

I use silverstripe 3.1
I would like to limit the languages (To only German and English) which are available in the drop down in the CMS. Therefore I put
the following code in my mysite/_config.php
i18n::set_locale('de_DE');
$allowed_locales = array(
'de_DE' => array('Deutsch', 'Deutsch'),
'en_EN' => array('English', 'English')
);
i18n::$common_locales = $allowed_locales;
Afer a flush=1 i get the following error:
Fatal error: Cannot access private property i18n::$common_locales in ... _config.php
Any ideas what goes wrong?
Thank you
as of 3.1 most of the static php variables are private. this means you can no longer access those.
the reason for this api change is that they are now cached by the config layer (this is also why you have to ?flush=1 now after changing private statics in classes like for example with private static $db)
if you want to update something in the config layer, you can do this with:
Config::inst()->update('CLASS', 'FIELD', $value);
you could use use the config update to overwrite the common locales (class would be 'i18n', and field would be 'common_locales'):
Config::inst()->update('i18n', 'common_locales', $array);
Note: if you want to completely overwrite an existing configuration, you have to do a remove() first.
Config::inst()->remove('i18n', 'common_locales');
Config::inst()->update('i18n', 'common_locales', $array);
however, if you are using the translatable module and you want to limit the number of translatable languages, there is a much better way already built in:
// in your _config.php
i18n::set_locale('en_US');
Translatable::set_allowed_locales(array(
'de_DE',
'en_US',
));
Config it through YAML:
i18n:
common_locales:
nl_BE:
name: Dutch (Belgium)
native: Nederlands
fr_BE:
name: French (Belgium)
native: Francais

Symfony2.2 : default_locale always applying in twig translations

I'm having a strange issue with Symfony2.2. I have a project using two languages : en/fr. So I create as usual (like Symfony2.0) two translation files "messages.en.yml" and "messages.fr.yml" in Ressources/Views/translations/. But Translations in twig could not change even if we set the request object and the locale session. Translation is always set by the default_locale (config.php).
Example : if default_locale = en, all my website (in twig) is translated in en, even if i set the _locale object in fr (request and session). Of course if I manually change the default_locale to fr the website is naturally in fr...
However, _locale session works but I don't know if locale request works, and of course translation works in controllers too...
There is my files :
config.yml:
framework:
#esi: ~
translator: { fallback: %locale% } # = en
# ...
default_locale: %locale% # = en
Controller :
public function indexAction()
{
$this->get('session')->set('_locale', 'fr');
$this->getRequest()->setLocale($lang);
exit($this->getRequest()->getLocale()); // = fr
exit($this->get('translator')->trans('Symfony2 is great')); // = Symfony2 est génial
return $this->render('TestBundle:Controller:test.html.twig');
View :
{% block content %}
<p>lang : {{ app.request.locale }}</p> {#} = "fr", OK{#}
<p>{{ 'Symfony2 is great'|trans }}</p> {#} = "Symfony2 is great", WAIT WHAT?{#}
I must resign myself to force the locale at the beginning of the method controller to have the requested locale (stored in session) like that :
Controller:
if($this->get('session')->get('_locale')){
$lang = $this->get('session')->get('_locale');
$this->getRequest()->setLocale($lang);
}
In other words, I do have a problem with the registration of the request object... Because the last code works well in the controller, and shows well the locale in twig page with app.request.locale, but not the translations... (sorry for my bad english and thanks for helping)
I had the same issue due to the low priority of my event listener. The locale would be overridden by the Translator's TranslatorListener. Increasing the priority of my event listener did the trick for me:
services:
app.locale_listener:
class: AppBundle\EventListener\LocaleListener
tags:
- { name: kernel.event_listener, priority: 11, ... }
Source: https://github.com/symfony/symfony/issues/12878#issuecomment-68628808
Parameter _locale in routing holds your locale value.
Look here on this page
Symfony - Book - Translation - Local and the URL
From Symfony 2.1 they have this kind of logic:
Since you can store the locale of the user in the session, it may be tempting to use the same URL to display a resource in many different languages based on the user's locale. For example, http://www.example.com/contact could show content in English for one user and French for another user. Unfortunately, this violates a fundamental rule of the Web: that a particular URL returns the same resource regardless of the user. To further muddy the problem, which version of the content would be indexed by search engines?
A better policy is to include the locale in the URL. This is fully-supported by the routing system using the special _locale parameter:
Now when you want to sel local, this doesn't work any more
$this->get('session')->set('_locale', 'fr');
You can use request insted of session now but you can not have session-logic with _local from Symfony 2.0 unless you simulate it with event listener on kernel request.

Custom route configuration with Silex

I know that the basis of Silex approach in which all the application logic in a single file. But my application will be possible to have more than twenty controllers. So I want to have a handy map to manage the router.
My question is to search for solutions in which I would be able to make a router to a separate file. In the best case, the file must be of YAML type:
# config/routing.yml
_home:
pattern: /
defaults: { _controller: MyProject\Controller\MyController::index }
But the native is also a good case (for me):
$routes = new RouteCollection();
$routes->add(
'home',
new Route('/', array('controller' => 'MyProject\Controller\MyController::index')
));
return $routes;
Problem of the second case is that I have to use the match() function for each rule of routing. It is not at all clear.
What are the ways to solve this issue? The condition is that I want to use the existing API Silex or components of Symfony2.
Small note:
I don't use a ControllerProviderInterface for my Controller classes. This is an independent classes.
First of all, the basis of Silex is not that you put everything in one file. The basis of Silex is that you create your own 'framework', your own way of organizing applications.
"Use silex if you are comfortable with making all of your own architecture decisions and full stack Symfony2 if not."
-- Dustin Whittle
Read more about this in this blogpost, created by the creator of Silex.
How to solve your problem
What you basically want is to parse a Yaml file and get the pattern and defaults._controller settings from each route that is parsed.
To parse a Yaml file, you can use the Yaml Component of Symfony2. You get an array back which you can use to add the route to Silex:
// parse the yaml file
$routes = ...;
$app = new Silex\Application();
foreach ($routes as $route) {
$app->match($route['pattern'], $route['defaults']['_controller']);
}
// ...
$app->run();
I thought I'd add my method here as, although others may work, there isn't really a simple solution. Adding FileLocator / YamlFileLoader adds a load of bulk that I don't want in my application just to read / parse a yaml file.
Composer
First, you're going to need to include the relevant files. The symfony YAML component, and a really simple and useful config service provider by someone who actively works on Silex.
"require": {
"symfony/yaml": "~2.3",
"igorw/config-service-provider": "1.2.*"
}
File
Let's say that your routes file looks like this (routes.yml):
config.routes:
dashboard:
pattern: /
defaults: { _controller: 'IndexController::indexAction' }
method: GET
Registration
Individually register each yaml file. The first key in the file is the name it will be available under your $app variable (handled by the pimple service locator).
$this->register(new ConfigServiceProvider(__DIR__."/../config/services.yml"));
$this->register(new ConfigServiceProvider(__DIR__."/../config/routes.yml"));
// any more yaml files you like
Routes
You can get these routes using the following:
$routes = $app['config.routes']; // See the first key in the yaml file for this name
foreach ($routes as $name => $route)
{
$app->match($route['pattern'], $route['defaults']['_controller'])->bind($name)->method(isset($route['method'])?$route['method']:'GET');
}
->bind() allows you to 'name' your urls to be used within twig, for example.
->method() allows you to specify POST | GET. You'll note that I defaulted it to 'GET' with a ternary there if the route doesn't specify a method.
Ok, that's how I solved it.
This method is part of my application and called before run():
# /src/Application.php
...
protected function _initRoutes()
{
$locator = new FileLocator(__DIR__.'/config');
$loader = new YamlFileLoader($locator);
$this['routes'] = $loader->load('routes.yml');
}
Application class is my own and it extends Silex\Application.
Configuration file:
# /src/config/routes.yml
home:
pattern: /
defaults: { _controller: '\MyDemoSite\Controllers\DefaultController::indexAction' }
It works fine for me!
UPD:
I think this is the right option to add collections:
$this['routes']->addCollection($loader->load('routes.yml'));
More flexible.
You could extend the routes service (which is a RouteCollection), and load a YAML file with FileLocator and YamlFileLoader:
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\Loader\YamlFileLoader;
$app->extend('routes', function($routeCollection) {
$locator = new FileLocator([__DIR__ . '/../config']);
$loader = new YamlFileLoader($locator);
$collection = $loader->load('routes.yml');
$routeCollection->addCollection($collection);
return $routeCollection;
});
You will need symfony/config and symfony/yaml dependencies though.

Resources