From faf74150e9481ad9338eb6cc2428d02b24e9fc43 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Sun, 6 Oct 2019 21:03:20 +0200 Subject: [PATCH] Mailer: Use users locale for translation --- .../TranslationServiceProvider.php | 6 +- src/Mail/EngelsystemMailer.php | 59 +++++++++- .../TranslationServiceProviderTest.php | 18 +-- tests/Unit/Mail/EngelsystemMailerTest.php | 107 ++++++++++++------ tests/Unit/TestCase.php | 4 +- 5 files changed, 141 insertions(+), 53 deletions(-) diff --git a/src/Helpers/Translation/TranslationServiceProvider.php b/src/Helpers/Translation/TranslationServiceProvider.php index 09337dad..05e782ec 100644 --- a/src/Helpers/Translation/TranslationServiceProvider.php +++ b/src/Helpers/Translation/TranslationServiceProvider.php @@ -40,8 +40,10 @@ class TranslationServiceProvider extends ServiceProvider 'localeChangeCallback' => [$this, 'setLocale'], ] ); - $this->app->instance(Translator::class, $translator); - $this->app->instance('translator', $translator); + $this->app->singleton(Translator::class, function () use ($translator) { + return $translator; + }); + $this->app->alias(Translator::class, 'translator'); } /** diff --git a/src/Mail/EngelsystemMailer.php b/src/Mail/EngelsystemMailer.php index 81660681..87915d67 100644 --- a/src/Mail/EngelsystemMailer.php +++ b/src/Mail/EngelsystemMailer.php @@ -2,6 +2,8 @@ namespace Engelsystem\Mail; +use Engelsystem\Helpers\Translation\Translator; +use Engelsystem\Models\User\User; use Engelsystem\Renderer\Renderer; use Swift_Mailer as SwiftMailer; @@ -10,30 +12,75 @@ class EngelsystemMailer extends Mailer /** @var Renderer|null */ protected $view; + /** @var Translator|null */ + protected $translation; + /** @var string */ protected $subjectPrefix = null; /** * @param SwiftMailer $mailer * @param Renderer $view + * @param Translator $translation */ - public function __construct(SwiftMailer $mailer, Renderer $view = null) + public function __construct(SwiftMailer $mailer, Renderer $view = null, Translator $translation = null) { parent::__construct($mailer); + $this->translation = $translation; $this->view = $view; } + /** + * @param string|string[]|User $to + * @param string $subject + * @param string $template + * @param array $data + * @param string|null $locale + * @return int + */ + public function sendViewTranslated( + $to, + string $subject, + string $template, + array $data = [], + ?string $locale = null + ): int { + if ($to instanceof User) { + $locale = $locale ?: $to->settings->language; + $to = $to->contact->email ? $to->contact->email : $to->email; + } + + $activeLocale = null; + if ( + $locale + && $this->translation + && isset($this->translation->getLocales()[$locale]) + ) { + $activeLocale = $this->translation->getLocale(); + $this->translation->setLocale($locale); + } + + $subject = $this->translation ? $this->translation->translate($subject) : $subject; + $sentMails = $this->sendView($to, $subject, $template, $data); + + if ($activeLocale) { + $this->translation->setLocale($activeLocale); + } + + return $sentMails; + } + /** * Send a template * - * @param string $to - * @param string $subject - * @param string $template - * @param array $data + * @param string|string[] $to + * @param string $subject + * @param string $template + * @param array $data * @return int */ - public function sendView($to, $subject, $template, $data = []): int + public function sendView($to, string $subject, string $template, array $data = []): int { $body = $this->view->render($template, $data); diff --git a/tests/Unit/Helpers/Translation/TranslationServiceProviderTest.php b/tests/Unit/Helpers/Translation/TranslationServiceProviderTest.php index 91307bdd..1822f353 100644 --- a/tests/Unit/Helpers/Translation/TranslationServiceProviderTest.php +++ b/tests/Unit/Helpers/Translation/TranslationServiceProviderTest.php @@ -21,7 +21,7 @@ class TranslationServiceProviderTest extends ServiceProviderTest $locales = ['fo_OO' => 'Foo', 'fo_OO.BAR' => 'Foo (Bar)', 'te_ST.WTF-9' => 'WTF\'s Testing?']; $config = new Config(['locales' => $locales, 'default_locale' => $defaultLocale]); - $app = $this->getApp(['make', 'instance', 'get']); + $app = $this->getApp(['make', 'singleton', 'alias', 'get']); /** @var Session|MockObject $session */ $session = $this->createMock(Session::class); /** @var Translator|MockObject $translator */ @@ -60,12 +60,16 @@ class TranslationServiceProviderTest extends ServiceProviderTest ) ->willReturn($translator); - $app->expects($this->exactly(2)) - ->method('instance') - ->withConsecutive( - [Translator::class, $translator], - ['translator', $translator] - ); + $app->expects($this->once()) + ->method('singleton') + ->willReturnCallback(function (string $abstract, callable $callback) use ($translator) { + $this->assertEquals(Translator::class, $abstract); + $this->assertEquals($translator, $callback()); + }); + + $app->expects($this->once()) + ->method('alias') + ->with(Translator::class, 'translator'); $serviceProvider->register(); } diff --git a/tests/Unit/Mail/EngelsystemMailerTest.php b/tests/Unit/Mail/EngelsystemMailerTest.php index 12dc3b0b..cdbdf435 100644 --- a/tests/Unit/Mail/EngelsystemMailerTest.php +++ b/tests/Unit/Mail/EngelsystemMailerTest.php @@ -2,15 +2,22 @@ namespace Engelsystem\Test\Unit\Mail; +use Engelsystem\Helpers\Translation\Translator; use Engelsystem\Mail\EngelsystemMailer; +use Engelsystem\Models\User\Contact; +use Engelsystem\Models\User\Settings; +use Engelsystem\Models\User\User; use Engelsystem\Renderer\Renderer; +use Engelsystem\Test\Unit\HasDatabase; +use Engelsystem\Test\Unit\TestCase; use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; use Swift_Mailer as SwiftMailer; use Swift_Message as SwiftMessage; class EngelsystemMailerTest extends TestCase { + use HasDatabase; + /** * @covers \Engelsystem\Mail\EngelsystemMailer::__construct * @covers \Engelsystem\Mail\EngelsystemMailer::sendView @@ -24,21 +31,69 @@ class EngelsystemMailerTest extends TestCase /** @var EngelsystemMailer|MockObject $mailer */ $mailer = $this->getMockBuilder(EngelsystemMailer::class) ->setConstructorArgs(['mailer' => $swiftMailer, 'view' => $view]) - ->setMethods(['send']) + ->onlyMethods(['send']) ->getMock(); - $mailer->expects($this->once()) - ->method('send') - ->with('foo@bar.baz', 'Lorem dolor', 'Rendered Stuff!') - ->willReturn(1); - $view->expects($this->once()) - ->method('render') - ->with('test/template.tpl', ['dev' => true]) - ->willReturn('Rendered Stuff!'); + $this->setExpects($mailer, 'send', ['foo@bar.baz', 'Lorem dolor', 'Rendered Stuff!'], 1); + $this->setExpects($view, 'render', ['test/template.tpl', ['dev' => true]], 'Rendered Stuff!'); $return = $mailer->sendView('foo@bar.baz', 'Lorem dolor', 'test/template.tpl', ['dev' => true]); $this->equalTo(1, $return); } + /** + * @covers \Engelsystem\Mail\EngelsystemMailer::sendViewTranslated + */ + public function testSendViewTranslated() + { + $this->initDatabase(); + + $settings = new Settings([ + 'language' => 'de_DE', + 'theme' => '', + ]); + $contact = new Contact(['email' => null]); + $user = new User([ + 'id' => 42, + 'name' => 'username', + 'email' => 'foo@bar.baz', + 'password' => '', + 'api_key' => '', + ]); + $user->save(); + $settings->user()->associate($user)->save(); + $contact->user()->associate($user)->save(); + + /** @var Renderer|MockObject $view */ + $view = $this->createMock(Renderer::class); + /** @var SwiftMailer|MockObject $swiftMailer */ + $swiftMailer = $this->createMock(SwiftMailer::class); + /** @var Translator|MockObject $translator */ + $translator = $this->createMock(Translator::class); + + /** @var EngelsystemMailer|MockObject $mailer */ + $mailer = $this->getMockBuilder(EngelsystemMailer::class) + ->setConstructorArgs(['mailer' => $swiftMailer, 'view' => $view, 'translation' => $translator]) + ->onlyMethods(['sendView']) + ->getMock(); + + $this->setExpects($mailer, 'sendView', ['foo@bar.baz', 'Lorem dolor', 'test/template.tpl', ['dev' => true]], 1); + $this->setExpects($translator, 'getLocales', null, ['de_DE' => 'de_DE', 'en_US' => 'en_US']); + $this->setExpects($translator, 'getLocale', null, 'en_US'); + $this->setExpects($translator, 'translate', ['translatable.text'], 'Lorem dolor'); + $translator->expects($this->exactly(2)) + ->method('setLocale') + ->withConsecutive(['de_DE'], ['en_US']); + + $return = $mailer->sendViewTranslated( + $user, + 'translatable.text', + 'test/template.tpl', + ['dev' => true], + 'de_DE' + ); + $this->equalTo(1, $return); + } + /** * @covers \Engelsystem\Mail\EngelsystemMailer::getSubjectPrefix * @covers \Engelsystem\Mail\EngelsystemMailer::send @@ -50,32 +105,12 @@ class EngelsystemMailerTest extends TestCase $message = $this->createMock(SwiftMessage::class); /** @var SwiftMailer|MockObject $swiftMailer */ $swiftMailer = $this->createMock(SwiftMailer::class); - $swiftMailer->expects($this->once()) - ->method('createMessage') - ->willReturn($message); - $swiftMailer->expects($this->once()) - ->method('send') - ->willReturn(1); - - $message->expects($this->once()) - ->method('setTo') - ->with(['to@xam.pel']) - ->willReturn($message); - - $message->expects($this->once()) - ->method('setFrom') - ->with('foo@bar.baz', 'Lorem Ipsum') - ->willReturn($message); - - $message->expects($this->once()) - ->method('setSubject') - ->with('[Mail test] Foo Bar') - ->willReturn($message); - - $message->expects($this->once()) - ->method('setBody') - ->with('Lorem Ipsum!') - ->willReturn($message); + $this->setExpects($swiftMailer, 'createMessage', null, $message); + $this->setExpects($swiftMailer, 'send', null, 1); + $this->setExpects($message, 'setTo', [['to@xam.pel']], $message); + $this->setExpects($message, 'setFrom', ['foo@bar.baz', 'Lorem Ipsum'], $message); + $this->setExpects($message, 'setSubject', ['[Mail test] Foo Bar'], $message); + $this->setExpects($message, 'setBody', ['Lorem Ipsum!'], $message); $mailer = new EngelsystemMailer($swiftMailer); $mailer->setFromAddress('foo@bar.baz'); diff --git a/tests/Unit/TestCase.php b/tests/Unit/TestCase.php index d09104d4..e1a704d9 100644 --- a/tests/Unit/TestCase.php +++ b/tests/Unit/TestCase.php @@ -2,8 +2,8 @@ namespace Engelsystem\Test\Unit; -use PHPUnit\Framework\MockObject\Matcher\InvokedRecorder; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\Rule\InvocationOrder; use PHPUnit\Framework\TestCase as PHPUnitTestCase; abstract class TestCase extends PHPUnitTestCase @@ -13,7 +13,7 @@ abstract class TestCase extends PHPUnitTestCase * @param string $method * @param array $arguments * @param mixed $return - * @param InvokedRecorder $times + * @param InvocationOrder $times */ protected function setExpects($object, $method, $arguments = null, $return = null, $times = null) {