Does anyone know how you can extend the Mailer class in the FOSUserBundle?
I am implementing a very basic parental email check (all the validation is done on the form to force a parent's email to be entered), if the parent email field is populated on the user entity then it shoudl send the email to that address not the user's email.
I have tried the following so far:
namespace SSERugby\UserBundle\Mailer;
use FOS\UserBundle\Mailer\Mailer as BaseMailer;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\Routing\RouterInterface;
class Mailer extends BaseMailer
{
public function sendConfirmationEmailMessage(UserInterface $user)
{
$email = $user->getEmail();
$parentEmail = $user->getParentEmail();
if(isset($parentEmail)&&(trim($parentEmail)!='')){
$email = $parentEmail;
}
$template = $this->parameters['confirmation.template'];
$url = $this->router->generate('fos_user_registration_confirm', array('token' => $user->getConfirmationToken()), true);
$rendered = $this->templating->render($template, array(
'user' => $user,
'confirmationUrl' => $url
));
$this->sendEmailMessage($rendered, $this->parameters['from_email']['confirmation'], $email);
}
}
It seems to just ignore the overridden class though and use the default, i have cleared the cache before testing.
Thanks
You should create new service with extended mail class (in src\SSERugby\UserBundle\Resources\config\services.xml) like:
<service id="my_mailer" class="SSERugby\UserBundle\Mailer\Mailer" public="true">
<argument type="service" id="mailer" />
<argument type="service" id="router" />
<argument type="service" id="templating" />
<argument type="collection">
<argument key="confirmation.template">%fos_user.registration.confirmation.template%</argument>
<argument key="resetting.template">%fos_user.resetting.email.template%</argument>
<argument key="from_email" type="collection">
<argument key="confirmation">%fos_user.registration.confirmation.from_email%</argument>
<argument key="resetting">%fos_user.resetting.email.from_email%</argument>
</argument>
</argument>
</service>
and then in app/config/config.yml use this service as default:
fos_user:
# ...
service:
mailer: my_mailer
FYI: I copied all service's arguments from FOSUserBundle default mailer config. You can add your own params to it. Also you can read about custom mailers at https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/doc/emails.md
Related
I have a Symfony project where I want to inject an entity repository into a service. The service definition is in XML format.
<service id="vendorname_shop.checkout_data_manager" class="Vendorname\ShopBundle\Checkout\CheckoutDataManager">
<argument type="service" id="security.token_storage" />
<argument type="service" id="session" />
<argument type="service" id="vendorname_shop.repository.pickup_point" />
<argument type="service" id="vendorname_shop.repository.order_payment_method" />
<argument type="service" id="vendorname_shop.repository.billing_address" />
</service>
I'd like to make vendorname_shop.repository.billing_address service to be a simple entity repository (not a custom class that I wrote, but the result of
EntityManager->getRepository(Vendorname\ShopBundle\Entity\BillingAddress::class)
method call), so I used the factory syntax in the xml, but I keep recieving error messages when Symfony tries to evaluate the argument:
<service id="vendorname_shop.repository.billing_address" class="Doctrine\ORM\EntityRepository">
<factory service="doctrine.orm.entity_manager" method="getRepository" />
<argument type="expression">Vendorname\ShopBundle\Entity\BillingAddress::class</argument>
</service>
The code above gives me Unexpected character "\" around position 11.
You can try something like this:
services:
my_service_name:
class: AppBundle\Controller\MyServiceName
arguments: ["#=service('doctrine.orm.entity_manager').getRepository('AppBundle:MyEntity')"]
Then you have build a service for your repository.
public function __construct(MyEntityRepository $repository) {
$this->repository = $repository;
}
But i think there are a lot more possibilities.
http://www.zuellich.de/blog/2016/03/symfony-3-inject-entity-repository-into-service-controller.html
here is another solution. I've replaced my answer with some of that solution it is a bit better.
As Cerad said, if I use a fully qualified name, the ::class is totally useless!
In addition changing the argument type to string solved the problem!
<argument type="string">Vendorname\ShopBundle\Entity\BillingAddresss</argument>
I have an application that contains a lot of translation resources for a lot of different languages. The warmup process takes a long time because of this.
I only support the translation of my site in a few languages, so I'd like to avoid generating catalogues for all the languages that I don't support.
What I did:
I overrode the TranslationsCacheWarmer to use my own translator. This is a custom translator that decorates the default translator but overrides the warmup method to only warmup files that are part of the locales that I support.
The problem is that the default warmer still runs generating files for all the locales.
This is the code that contains the custom translator: https://gist.github.com/marcosdsanchez/e8e2cd19031a2fbcd894
and here's how I'm defining the services:
<service id="web.translation.public_languages_translator" class="X\Translation\PublicLanguagesTranslator" public="false">
<argument type="service" id="translator.default" />
<argument type="collection">%chess.translation.public_languages%</argument>
</service>
<service id="translation.warmer" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\TranslationsCacheWarmer" public="false">
<argument type="service" id="web.translation.public_languages_translator" />
<tag name="kernel.cache_warmer" />
</service>
I'm using symfony 2.7.3
I ended up doing something different to get the same result. Instead of trying to create a custom CacheWarmer, I created a compiler pass and modified the definition of the 'options' argument. In this compiler pass, I removed all the files that don't have the locale or language code.
Code:
<?php
namespace X\DependencyInjection\Compiler;
use X\Entity\I18nLanguage;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class TranslatorCompilerPass implements CompilerPassInterface
{
/**
* You can modify the container here before it is dumped to PHP code.
*
* #param ContainerBuilder $container
*
* #api
*/
public function process(ContainerBuilder $container)
{
$definition = $container->getDefinition('translator.default');
$options = $definition->getArgument(3);
$keys = array_keys($options['resource_files']);
$locales = I18nLanguage::PUBLIC_LOCALES;
$langCodes = array();
foreach (I18nLanguage::PUBLIC_LOCALES as $locale) {
$langCodes[] = substr($locale, 0, strpos($locale, '_'));
}
$localesAndLangCodes = array_merge($locales, $langCodes);
foreach ($keys as $key) {
if (!in_array($key, $localesAndLangCodes, true)) {
unset($options['resource_files'][$key]);
}
}
$arguments = $definition->getArguments();
$definition->setArguments(array($arguments[0], $arguments[1], $arguments[2], $options));
}
}
That did the trick for me and I can also apply other optimizations like the removal of loaders, etc.
In Terminal when I try to run my created command I get the following error:
[Symfony\Component\DependencyInjection\Exception\InvalidArgumentException]]
You cannot dump a container with parameters that contain references to other services (reference to service "old_sound_rabbit_mq.split_file_producer" found in "/rabbit").
This is what happens when I run my newly created console command:
$this->getContainer()->get('split_file')->process();
I don't know why it says that You cannot dump! I don't dump anything in the project.
Is there something I'm unaware of?
EDIT
A part of my services.yml:
<parameters>
<parameter key="file_path">/var/www/path/file.xml</parameter>
<parameter key="rabbit" type="service" id="old_sound_rabbit_mq.split_file_producer" />
</parameters>
<service id="split_file" class="Acme\DemoBundle\SplitFile">
<argument>%file_path%</argument>
<argument>%rabbit%</argument>
</service>
And this is my console command class:
namespace Acme\DemoBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class ReadFileCommand extends ContainerAwareCommand
{
protected function configure()
{
$this->setName('reader:read-file');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->getContainer()->get('split_file')->process();
}
}
Parameters only have a key value. You can't add service etc to a parameter.
<service id="split_file" class="Acme\DemoBundle\SplitFile">
<argument>%file_path%</argument>
<argument type="service" id="old_sound_rabbit_mq.split_file_producer"/>
</service>
http://symfony.com/doc/current/book/service_container.html
I'd suggest switching to yml as it's less verbose
You could create an alias for old rabbit if you wanted.
From monolog.xml:
<service id="monolog.logger" parent="monolog.logger_prototype" public="false">
<argument index="0">app</argument>
</service>
<service id="logger" alias="monolog.logger" />
<service id="monolog.logger_prototype" class="%monolog.logger.class%" abstract="true">
<argument /><!-- Channel -->
</service>
How do I accomplish the same overriding of the 0th argument in Yaml?
My colleague created a bundle that allows you to easily convert from XML to YML and it came up with:
services:
monolog.logger:
public: false
arguments: { index_0: app }
monolog.logger_prototype:
class: %monolog.logger.class%
arguments: ['']
logger: #monolog.logger
Never would have guessed that.
One of defining logger with custom channel as service way:
# app/config/config.yml
monolog:
channels: [custom_channel]
When in a controller:
$logger = $this->get('monolog.logger.custom_channel');
or when defining a service:
services:
app.logger.custom_channel:
parent: monolog.logger.custom_channel
1. Passing parameters into the service?
If not already defined in the services.xml (or yaml), is the only way to pass parameter(s) into service is:
$container->setParameter('loader', $loader);
$container->get('myservice');
I suppose this way loader will be available to ALL services, not just "myservice"?
2. Passing an array of objects into the service?
The Template/DelegatingEngine class takes an array of engine object into the constructor, and I dont know how should I define that in the xml file:
public function __construct(array $engines = array())
{
$this->engines = array();
foreach ($engines as $engine) {
$this->addEngine($engine);
}
}
What should I put into the
<service id="myCustomeFramework.TemplateEngine" class="path\to\DelegateEngine" scope="prototype">
<argument>how can i pass an array of engines here?</argument>
</service>
Answer 1
Yes, it will be available for all services that uses that parameter and that are called after setting the parameter.
Answer 2
For passing an array as an argument to a service using xml you have to do it in this way:
<service id="myCustomeFramework.TemplateEngine" class="path\to\DelegateEngine" scope="prototype">
<argument type="collection">
<argument key="key">value</argument>
<argument key="key">value</argument>
<argument key="key">value</argument>
</argument>
</service>