Get config data in Yaml (bespoke variables) in any Symfony2 controller - symfony

I want to do this in the main app/config/config.yml file:
variables:
a: 1
email: jim#email.com
variable2: hello
And this in any controller:
$variables = **get Yaml config data**
echo $variables['email'];
Of course I can't, but is anything like this possible?
I've seen where you can set global variables for access by Twig, but not seen how a Symfony2 controller can get them.
Of course if there's a better method as well then please mention that as this to me seems a good way of doing it.

Use parameters in parameters.yml for that:
parameters:
email: boss#acme.com
This way you'll be able to get it in a controller this way:
$email = $this->container->getParameter('email');
You can also create a Twig global in config.yml to have access to it from Twig using the same parameter:
twig:
globals:
email: %email%
And in Twig:
{{ email }}

Related

Symfony services.yaml env custom param condition

I have a specific variable in my .env.dev.local
SRV_INST=s01
Is there a way to use custom env variables in services.yaml in a conditional way similar to when#dev ? I would like to define some services only when SRV_INST=s01 (something like when %env(SRV_INST)% === 's01').
I can use services.php, but I wanted to know if there's a way to do this in services.yaml
you found a solution - but for anyone else, there are multiple other solutions for this:
services:
App\Mailer:
# the '#=' prefix is required when using expressions for arguments in YAML files
arguments: ["#=container.hasParameter('some_param') ? parameter('some_param') : 'default_value'"]
or
services:
# ...
App\Mail\MailerConfiguration: ~
App\Mailer:
# the '#=' prefix is required when using expressions for arguments in YAML files
arguments: ['#=service("App\\Mail\\MailerConfiguration").getMailerMethod()']
you can find more information at https://symfony.com/doc/current/service_container/expression_language.html
Okay, I solved this by importing a .php additional configuration file.
// config/services.yaml
imports:
- { resource: 'services_conditional.php' }
And the services_conditional.php file:
// config/services_conditional.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use SomeCustom\Service\CustomDoubleBla;
return function (ContainerConfigurator $configurator) {
$services = $configurator->services();
if (!empty($_ENV['SRV_INST']) && $_ENV['SRV_INST'] === 's01') {
$services->set(CustomDoubleBla::class)
->decorate('custom_single_bla.service')
// pass the old service as an argument
->args([service('.inner')]);
}
};

Symfony : How to access configuration in controller

