Skip to content

Commit

Permalink
Add configurable mailer
Browse files Browse the repository at this point in the history
  • Loading branch information
Romain Mouillard committed Nov 14, 2018
1 parent d431d9d commit 4a822bd
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 119 deletions.
2 changes: 2 additions & 0 deletions docs/reference/advanced_configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ Full configuration options:
profile:
default_avatar: 'bundles/sonatauser/default_avatar.png' # Default avatar displayed if the user doesn't have one
mailer: sonata.user.mailer.default # Service used to send emails
# override FOSUser default serialization
jms_serializer:
metadata:
Expand Down
13 changes: 13 additions & 0 deletions docs/reference/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,19 @@ Add these config lines to your FOSUserBundle configuration:
address: "%mailer_user%"
sender_name: "%mailer_user%"
Mailer Configuration
~~~~~~~~~~~~~~~~~~~~

You can define a custom mailer to send reset password emails.
Your mailer will have to implement ``FOS\UserBundle\Mailer\MailerInterface``.

.. code-block:: yaml
# config/packages/sonata.yaml
sonata_user:
mailer: custom.mailer.service.id
Integrating the bundle into the Sonata Admin Bundle
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
48 changes: 5 additions & 43 deletions src/Action/SendEmailAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace Sonata\UserBundle\Action;

use FOS\UserBundle\Model\UserInterface;
use FOS\UserBundle\Mailer\MailerInterface;
use FOS\UserBundle\Model\UserManagerInterface;
use FOS\UserBundle\Util\TokenGeneratorInterface;
use Sonata\AdminBundle\Admin\Pool;
Expand Down Expand Up @@ -52,7 +52,7 @@ final class SendEmailAction
private $userManager;

/**
* @var \Swift_Mailer
* @var MailerInterface
*/
private $mailer;

Expand All @@ -66,27 +66,15 @@ final class SendEmailAction
*/
private $resetTtl;

/**
* @var string[]
*/
private $fromEmail;

/**
* @var string
*/
private $template;

public function __construct(
EngineInterface $templating,
UrlGeneratorInterface $urlGenerator,
Pool $adminPool,
TemplateRegistryInterface $templateRegistry,
UserManagerInterface $userManager,
\Swift_Mailer $mailer,
MailerInterface $mailer,
TokenGeneratorInterface $tokenGenerator,
int $resetTtl,
array $fromEmail,
string $template
int $resetTtl
) {
$this->templating = $templating;
$this->urlGenerator = $urlGenerator;
Expand All @@ -96,8 +84,6 @@ public function __construct(
$this->mailer = $mailer;
$this->tokenGenerator = $tokenGenerator;
$this->resetTtl = $resetTtl;
$this->fromEmail = $fromEmail;
$this->template = $template;
}

public function __invoke(Request $request): Response
Expand All @@ -123,7 +109,7 @@ public function __invoke(Request $request): Response
$user->setConfirmationToken($this->tokenGenerator->generateToken());
}

$this->sendResettingEmailMessage($user);
$this->mailer->sendResettingEmailMessage($user);
$user->setPasswordRequestedAt(new \DateTime());
$this->userManager->updateUser($user);
}
Expand All @@ -132,28 +118,4 @@ public function __invoke(Request $request): Response
'username' => $username,
]));
}

private function sendResettingEmailMessage(UserInterface $user): void
{
$url = $this->urlGenerator->generate('sonata_user_admin_resetting_reset', [
'token' => $user->getConfirmationToken(),
], UrlGeneratorInterface::ABSOLUTE_URL);

$rendered = $this->templating->render($this->template, [
'user' => $user,
'confirmationUrl' => $url,
]);

// Render the email, use the first line as the subject, and the rest as the body
$renderedLines = explode(PHP_EOL, trim($rendered));
$subject = array_shift($renderedLines);
$body = implode(PHP_EOL, $renderedLines);
$message = (new \Swift_Message())
->setSubject($subject)
->setFrom($this->fromEmail)
->setTo((string) $user->getEmail())
->setBody($body);

$this->mailer->send($message);
}
}
1 change: 1 addition & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ public function getConfigTreeBuilder()
->scalarNode('default_avatar')->defaultValue('bundles/sonatauser/default_avatar.png')->end()
->end()
->end()
->scalarNode('mailer')->defaultValue('sonata.user.mailer.default')->info('Custom mailer used to send reset password emails')->end()
->end()
;

