How to pass the Translator to Twig Date Extension - symfony

I am using Symfony5 and Twig 1.5 and want to translate the time_diff filter. My service configuration looks like this:
twig.extension:
class: Twig_Extensions_Extension_Date
arguments: ['#translator']
tags:
- { name: twig.extension }
Unfortunately I get the following error message:
Argument 1 passed to Twig_Extensions_Extension_Date::__construct() must be an instance of Symfony\Component\Translation\TranslatorInterface or null, instance of Symfony\Component\Translation\DataCollectorTranslator
The reason for this is that Twig_Extensions_Extension_Date expects Symfony\Component\Translation\TranslatorInterface but DataCollectorTranslator implements Symfony\Contracts\Translation\TranslatorInterface.
How can I pass the correct translator to Twig_Extensions_Extension_Date?

It looks like Twig-extensions was abandoned and you have to write it yourself or use another bundle (https://github.com/twigphp/Twig-extensions/issues/264).

Related

How to use libphonenumber.phone_number_util in Symfony 4

To parse phone number I need to use libphonenumber.phone_number_util in my controller ( Symfony 4) as like as :
$parsed = $this->get('libphonenumber.phone_number_util')->parse($phoneNo);
as we have libphonenumber.phone_number_util in private I wanted to make it public by adding this helper in service as below:
services:
libphonenumber\PhoneNumberUtil:
alias: libphonenumber.phone_number_util
public: true
But this returns Exception and message:
"message": "The \"libphonenumber.phone_number_util\" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.",
"class": "Symfony\\Component\\DependencyInjection\\Exception\\ServiceNotFoundException",
If you are using this in a controller method (which I presume you do based on $this->get(...)), you need to
1) Declare your controller as a service and tag it with controller.service_arguments tag
2) Make sure your util service id matches the class name (I suppose it does already). You don't need it to be public - that's and ancient approach
3) Require the util as a parameter to your controller's action method.
E.g.
services:
libphonenumber\PhoneNumberUtil:
alias: libphonenumber.phone_number_util
AppBundle\Controller\MyController:
tags: ['controller.service_arguments']
and
public function validatePhoneAction(Request $request, PhoneNumberUtil $phoneNumberUtil)
{
...
$phoneNumberUtil->parse($request->request->get('phone_number');
...
}
There is a nice Symfony blog post about these changes in dependency management: https://symfony.com/blog/new-in-symfony-3-4-services-are-private-by-default

Symfony 3 - How inject own variable from config to service right way?

I want on my web create cache config with different cache values. I have working example:
// config.yml
parameters:
myValue:
first: 1
second: 2
// services.yml
my_repo:
class: AppBundle\Repository\MyRepository
factory: ["#doctrine.orm.entity_manager", getRepository]
arguments:
- 'AppBundle\Entity\My'
calls:
- [setValue, ["%myValue%"]]
// MyRepository.php
public function setValue($val) {
$this->first = $val['first'];
}
// Inside controller method
$someVariable = $this->get('my_repo')
->someOtherFunction();
But is this way correct? What if another programmer will call repository 'standart' way $em->getRepository('MyRepository')? It will crash on udefined variable... Is there way to do this for example via constructor? Or constructor is bad idea?
I am interested in the yours practice - better solution etc.
Something like
[setValue, ["#=container.hasParameter('myValue') ? parameter('myValue') : array()"]]
Should do the trick. Then just check in your service if the variable injected is empty or not. See the doc for more on the Expression language

Injecting parameter based service into other service

I have a service which takes a driver to do the actual work. The driver itself is within the context of Symfony 2 is just another service.
To illustrate a simplified version:
services:
# The driver services.
my_scope.mailer_driver_smtp:
class: \My\Scope\Service\Driver\SmtpDriver
my_scope.mailer_driver_mock:
class: \My\Scope\Service\Driver\MockDriver
# The actual service.
my_scope.mailer:
class: \My\Scope\Service\Mailer
calls:
- [setDriver, [#my_scope.mailer_driver_smtp]]
As the above illustrates, I can inject any of the two driver services into the Mailer service. The problem is of course that the driver service being injected is hard coded. So, I want to parameterize the #my_scope.mailer_driver_smtp.
I do this by adding an entry to my parameters.yml
my_scope_mailer_driver: my_scope.mailer_driver_smtp
I can then use this in my config.yml and assign the parameter to the semantic exposed configuration [1]:
my_scope:
mailer:
driver: %my_scope_mailer_driver%
In the end, in the Configuration class of my bundle I set a parameter onto the container:
$container->setParameter('my_scope.mailer.driver', $config['mailer']['driver'] );
The value for the container parameter my_scope.mailer.driver now equals the my_scope.mailer_driver_smtp that I set in the parameters.yml, which is, as my understanding of it is correct, just a string.
If I now use the parameter name from the container I get an error complaining that there is no such service. E.g:
services:
my_scope.mailer:
class: \My\Scope\Service\Mailer
calls:
- [setDriver, [#my_scope.mailer.driver]]
The above will result in an error:
[Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException]
The service "my_scope.mailer" has a dependency on a non-existent service "my_scope.mailer.driver"
The question now is, what is the correct syntax to inject this container parameter based service?
[1] http://symfony.com/doc/current/cookbook/bundles/extension.html
This question has a similar answer here
I think the best way to use this kind of definition is to use service aliasing.
This may look like this
Acme\FooBundle\DependencyInjection\AcmeFooExtension
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration;
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader(
$container,
new FileLocator(__DIR__.'/../Resources/config')
);
$loader->load('services.yml');
$alias = $config['mailer']['driver'];
$container->setAlias('my_scope.mailer_driver', $alias);
}
This will alias the service you've defined in my_scope.mailer.driver with my_scope.mailer_driver, which you can use as any other service
services.yml
services:
my_scope.mailer_driver:
alias: my_scope.mailer_driver_smtp # Fallback
my_scope.mailer_driver_smtp:
class: My\Scope\Driver\Smtp
my_scope.mailer_driver_mock:
class: My\Scope\Driver\Mock
my_scope.mailer:
class: My\Scope\Mailer
arguments:
- #my_scope.mailer_driver
With such a design, the service will change whenever you change the my_scope.mailer_driver parameter in your config.yml.
Note that the extension will throw an exception if the service doesn't exist.
With service container expression language you have access to the following two functions in config files:
service - returns a given service (see the example below);
parameter - returns a specific parameter value (syntax is just like service)
So to convert parameter name into a service reference you need something like this:
parameters:
my_scope_mailer_driver: my_scope.mailer_driver_smtp
services:
my_scope.mailer:
class: \My\Scope\Service\Mailer
calls:
- [setDriver, [#=service(parameter('my_scope_mailer_driver'))]]
At first I thought this was just a question of getting the # symbol passed in properly. But I tried assorted combinations and came to the conclusion that you can't pass an actual service as a parameter. Maybe someone else will chime in and show how to do this.
So then I figured is was just a question of using the service definition and passing it a reference. At first I tried this in the usual extension but the container does not yet contain all the service definitions.
So I used a compiler pass: http://symfony.com/doc/current/cookbook/service_container/compiler_passes.html
The Pass class looks like:
namespace Cerad\Bundle\AppCeradBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class Pass1 implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
// Set in the Extension: my_scope.mailer_driver_smtp
$mailerDriverId = $container->getParameter('my_scope.mailer.driver');
$def = $container->getDefinition('my_scope.mailer');
$def->addMethodCall('setDriver', array(new Reference($mailerDriverId)));
}
}
Take the calls section out of the service file and it should work. I suspect there is an easier way but maybe not.
#my_scope.mailer.driver needs to be a service but not defined as service. To retrieve string parameter named as my_scope.mailer.driver you need to wrap it with %: %my_scope.mailer.driver%.
So you need to pass #%my_scope.mailer.driver% as parameter to a service. Yml parser will replace %my_scope.mailer.driver% with the appropriate value of the parameter and only then it will be called as a service.

How do I configure my Twig / Symfony2 services for this?

How do I configure my services for this?
https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Twig/Extension/RoutingExtension.php
I'm guessing it's something like this:
twig.extension.anyName:
class: Bundle\Twig\RoutingExtension
arguments:
- "twig.extension.routing"
tags:
- { name: twig.extension }
...but it errors with:
Catchable Fatal Error: Argument 1 passed to Bundle\Twig\RoutingExtension::__construct() must implement interface Symfony\Component\Routing\Generator\UrlGeneratorInterface, string given...
Valid syntax for referencing other services is # symbol followed by service name. Currently you are passing string "twig.extension.routing" to your service constructor.
If you want pass service instance to your service, it could look something like this
twig.extension.anyName:
class: Bundle\Twig\RoutingExtension
arguments:
- "#twig.extension.routing"
tags:
- { name: twig.extension }

Routing requirements 0

I have a problem with my Symfony2.2 beta routes. (symfony-2-2-0-beta-1)
I use annoations routes like this:
#Route("/form/{id}", defaults={"id"=0}, requirements={"id"="\d+"});
And the error is:
An exception has been thrown during the rendering of a template ("Parameter "id" for route "[...]_form" must match "\d+" ("" given).") in [...]:form.html.twig at line 1.
The line 1 is:
{{ path("[...]_form") }}
I think the route is correct, because I define "id=0" as default.
And in Symfony2.1 the same code works.
Have you tried setting the default in your action and taking it out of the annotation?
/**
* #Route("/form/{id}", name="my_form", requirements={"id"="\d+"});
*/
public function myFunction($id = 0){
...
I believe this is one of the changes in Symfony 2.2 although I haven't tried it yet. http://symfony.com/blog/new-in-symfony-2-2-small-things-matter#defining-default-values-when-using-the-route-annotation
You can try
requirements:
id: \S|\d+

Resources