diff --git a/CHANGELOG.md b/CHANGELOG.md index 100c45a6..27ea28dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - Update to Laravel 10 - Update to PHPUnit 10 +### Alert +- Messages are now translated at read time ([#1156](https://github.com/userfrosting/UserFrosting/pull/1156), [#811](https://github.com/userfrosting/UserFrosting/issues/811)). Messages will be translated when using `messages` and `getAndClearMessages`. `addMessage` now accept the optional placeholders, which will be stored with the alert message. `addMessageTranslated` is **deprecated**. +- Translator is not optional anymore. `setTranslator` method has been removed. + ## [5.0.0](https://github.com/userfrosting/framework/compare/4.6.1...5.0.0) With version 5, this repo can be used as a bare bone Slim & Symfony Console application. It include the necessary routing class, [PHP-DI](https://php-di.org) as the Dependency Injection Container, a PSR EventDispatcher, etc. SprinkleManager has also been moved from Core/System Sprinkle and completely rewritten. diff --git a/src/Alert/AlertStream.php b/src/Alert/AlertStream.php index 14559bd6..dee90a2d 100644 --- a/src/Alert/AlertStream.php +++ b/src/Alert/AlertStream.php @@ -12,7 +12,6 @@ namespace UserFrosting\Alert; -use RuntimeException; use UserFrosting\Fortress\ServerSideValidator; use UserFrosting\I18n\Translator; @@ -24,46 +23,29 @@ abstract class AlertStream /** * Create a new message stream. * - * @param string $messagesKey - * @param Translator|null $translator + * @param Translator $translator */ public function __construct( - protected string $messagesKey, - protected ?Translator $translator = null + protected Translator $translator ) { } - /** - * Set the translator to be used for all message streams. Must be done - * before `addMessageTranslated` can be used. - * - * @param Translator|null $translator - * - * @return static - */ - public function setTranslator(?Translator $translator = null): static - { - $this->translator = $translator; - - return $this; - } - /** * Adds a raw text message to the cache message stream. * - * @param string $type The type of message, indicating how it will be styled when outputted. Should be set to "success", "danger", "warning", or "info". - * @param string $message The message to be added to the message stream. + * @param string $type The type of message, indicating how it will be styled when outputted. Should be set to "success", "danger", "warning", or "info". + * @param string $message The message to be added to the message stream. + * @param mixed[]|int $placeholders An optional hash of placeholder names => placeholder values to substitute into the translated message. * * @return static */ - public function addMessage(string $type, string $message): static + public function addMessage(string $type, string $message, array|int $placeholders = []): static { - $messages = $this->messages(); - $messages[] = [ - 'type' => $type, - 'message' => $message, - ]; - $this->saveMessages($messages); + $this->storeMessage([ + 'type' => $type, + 'message' => $message, + 'placeholders' => $placeholders, + ]); return $this; } @@ -72,22 +54,16 @@ public function addMessage(string $type, string $message): static * Adds a text message to the cache message stream, translated into the currently selected language. * * @param string $type The type of message, indicating how it will be styled when outputted. Should be set to "success", "danger", "warning", or "info". - * @param string $messageId The message id for the message to be added to the message stream. + * @param string $message The message id for the message to be added to the message stream. * @param mixed[]|int $placeholders An optional hash of placeholder names => placeholder values to substitute into the translated message. * - * @throws RuntimeException - * * @return static + * + * @deprecated 5.1 Use `addMessage` instead. */ - public function addMessageTranslated(string $type, string $messageId, array|int $placeholders = []): static + public function addMessageTranslated(string $type, string $message, array|int $placeholders = []): static { - if ($this->translator === null) { - throw new RuntimeException('No translator has been set! Please call MessageStream::setTranslator first.'); - } - - $message = $this->translator->translate($messageId, $placeholders); - - return $this->addMessage($type, $message); + return $this->addMessage($type, $message, $placeholders); } /** @@ -97,7 +73,7 @@ public function addMessageTranslated(string $type, string $messageId, array|int * This is useful, because typically we don't want to view the same messages more than once. * Returns an array of messages, each of which is itself an array containing "type" and "message" fields. * - * @return array + * @return array */ public function getAndClearMessages(): array { @@ -107,6 +83,19 @@ public function getAndClearMessages(): array return $messages; } + /** + * Get the messages from this message stream. + * + * @return array + */ + public function messages(): array + { + $messages = $this->retrieveMessages(); + $messages = $this->translateMessages($messages); + + return $messages; + } + /** * Add error messages from a ServerSideValidator object to the message stream. * @@ -123,21 +112,29 @@ public function addValidationErrors(ServerSideValidator $validator): void } /** - * Return the translator for this message stream. + * Translates messages that have a message id instead of a message. * - * @return Translator|null The translator for this message stream. + * @param array $messages + * + * @return array */ - public function translator(): ?Translator + protected function translateMessages(array $messages): array { - return $this->translator; + $translated = []; + foreach ($messages as $message) { + $message['message'] = $this->translator->translate($message['message'], $message['placeholders']); + $translated[] = $message; + } + + return $translated; } /** * Get the messages from this message stream. * - * @return array An array of messages, each of which is itself an array containing "type" and "message" fields. + * @return array An array of messages, each of which is itself an array containing "type" and "message" fields. */ - abstract public function messages(): array; + abstract protected function retrieveMessages(): array; /** * Clear all messages from this message stream. @@ -147,7 +144,7 @@ abstract public function resetMessageStream(): void; /** * Save messages to the stream. * - * @param array $messages + * @param array{type: string, message: string, placeholders: mixed[]|int} $message */ - abstract protected function saveMessages(array $messages): void; + abstract protected function storeMessage(array $message): void; } diff --git a/src/Alert/CacheAlertStream.php b/src/Alert/CacheAlertStream.php index 0a33d478..9381171d 100644 --- a/src/Alert/CacheAlertStream.php +++ b/src/Alert/CacheAlertStream.php @@ -24,35 +24,27 @@ */ class CacheAlertStream extends AlertStream { - /** - * @var Cache Object We use the cache object so that added messages will automatically appear in the cache. - */ - protected Cache $cache; - - /** - * @var string Session id tied to the alert stream. - */ - protected string $session_id; - /** * Create a new message stream. * - * @param string $messagesKey Store the messages under this key - * @param Translator|null $translator - * @param Cache $cache - * @param string $sessionId + * @param string $messagesKey Store the messages under this key + * @param Translator $translator + * @param Cache $cache Object We use the cache object so that added messages will automatically appear in the cache. + * @param string $tag Cache tag id tied to the alert stream. Usually tied to the session ID. */ - public function __construct(string $messagesKey, ?Translator $translator, Cache $cache, string $sessionId) - { - $this->cache = $cache; - $this->session_id = $sessionId; - parent::__construct($messagesKey, $translator); + public function __construct( + protected string $messagesKey, + protected Translator $translator, + protected Cache $cache, + protected string $tag, + ) { + parent::__construct($translator); } /** * {@inheritDoc} */ - public function messages(): array + protected function retrieveMessages(): array { if ($this->getCache()->has($this->messagesKey)) { $data = $this->getCache()->get($this->messagesKey); @@ -74,8 +66,11 @@ public function resetMessageStream(): void /** * {@inheritDoc} */ - protected function saveMessages(array $messages): void + protected function storeMessage(array $message): void { + $messages = $this->retrieveMessages(); + $messages[] = $message; + $this->getCache()->forever($this->messagesKey, $messages); } @@ -84,6 +79,6 @@ protected function saveMessages(array $messages): void */ protected function getCache(): TaggedCache { - return $this->cache->tags('_s' . $this->session_id); + return $this->cache->tags('_s' . $this->tag); } } diff --git a/src/Alert/SessionAlertStream.php b/src/Alert/SessionAlertStream.php index 00975f55..5061061c 100644 --- a/src/Alert/SessionAlertStream.php +++ b/src/Alert/SessionAlertStream.php @@ -21,28 +21,25 @@ */ class SessionAlertStream extends AlertStream { - /** - * @var Session We use the session object so that added messages will automatically appear in the session. - */ - protected Session $session; - /** * Create a new message stream. * - * @param string $messagesKey Store the messages under this key - * @param Translator|null $translator - * @param Session $session + * @param string $messagesKey Store the messages under this key + * @param Session $session We use the session object so that added messages will automatically appear in the session. + * @param Translator $translator */ - public function __construct(string $messagesKey, ?Translator $translator, Session $session) - { - $this->session = $session; - parent::__construct($messagesKey, $translator); + public function __construct( + protected string $messagesKey, + protected Translator $translator, + protected Session $session, + ) { + parent::__construct($translator); } /** * {@inheritDoc} */ - public function messages(): array + protected function retrieveMessages(): array { $data = $this->session->get($this->messagesKey); @@ -60,8 +57,11 @@ public function resetMessageStream(): void /** * {@inheritDoc} */ - protected function saveMessages(array $messages): void + protected function storeMessage(array $message): void { + $messages = $this->retrieveMessages(); + $messages[] = $message; + $this->session->set($this->messagesKey, $messages); } } diff --git a/tests/Alert/CacheAlertStreamTest.php b/tests/Alert/CacheAlertStreamTest.php index 47920268..85ebfa74 100644 --- a/tests/Alert/CacheAlertStreamTest.php +++ b/tests/Alert/CacheAlertStreamTest.php @@ -16,6 +16,7 @@ use PHPUnit\Framework\TestCase; use UserFrosting\Alert\AlertStream; use UserFrosting\Alert\CacheAlertStream; +use UserFrosting\Cache\ArrayStore; use UserFrosting\I18n\Translator; class CacheAlertStreamTest extends TestCase @@ -23,36 +24,18 @@ class CacheAlertStreamTest extends TestCase use MockeryPHPUnitIntegration; protected string $key = 'alerts'; - - protected string $session_id = 'foo123'; + protected string $tag = 'foo123'; public function testConstructor(): void { $translator = m::mock(Translator::class); $cache = m::mock(Cache::class); - $stream = new CacheAlertStream($this->key, $translator, $cache, $this->session_id); + $stream = new CacheAlertStream($this->key, $translator, $cache, $this->tag); $this->assertInstanceOf(AlertStream::class, $stream); // @phpstan-ignore-line $this->assertInstanceOf(CacheAlertStream::class, $stream); // @phpstan-ignore-line } - /** - * @depends testConstructor - */ - public function testSetTranslator(): void - { - $translator = m::mock(Translator::class); - $cache = m::mock(Cache::class); - $stream = new CacheAlertStream($this->key, $translator, $cache, $this->session_id); - - $this->assertSame($translator, $stream->translator()); - - $translator2 = m::mock(Translator::class); - $this->assertNotSame($translator, $translator2); - $this->assertInstanceOf(CacheAlertStream::class, $stream->setTranslator($translator2)); // @phpstan-ignore-line - $this->assertSame($translator2, $stream->translator()); - } - /** * @depends testConstructor */ @@ -65,15 +48,16 @@ public function testAddMessage(): void // Set expectations $message = [ - 'type' => 'success', - 'message' => 'foo', + 'type' => 'success', + 'message' => 'foo', + 'placeholders' => [], ]; $tags->shouldReceive('has')->with($this->key)->once()->andReturn(false); $tags->shouldReceive('forever')->with($this->key, [$message])->once()->andReturn(null); - $cache->shouldReceive('tags')->with('_s' . $this->session_id)->andReturn($tags); + $cache->shouldReceive('tags')->with('_s' . $this->tag)->andReturn($tags); // Process - $stream = new CacheAlertStream($this->key, $translator, $cache, $this->session_id); + $stream = new CacheAlertStream($this->key, $translator, $cache, $this->tag); $this->assertInstanceOf(CacheAlertStream::class, $stream->addMessage('success', 'foo')); // @phpstan-ignore-line } @@ -89,16 +73,17 @@ public function testAddMessageWithExistingKey(): void // Set expectations $message = [ - 'type' => 'success', - 'message' => 'foo', + 'type' => 'success', + 'message' => 'foo', + 'placeholders' => [], ]; $tags->shouldReceive('has')->with($this->key)->once()->andReturn(true); $tags->shouldReceive('get')->with($this->key)->once()->andReturn(false); $tags->shouldReceive('forever')->with($this->key, [$message])->once()->andReturn(null); - $cache->shouldReceive('tags')->with('_s' . $this->session_id)->andReturn($tags); + $cache->shouldReceive('tags')->with('_s' . $this->tag)->andReturn($tags); // Process - $stream = new CacheAlertStream($this->key, $translator, $cache, $this->session_id); + $stream = new CacheAlertStream($this->key, $translator, $cache, $this->tag); $stream->addMessage('success', 'foo'); } @@ -114,16 +99,17 @@ public function testAddMessageWithExistingKeyNotEmpty(): void // Set expectations $message = [ - 'type' => 'success', - 'message' => 'foo', + 'type' => 'success', + 'message' => 'foo', + 'placeholders' => [], ]; $tags->shouldReceive('has')->with($this->key)->once()->andReturn(true); $tags->shouldReceive('get')->with($this->key)->once()->andReturn([$message]); $tags->shouldReceive('forever')->with($this->key, [$message, $message])->once()->andReturn(null); - $cache->shouldReceive('tags')->with('_s' . $this->session_id)->andReturn($tags); + $cache->shouldReceive('tags')->with('_s' . $this->tag)->andReturn($tags); // Process - $stream = new CacheAlertStream($this->key, $translator, $cache, $this->session_id); + $stream = new CacheAlertStream($this->key, $translator, $cache, $this->tag); $stream->addMessage('success', 'foo'); } @@ -139,25 +125,13 @@ public function testResetMessageStream(): void // Set expectations $tags->shouldReceive('forget')->with($this->key)->once()->andReturn(true); - $cache->shouldReceive('tags')->with('_s' . $this->session_id)->andReturn($tags); + $cache->shouldReceive('tags')->with('_s' . $this->tag)->andReturn($tags); // Process - $stream = new CacheAlertStream($this->key, $translator, $cache, $this->session_id); + $stream = new CacheAlertStream($this->key, $translator, $cache, $this->tag); $stream->resetMessageStream(); } - /** - * @depends testConstructor - */ - public function testAddMessageTranslatedWithNoTranslator(): void - { - $cache = m::mock(Cache::class); - $stream = new CacheAlertStream($this->key, null, $cache, $this->session_id); - - $this->expectException(\RuntimeException::class); - $stream->addMessageTranslated('success', 'foo', []); - } - /** * @depends testConstructor */ @@ -168,24 +142,29 @@ public function testAddMessageTranslated(): void $cache = m::mock(Cache::class); $tags = m::mock(\Illuminate\Cache\TaggedCache::class); - // + // Data $key = 'FOO'; $placeholder = ['key' => 'value']; $result = 'Bar'; // Set expectations - $translator->shouldReceive('translate')->with($key, $placeholder)->andReturn($result); $message = [ - 'type' => 'success', - 'message' => $result, + 'type' => 'success', + 'message' => $key, + 'placeholders' => $placeholder, ]; $tags->shouldReceive('has')->with($this->key)->once()->andReturn(false); + $tags->shouldReceive('has')->with($this->key)->once()->andReturn(true); + $tags->shouldReceive('get')->with($this->key)->once()->andReturn([$message]); $tags->shouldReceive('forever')->with($this->key, [$message])->once()->andReturn(null); - $cache->shouldReceive('tags')->with('_s' . $this->session_id)->andReturn($tags); + $cache->shouldReceive('tags')->with('_s' . $this->tag)->andReturn($tags); // Process - $stream = new CacheAlertStream($this->key, $translator, $cache, $this->session_id); - $stream->addMessageTranslated('success', $key, $placeholder); + $stream = new CacheAlertStream($this->key, $translator, $cache, $this->tag); + $stream->addMessageTranslated('success', $key, $placeholder); // @phpstan-ignore-line + + $translator->shouldReceive('translate')->with($key, $placeholder)->andReturn($result); + $this->assertSame($result, $stream->messages()[0]['message']); } /** @@ -201,16 +180,18 @@ public function testGetAndClearMessages(): void // Set expectations $message = [ - 'type' => 'success', - 'message' => 'foo', + 'type' => 'success', + 'message' => 'foo', + 'placeholders' => [], ]; $tags->shouldReceive('forget')->with($this->key)->once()->andReturn(true); $tags->shouldReceive('has')->with($this->key)->once()->andReturn(true); $tags->shouldReceive('get')->with($this->key)->once()->andReturn([$message]); - $cache->shouldReceive('tags')->with('_s' . $this->session_id)->andReturn($tags); + $cache->shouldReceive('tags')->with('_s' . $this->tag)->andReturn($tags); + $translator->shouldReceive('translate')->with('foo', [])->andReturn('foo'); // Process - $stream = new CacheAlertStream($this->key, $translator, $cache, $this->session_id); + $stream = new CacheAlertStream($this->key, $translator, $cache, $this->tag); $this->assertSame([$message], $stream->getAndClearMessages()); } @@ -233,22 +214,57 @@ public function testAddValidationErrors(): void $validator->shouldReceive('errors')->once()->andReturn($data); $message1 = [ - 'type' => 'danger', - 'message' => 'Name is required', + 'type' => 'danger', + 'message' => 'Name is required', + 'placeholders' => [], ]; $message2 = [ - 'type' => 'danger', - 'message' => 'Email should be a valid email address', + 'type' => 'danger', + 'message' => 'Email should be a valid email address', + 'placeholders' => [], ]; $tags->shouldReceive('has')->with($this->key)->andReturn(false, true, true); // Save 1, Save 2, display both $tags->shouldReceive('get')->with($this->key)->andReturn([$message1], [$message1, $message2]); // Save 2, Display both $tags->shouldReceive('forever')->with($this->key, [$message1])->once()->andReturn(null); // Save 1 $tags->shouldReceive('forever')->with($this->key, [$message1, $message2])->once()->andReturn(null); // Save 2 - $cache->shouldReceive('tags')->with('_s' . $this->session_id)->andReturn($tags); + $cache->shouldReceive('tags')->with('_s' . $this->tag)->andReturn($tags); + $translator->shouldReceive('translate')->with($message1['message'], [])->andReturn($message1['message']); + $translator->shouldReceive('translate')->with($message2['message'], [])->andReturn($message2['message']); // Process - $stream = new CacheAlertStream($this->key, $translator, $cache, $this->session_id); + $stream = new CacheAlertStream($this->key, $translator, $cache, $this->tag); $stream->addValidationErrors($validator); $this->assertSame([$message1, $message2], $stream->messages()); } + + public function testRealCacheService(): void + { + // Data + $key = 'FOO'; + $placeholder = ['key' => 'value']; + $result = 'Bar'; + $expectedResult = [ + 'type' => 'success', + 'message' => $result, + 'placeholders' => $placeholder, + ]; + + // Setup dependencies + $cache = (new ArrayStore())->instance(); + + // Setup Translator + $translator = m::mock(Translator::class); + $translator->shouldReceive('translate')->with($key, $placeholder)->andReturn($result); + + $stream = new CacheAlertStream($this->key, $translator, $cache, $this->tag); + $this->assertEmpty($stream->messages()); + $stream->addMessage('success', $key, $placeholder); + $this->assertCount(1, $stream->messages()); + $this->assertSame([$expectedResult], $stream->messages()); + $this->assertCount(1, $stream->messages()); + $stream->addMessage('success', $key, $placeholder); + $this->assertCount(2, $stream->messages()); + $this->assertSame([$expectedResult, $expectedResult], $stream->getAndClearMessages()); + $this->assertCount(0, $stream->messages()); + } } diff --git a/tests/Alert/SessionAlertStreamTest.php b/tests/Alert/SessionAlertStreamTest.php index e7a22d95..2f0ead39 100644 --- a/tests/Alert/SessionAlertStreamTest.php +++ b/tests/Alert/SessionAlertStreamTest.php @@ -10,6 +10,7 @@ namespace UserFrosting\Tests\Alert; +use Illuminate\Session\ArraySessionHandler; use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -23,7 +24,6 @@ class SessionAlertStreamTest extends TestCase use MockeryPHPUnitIntegration; protected string $key = 'alerts'; - protected string $session_id = 'foo123'; public function testConstructor(): void @@ -36,23 +36,6 @@ public function testConstructor(): void $this->assertInstanceOf(SessionAlertStream::class, $stream); // @phpstan-ignore-line } - /** - * @depends testConstructor - */ - public function testSetTranslator(): void - { - $translator = m::mock(Translator::class); - $session = m::mock(Session::class); - $stream = new SessionAlertStream($this->key, $translator, $session); - - $this->assertSame($translator, $stream->translator()); - - $translator2 = m::mock(Translator::class); - $this->assertNotSame($translator, $translator2); - $this->assertInstanceOf(SessionAlertStream::class, $stream->setTranslator($translator2)); // @phpstan-ignore-line - $this->assertSame($translator2, $stream->translator()); - } - /** * @depends testConstructor */ @@ -64,8 +47,9 @@ public function testAddMessage(): void // Set expectations $message = [ - 'type' => 'success', - 'message' => 'foo', + 'type' => 'success', + 'message' => 'foo', + 'placeholders' => [], ]; $session->shouldReceive('get')->with($this->key)->once()->andReturn(false); $session->shouldReceive('set')->with($this->key, [$message])->once()->andReturn(null); @@ -86,8 +70,9 @@ public function testAddMessageWithExistingKeyNotEmpty(): void // Set expectations $message = [ - 'type' => 'success', - 'message' => 'foo', + 'type' => 'success', + 'message' => 'foo', + 'placeholders' => [], ]; $session->shouldReceive('get')->with($this->key)->once()->andReturn([$message]); $session->shouldReceive('set')->with($this->key, [$message, $message])->once()->andReturn(null); @@ -114,18 +99,6 @@ public function testResetMessageStream(): void $stream->resetMessageStream(); } - /** - * @depends testConstructor - */ - public function testAddMessageTranslatedWithNoTranslator(): void - { - $session = m::mock(Session::class); - $stream = new SessionAlertStream($this->key, null, $session); - - $this->expectException(\RuntimeException::class); - $stream->addMessageTranslated('success', 'foo', []); - } - /** * @depends testConstructor */ @@ -135,7 +108,7 @@ public function testAddMessageTranslated(): void $translator = m::mock(Translator::class); $session = m::mock(Session::class); - // + // Data $key = 'FOO'; $placeholder = ['key' => 'value']; $result = 'Bar'; @@ -143,15 +116,20 @@ public function testAddMessageTranslated(): void // Set expectations $translator->shouldReceive('translate')->with($key, $placeholder)->andReturn($result); $message = [ - 'type' => 'success', - 'message' => $result, + 'type' => 'success', + 'message' => 'FOO', + 'placeholders' => ['key' => 'value'], ]; $session->shouldReceive('get')->with($this->key)->once()->andReturn(false); $session->shouldReceive('set')->with($this->key, [$message])->once()->andReturn(null); + $session->shouldReceive('get')->with($this->key)->once()->andReturn([$message]); // Process $stream = new SessionAlertStream($this->key, $translator, $session); - $stream->addMessageTranslated('success', $key, $placeholder); + $stream->addMessageTranslated('success', $key, $placeholder); // @phpstan-ignore-line + + $translator->shouldReceive('translate')->with($key, $placeholder)->andReturn($result); + $this->assertSame($result, $stream->messages()[0]['message']); } /** @@ -165,11 +143,13 @@ public function testGetAndClearMessages(): void // Set expectations $message = [ - 'type' => 'success', - 'message' => 'foo', + 'type' => 'success', + 'message' => 'foo', + 'placeholders' => [], ]; $session->shouldReceive('get')->with($this->key)->once()->andReturn([$message]); $session->shouldReceive('set')->with($this->key, [])->once()->andReturn(true); + $translator->shouldReceive('translate')->with('foo', [])->andReturn('foo'); // Process $stream = new SessionAlertStream($this->key, $translator, $session); @@ -194,20 +174,58 @@ public function testAddValidationErrors(): void $validator->shouldReceive('errors')->once()->andReturn($data); $message1 = [ - 'type' => 'danger', - 'message' => 'Name is required', + 'type' => 'danger', + 'message' => 'Name is required', + 'placeholders' => [], ]; $message2 = [ - 'type' => 'danger', - 'message' => 'Email should be a valid email address', + 'type' => 'danger', + 'message' => 'Email should be a valid email address', + 'placeholders' => [], ]; $session->shouldReceive('get')->with($this->key)->andReturn(false, [$message1], [$message1, $message2]); // Save 1, Save 2, Display both $session->shouldReceive('set')->with($this->key, [$message1])->andReturn(null); // Save 1 $session->shouldReceive('set')->with($this->key, [$message1, $message2])->andReturn(null); // Save 2 + $translator->shouldReceive('translate')->with($message1['message'], [])->andReturn($message1['message']); + $translator->shouldReceive('translate')->with($message2['message'], [])->andReturn($message2['message']); // Process $stream = new SessionAlertStream($this->key, $translator, $session); $stream->addValidationErrors($validator); $this->assertSame([$message1, $message2], $stream->messages()); } + + public function testRealSessionService(): void + { + // Data + $key = 'FOO'; + $placeholder = ['key' => 'value']; + $result = 'Bar'; + $expectedResult = [ + 'type' => 'success', + 'message' => $result, + 'placeholders' => $placeholder, + ]; + + // Setup dependencies + $handler = new ArraySessionHandler(60); + $session = new Session($handler); + $session->destroy(); + $session->start(); + + // Setup Translator + $translator = m::mock(Translator::class); + $translator->shouldReceive('translate')->with($key, $placeholder)->andReturn($result); + + $stream = new SessionAlertStream($this->key, $translator, $session); + $this->assertEmpty($stream->messages()); + $stream->addMessage('success', $key, $placeholder); + $this->assertCount(1, $stream->messages()); + $this->assertSame([$expectedResult], $stream->messages()); + $this->assertCount(1, $stream->messages()); + $stream->addMessage('success', $key, $placeholder); + $this->assertCount(2, $stream->messages()); + $this->assertSame([$expectedResult, $expectedResult], $stream->getAndClearMessages()); + $this->assertCount(0, $stream->messages()); + } }