This may be a silly question, but i can't see how to access this data :
In the main app/config/config.yml, i have the general configuration data for my application.
parameters: #accessible by getParameter()
locale: fr
# ...
fos_user: #accessible by ???
#...
registration:
form:
from_email:
address: mymail#mydomain.fr
sender_name: TheSenderName
In my custom bundle i can access the parameters from that config.yml file with :
$this->container->getParameter('locale'); //gives me "fr" as expected
But how can i access the non parameters configuration values ?
i would like here to get the adress defined in te FOS User bundle configuration :
I can't do
$admin_adress = $this->container->getParameter('fos_user.registration.confirmation.from_email.address');
What is the right way to access thoses ?
Edit :
Yes i wanted to access this config data from FOS User Bundle (here in the example, but it could be any), inside a controller or whatever in my bundle.
I think this question nailed it
class MyProjectExtension extends Extension
{
public function load( array $configs, ContainerBuilder $container )
{
// The next 2 lines are pretty common to all Extension templates.
$configuration = new Configuration();
$processedConfig = $this->processConfiguration( $configuration, $configs );
// This is the KEY TO YOUR ANSWER
$container->setParameter( 'from_email.address', $processedConfig[ 'registration.confirmation.from_email.address' ];
// Other stuff like loading services.yml
}
You can act that way
parameters:
locale: fr
fos_user:
registration:
form:
from_email:
address: mymail#mydomain.fr
# ...
fos_user:
#...
registration:
form:
from_email:
address: %fos_user.registration.form.from_email.address%
sender_name: TheSenderName
Of course I've choose this name just to fit your controller request for parameter: you can (and maybe should) choose other keys.
However with container->getParameter you can access only parameters section of your configuration file (plus parameters exposed from vendors)
One of the solutions can be passing your controller as a service, then inject your parameters like that :
# services.yml
my.amazing.controller:
class: CompanyFirst\LabBundle\Controller\PloufController
arguments:
- '#filesystem'
- '%dump_file_convention%' // your config parameter

Multiple Twig_Extension in Symfony2

I want to register my custom Twig filters in separate bundle (to avoid having one huge file).
I have Yaml configurations in each bundle:
# services.yml
services:
twig.extension.[BundleName]:
class: Kuba\[BundleName]\Twig\AppExtension
public: false
tags:
- { name: twig.extension }
Yet, all the time the last (lexicographically) extension overrides previous one.
How can I register more than one extension and if it's not possible what would be de best practise to split the code?
Twig extensions are identified by the string returned by getName() method. Is there a reason you have to return same string in all your twig extension!

Symfony2 multi-level dynamic router

I have a current project that has to displays both defined pages with specific entities, what is very easy to manage with Symfony2, and content pages on different layouts, what is - I guess - a bit less common.
I get in trouble trying to build the routing system.
For instance, if I have to display a page with some news,
I would like to update the router of my bundle with a new route like :
my_bundle_news_page:
pattern: /news
defaults:
_controller: MyBundle:NewsController:indexAction
But how to manage a dynamic router that could have a totally custom URL on many levels ?
Let's imagine I've got a "Page" Entity, that is self-references for an optionnal "parent-child" relation.
I don't think I can just use any config YAML file for this specific routing ?!
my_bundle_custom_page:
pattern: /{slug}
defaults:
_controller: MyBundle:PageController:showAction
This would bind all the first-level pages:
/projects
/about
/contact
/our-project
What about a page that would be displayed with, for instance, a slug like:
/our-project/health
In fact any URL...
/{slug-level1}/{slug-level2}/{slug-level3} etc.
Cause the pages are supposed to change and be updated from webmastering.
I guess the best way would be to have a router that compare the {slug} with a database field (entity property)
I read in the Symfony-CMF doc that it is possible to write a service based a route provider:
namespace MyBundle\Routing;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route as SymfonyRoute;
use MyBundle\Entity\PageRepository;
class RouteProvider extends PageRepository {
public function findPageBySlug($slug)
{
// Find a page by slug property
$page = $this->findOneBySlug($slug);
if (!$page) {
// Maybe any custom Exception
throw $this->createNotFoundException('The page you are looking for does not exists.');
}
$pattern = $page->getUrl(); // e.g. "/first-level/second-level/third-level"
$collection = new RouteCollection();
// create a new Route and set our page as a default
// (so that we can retrieve it from the request)
$route = new SymfonyRoute($pattern, array(
'page' => $page,
));
// add the route to the RouteCollection using a unique ID as the key.
$collection->add('page_'.uniqid(), $route);
return $collection;
}
}
But how to set it up as a service ? Are there some requirements ?
How could this kind of thing work, does it add a route to the RouteCollection when request is called ?
And will I be able to bind any route in this way ?
EDIT : services.yml of my bundle
parameters:
cmf_routing.matcher.dummy_collection.class: Symfony\Component\Routing\RouteCollection
cmf_routing.matcher.dummy_context.class: Symfony\Component\Routing\RequestContext
cmf_routing.generator.class: Symfony\Cmf\Bundle\RoutingBundle\Routing\ContentAwareGenerator
cmf_routing.nested_matcher.class: Symfony\Cmf\Component\Routing\NestedMatcher\NestedMatcher
cmf_routing.url_matcher.class: Symfony\Cmf\Component\Routing\NestedMatcher\NestedMatcher
fsbcms.chain_router.class: Symfony\Cmf\Component\Routing\ChainRouter
fsbcms.route_provider.class: FSB\CMSBundle\Routing\RouteProvider
fsbcms.dynamic_router.class: Symfony\Cmf\Component\Routing\DynamicRouter
fsbcms.route_entity.class: null
services:
fsbcms.router:
class: %fsbcms.chain_router.class%
arguments:
- "#logger"
calls:
- [setContext, ["router.request_context"]]
fsbcms.route_provider:
class: "%fsbcms.route_provider.class%"
arguments:
- "#doctrine"
cmf_routing.matcher.dummy_collection:
class: "%cmf_routing.matcher.dummy_collection.class%"
public: "false"
cmf_routing.matcher.dummy_context:
class: "%cmf_routing.matcher.dummy_context.class%"
public: false
cmf_routing.generator:
class: "%cmf_routing.generator.class%"
arguments:
- "#fsbcms.route_provider"
- "#logger"
calls:
- [setContainer, ["service_container"]]
- [setContentRepository, ["cmf_routing.content_repository"]]
cmf_routing.url_matcher:
class: "%cmf_routing.url_matcher.class%"
arguments: ["#cmf_routing.matcher.dummy_collection", "#cmf_routing.matcher.dummy_context"]
cmf_routing.nested_matcher:
class: "%cmf_routing.nested_matcher.class%"
arguments: ["#fsbcms.route_provider"]
calls:
- [setFinalMatcher, ["cmf_routing.url_matcher"]]
fsbcms.dynamic_router:
class: "%fsbcms.dynamic_router.class%"
arguments:
- "#router.request_context"
- "#cmf_routing.nested_matcher"
- "#cmf_routing.generator"
tags:
- { name: router, priority: 300 }
I suggest taking a look at the Symfony CMF routing component and the CmfRoutingBundle (to implement the component in symfony).
The Routing component uses a chain router, which is irrelevant for this question but it's good to know. The chain router chains over a queue of routers. The component provides a DynamicRouter that uses a NestedMatcher. That's exactly what you want.
The NestedMatcher uses a Route provider to get the routes from a dynamic source (e.g. a database). You are showing an example of a Route provider in your question.
Furthermore, it uses a FinalMatcher to match the route. You can just pass an instance of Symfony\Cmf\Component\Routing\NestedMatcher\UrlMatcher, as you are doing not too difficult things.
Take a look at the docs of the RoutingBundle to learn how to activate the chain router and then create a route provider which loads the routes, make a service:
acme_routing.route_provider:
class: Acme\RoutingBundle\Provider\DoctrineOrmProvider
arguments: ["#doctrine"]
Now, you can create a NestedMatcher service:
acme_routing.url_matcher:
class: Symfony\Cmf\Component\Routing\NestedMatcher\UrlMatcher
arguments: ["#cmf_routing.matcher.dummy_collection", "#cmf_routing.matcher.dummy_context"]
acme_routing.nested_matcher:
class: Symfony\Cmf\Component\Routing\NestedMatcher
arguments: ["#acme_routing.route_provider"]
calls:
- [setFinalMatcher, ["acme_routing.url_matcher"]]
Now, register the DynamicRouter and put it in the chain:
acme_routing.dynamic_router:
class: Symfony\Cmf\Component\Routing\DynamicRouter
arguments:
- "#router.request_context"
- "#acme_routing.nested_matcher"
- "#cmf_routing.generator"
tags:
- { name: router, priority: 300 }
Now, it should work and should load the routes from the database and match them against the request.

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.

Resources