Expand Down
58 changes: 14 additions & 44 deletions src/DependencyInjection/SonataUserExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class_exists('Sonata\GoogleAuthenticator\GoogleAuthenticator')) {
$loader->load('twig.xml');
$loader->load('command.xml');
$loader->load('actions.xml');
$loader->load('mailer.xml');

if ('orm' === $config['manager_type'] && isset(
$bundles['FOSRestBundle'],
Expand All @@ -105,6 +106,7 @@ class_exists('Sonata\GoogleAuthenticator\GoogleAuthenticator')) {

$this->configureTranslationDomain($config, $container);
$this->configureController($config, $container);
$this->configureMailer($config, $container);

$container->setParameter('sonata.user.default_avatar', $config['profile']['default_avatar']);

Expand All @@ -114,13 +116,9 @@ class_exists('Sonata\GoogleAuthenticator\GoogleAuthenticator')) {
}

/**
* @param array $config
*
* @throws \RuntimeException
*
* @return array
*/
public function fixImpersonating(array $config)
public function fixImpersonating(array $config): array
{
if (isset($config['impersonating'], $config['impersonating_route'])) {
throw new \RuntimeException('you can\'t have `impersonating` and `impersonating_route` keys defined at the same time');
Expand All @@ -144,15 +142,7 @@ public function fixImpersonating(array $config)
return $config;
}

/**
* @param array $config
* @param ContainerBuilder $container
*
* @throws \RuntimeException
*
* @return mixed
*/
public function configureGoogleAuthenticator($config, ContainerBuilder $container)
public function configureGoogleAuthenticator(array $config, ContainerBuilder $container): void
{
$container->setParameter('sonata.user.google.authenticator.enabled', $config['google_authenticator']['enabled']);

Expand All @@ -177,11 +167,7 @@ public function configureGoogleAuthenticator($config, ContainerBuilder $containe
->replaceArgument(0, $config['google_authenticator']['server']);
}

/**
* @param array $config
* @param ContainerBuilder $container
*/
public function configureClass($config, ContainerBuilder $container): void
public function configureClass(array $config, ContainerBuilder $container): void
{
if ('orm' === $config['manager_type']) {
$modelType = 'entity';
Expand All @@ -195,39 +181,29 @@ public function configureClass($config, ContainerBuilder $container): void
$container->setParameter(sprintf('sonata.user.admin.group.%s', $modelType), $config['class']['group']);
}

/**
* @param array $config
* @param ContainerBuilder $container
*/
public function configureAdminClass($config, ContainerBuilder $container): void
public function configureAdminClass(array $config, ContainerBuilder $container): void
{
$container->setParameter('sonata.user.admin.user.class', $config['admin']['user']['class']);
$container->setParameter('sonata.user.admin.group.class', $config['admin']['group']['class']);
}

/**
* @param array $config
* @param ContainerBuilder $container
*/
public function configureTranslationDomain($config, ContainerBuilder $container): void
public function configureTranslationDomain(array $config, ContainerBuilder $container): void
{
$container->setParameter('sonata.user.admin.user.translation_domain', $config['admin']['user']['translation']);
$container->setParameter('sonata.user.admin.group.translation_domain', $config['admin']['group']['translation']);
}

/**
* @param array $config
* @param ContainerBuilder $container
*/
public function configureController($config, ContainerBuilder $container): void
public function configureController(array $config, ContainerBuilder $container): void
{
$container->setParameter('sonata.user.admin.user.controller', $config['admin']['user']['controller']);
$container->setParameter('sonata.user.admin.group.controller', $config['admin']['group']['controller']);
}

/**
* @param array $config
*/
public function configureMailer(array $config, ContainerBuilder $container): void
{
$container->setAlias('sonata.user.mailer', $config['mailer']);
}

public function registerDoctrineMapping(array $config): void
{
foreach ($config['class'] as $type => $class) {
Expand Down Expand Up @@ -262,11 +238,8 @@ public function registerDoctrineMapping(array $config): void

/**
* Adds aliases for user & group managers depending on $managerType.
*
* @param ContainerBuilder $container
* @param $managerType
*/
protected function aliasManagers(ContainerBuilder $container, $managerType): void
protected function aliasManagers(ContainerBuilder $container, string $managerType): void
{
$container->setAlias('sonata.user.user_manager', sprintf('sonata.user.%s.user_manager', $managerType));
$container->setAlias('sonata.user.group_manager', sprintf('sonata.user.%s.group_manager', $managerType));
Expand All @@ -276,9 +249,6 @@ protected function aliasManagers(ContainerBuilder $container, $managerType): voi
$container->getAlias('sonata.user.group_manager')->setPublic(true);
}

/**
* @param array $config
*/
private function checkManagerTypeToModelTypeMapping(array $config): void
{
$managerType = $config['manager_type'];
Expand Down
85 changes: 85 additions & 0 deletions src/Mailer/Mailer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sonata\UserBundle\Mailer;

use FOS\UserBundle\Mailer\MailerInterface;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

final class Mailer implements MailerInterface
{
/**
* @var UrlGeneratorInterface
*/
private $urlGenerator;

/**
* @var EngineInterface
*/
private $templating;

/**
* @var \Swift_Mailer
*/
private $mailer;

/**
* @var array
*/
private $fromEmail;

/**
* @var string
*/
private $emailTemplate;

public function __construct(UrlGeneratorInterface $urlGenerator, EngineInterface $templating, \Swift_Mailer $mailer, array $fromEmail, string $emailTemplate)
{
$this->urlGenerator = $urlGenerator;
$this->templating = $templating;
$this->mailer = $mailer;
$this->fromEmail = $fromEmail;
$this->emailTemplate = $emailTemplate;
}

public function sendResettingEmailMessage(UserInterface $user): void
{
$url = $this->urlGenerator->generate('sonata_user_admin_resetting_reset', [
'token' => $user->getConfirmationToken(),
], UrlGeneratorInterface::ABSOLUTE_URL);

$rendered = $this->templating->render($this->emailTemplate, [
'user' => $user,
'confirmationUrl' => $url,
]);

// Render the email, use the first line as the subject, and the rest as the body
$renderedLines = explode(PHP_EOL, trim($rendered));
$subject = array_shift($renderedLines);
$body = implode(PHP_EOL, $renderedLines);
$message = (new \Swift_Message())
->setSubject($subject)
->setFrom($this->fromEmail)
->setTo((string) $user->getEmail())
->setBody($body);

$this->mailer->send($message);
}

public function sendConfirmationEmailMessage(UserInterface $user): void
{
throw new \LogicException('This method is not implemented.');
}
}
4 changes: 1 addition & 3 deletions src/Resources/config/actions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@
<argument type="service" id="sonata.admin.pool"/>
<argument type="service" id="sonata.admin.global_template_registry"/>
<argument type="service" id="fos_user.user_manager"/>
<argument type="service" id="mailer"/>
<argument type="service" id="sonata.user.mailer"/>
<argument type="service" id="fos_user.util.token_generator"/>
<argument>%fos_user.resetting.retry_ttl%</argument>
<argument>%fos_user.resetting.email.from_email%</argument>
<argument>%fos_user.resetting.email.template%</argument>
</service>
<service id="Sonata\UserBundle\Action\CheckEmailAction" class="Sonata\UserBundle\Action\CheckEmailAction" public="true">
<argument type="service" id="templating"/>
Expand Down
12 changes: 12 additions & 0 deletions src/Resources/config/mailer.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="sonata.user.mailer.default" class="Sonata\UserBundle\Mailer\Mailer">
<argument type="service" id="router"/>
<argument type="service" id="sonata.templating"/>
<argument type="service" id="mailer"/>
<argument>%fos_user.resetting.email.from_email%</argument>
<argument>%fos_user.resetting.email.template%</argument>
</service>
</services>
</container>

0 comments on commit 4a822bd

Please sign in to comment.