Skip to content

Commit

Permalink
Implements multiple Flash messages
Browse files Browse the repository at this point in the history
The FlashComponent now stores Flash messages as a stack, meaning that if
you make successive calls to FlashComponent::set() or to the magic call,
each messages will be appended to be rendered with one call to the
FlashHelper::render() method.
  • Loading branch information
HavokInspiration committed Mar 26, 2015
1 parent 7140aa4 commit e73e974
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 44 deletions.
20 changes: 17 additions & 3 deletions src/Controller/Component/FlashComponent.php
Expand Up @@ -42,7 +42,8 @@ class FlashComponent extends Component
protected $_defaultConfig = [
'key' => 'flash',
'element' => 'default',
'params' => []
'params' => [],
'clear' => false
];

/**
Expand All @@ -59,6 +60,8 @@ public function __construct(ComponentRegistry $registry, array $config = [])

/**
* Used to set a session variable that can be used to output messages in the view.
* If you make consecutive calls to this method, the messages will stack (if they are
* set with the same flash key)
*
* In your controller: $this->Flash->set('This has been saved');
*
Expand All @@ -67,6 +70,7 @@ public function __construct(ComponentRegistry $registry, array $config = [])
* - `key` The key to set under the session's Flash key
* - `element` The element used to render the flash message. Default to 'default'.
* - `params` An array of variables to make available when using an element
* - `clear` A bool stating if the current stack should be cleared to start a new one
*
* @param string|\Exception $message Message to be flashed. If an instance
* of \Exception the exception message will be used and code will be set
Expand All @@ -91,12 +95,19 @@ public function set($message, array $options = [])
$options['element'] = 'Flash/' . $element;
}

$this->_session->write('Flash.' . $options['key'], [
$messages = [];
if ($options['clear'] === false) {
$messages = $this->_session->read('Flash.' . $options['key']);
}

$messages[] = [
'message' => $message,
'key' => $options['key'],
'element' => $options['element'],
'params' => $options['params']
]);
];

$this->_session->write('Flash.' . $options['key'], $messages);
}

/**
Expand All @@ -106,6 +117,9 @@ public function set($message, array $options = [])
* success.ctp element under `src/Template/Element/Flash` for rendering the
* flash message.
*
* If you make consecutive calls to this method, the messages will stack (if they are
* set with the same flash key)
*
* Note that the parameter `element` will be always overridden. In order to call a
* specific element from a plugin, you should set the `plugin` option in $args.
*
Expand Down
12 changes: 10 additions & 2 deletions src/View/Helper/FlashHelper.php
Expand Up @@ -57,6 +57,9 @@ class FlashHelper extends Helper
* ]);
* ```
*
* If you have several messages stored in the Session, each message will be rendered in its own
* element.
*
* @param string $key The [Flash.]key you are rendering in the view.
* @param array $options Additional options to use for the creation of this flash message.
* Supports the 'params', and 'element' keys that are used in the helper.
Expand All @@ -77,10 +80,15 @@ public function render($key = 'flash', array $options = [])
$key
));
}
$flash = $options + $flash;
$this->request->session()->delete("Flash.$key");

return $this->_View->element($flash['element'], $flash);
$out = '';
foreach ($flash as $message) {
$message = $options + $message;
$out .= $this->_View->element($message['element'], $message);
}

return $out;
}

/**
Expand Down
126 changes: 102 additions & 24 deletions tests/TestCase/Controller/Component/FlashComponentTest.php
Expand Up @@ -67,16 +67,18 @@ public function testSet()

$this->Flash->set('This is a test message');
$expected = [
'message' => 'This is a test message',
'key' => 'flash',
'element' => 'Flash/default',
'params' => []
[
'message' => 'This is a test message',
'key' => 'flash',
'element' => 'Flash/default',
'params' => []
]
];
$result = $this->Session->read('Flash.flash');
$this->assertEquals($expected, $result);

$this->Flash->set('This is a test message', ['element' => 'test', 'params' => ['foo' => 'bar']]);
$expected = [
$expected[] = [
'message' => 'This is a test message',
'key' => 'flash',
'element' => 'Flash/test',
Expand All @@ -86,7 +88,7 @@ public function testSet()
$this->assertEquals($expected, $result);

$this->Flash->set('This is a test message', ['element' => 'MyPlugin.alert']);
$expected = [
$expected[] = [
'message' => 'This is a test message',
'key' => 'flash',
'element' => 'MyPlugin.Flash/alert',
Expand All @@ -97,15 +99,52 @@ public function testSet()

$this->Flash->set('This is a test message', ['key' => 'foobar']);
$expected = [
'message' => 'This is a test message',
'key' => 'foobar',
'element' => 'Flash/default',
'params' => []
[
'message' => 'This is a test message',
'key' => 'foobar',
'element' => 'Flash/default',
'params' => []
]
];
$result = $this->Session->read('Flash.foobar');
$this->assertEquals($expected, $result);
}

/**
* test setting messages with using the clear option
*
* @return void
* @covers \Cake\Controller\Component\FlashComponent::set
*/
public function testSetWithClear()
{
$this->assertNull($this->Session->read('Flash.flash'));

$this->Flash->set('This is a test message');
$expected = [
[
'message' => 'This is a test message',
'key' => 'flash',
'element' => 'Flash/default',
'params' => []
]
];
$result = $this->Session->read('Flash.flash');
$this->assertEquals($expected, $result);

$this->Flash->set('This is another test message', ['clear' => true]);
$expected = [
[
'message' => 'This is another test message',
'key' => 'flash',
'element' => 'Flash/default',
'params' => []
]
];
$result = $this->Session->read('Flash.flash');
$this->assertEquals($expected, $result);
}

/**
* testSetWithException method
*
Expand All @@ -118,10 +157,12 @@ public function testSetWithException()

$this->Flash->set(new \Exception('This is a test message', 404));
$expected = [
'message' => 'This is a test message',
'key' => 'flash',
'element' => 'Flash/default',
'params' => ['code' => 404]
[
'message' => 'This is a test message',
'key' => 'flash',
'element' => 'Flash/default',
'params' => ['code' => 404]
]
];
$result = $this->Session->read('Flash.flash');
$this->assertEquals($expected, $result);
Expand All @@ -139,10 +180,12 @@ public function testSetWithComponentConfiguration()
$this->Controller->loadComponent('Flash', ['element' => 'test']);
$this->Controller->Flash->set('This is a test message');
$expected = [
'message' => 'This is a test message',
'key' => 'flash',
'element' => 'Flash/test',
'params' => []
[
'message' => 'This is a test message',
'key' => 'flash',
'element' => 'Flash/test',
'params' => []
]
];
$result = $this->Session->read('Flash.flash');
$this->assertEquals($expected, $result);
Expand All @@ -160,17 +203,19 @@ public function testCall()

$this->Flash->success('It worked');
$expected = [
'message' => 'It worked',
'key' => 'flash',
'element' => 'Flash/success',
'params' => []
[
'message' => 'It worked',
'key' => 'flash',
'element' => 'Flash/success',
'params' => []
]
];
$result = $this->Session->read('Flash.flash');
$this->assertEquals($expected, $result);

$this->Flash->error('It did not work', ['element' => 'error_thing']);

$expected = [
$expected[] = [
'message' => 'It did not work',
'key' => 'flash',
'element' => 'Flash/error',
Expand All @@ -181,7 +226,7 @@ public function testCall()

$this->Flash->success('It worked', ['plugin' => 'MyPlugin']);

$expected = [
$expected[] = [
'message' => 'It worked',
'key' => 'flash',
'element' => 'MyPlugin.Flash/success',
Expand All @@ -190,4 +235,37 @@ public function testCall()
$result = $this->Session->read('Flash.flash');
$this->assertEquals($expected, $result);
}

/**
* Test a magic call with the "clear" flag to true
*
* @return void
* @covers \Cake\Controller\Component\FlashComponent::set
*/
public function testCallWithClear()
{
$this->assertNull($this->Session->read('Flash.flash'));
$this->Flash->success('It worked');
$expected = [
[
'message' => 'It worked',
'key' => 'flash',
'element' => 'Flash/success',
'params' => []
]
];
$result = $this->Session->read('Flash.flash');
$this->assertEquals($expected, $result);
$this->Flash->success('It worked too', ['clear' => true]);
$expected = [
[
'message' => 'It worked too',
'key' => 'flash',
'element' => 'Flash/success',
'params' => []
]
];
$result = $this->Session->read('Flash.flash');
$this->assertEquals($expected, $result);
}
}
2 changes: 1 addition & 1 deletion tests/TestCase/TestSuite/IntegrationTestCaseTest.php
Expand Up @@ -118,7 +118,7 @@ public function testFlashSessionAndCookieAsserts()
{
$this->post('/posts/index');

$this->assertSession('An error message', 'Flash.flash.message');
$this->assertSession('An error message', 'Flash.flash.0.message');
$this->assertCookie(1, 'remember_me');
}

Expand Down
79 changes: 65 additions & 14 deletions tests/TestCase/View/Helper/FlashHelperTest.php
Expand Up @@ -46,25 +46,54 @@ public function setUp()
$session->write([
'Flash' => [
'flash' => [
'key' => 'flash',
'message' => 'This is a calling',
'element' => 'Flash/default',
'params' => []
[
'key' => 'flash',
'message' => 'This is a calling',
'element' => 'Flash/default',
'params' => []
]
],
'notification' => [
'key' => 'notification',
'message' => 'This is a test of the emergency broadcasting system',
'element' => 'flash_helper',
'params' => [
'title' => 'Notice!',
'name' => 'Alert!'
[
'key' => 'notification',
'message' => 'This is a test of the emergency broadcasting system',
'element' => 'flash_helper',
'params' => [
'title' => 'Notice!',
'name' => 'Alert!'
]
]
],
'classy' => [
'key' => 'classy',
'message' => 'Recorded',
'element' => 'flash_classy',
'params' => []
[
'key' => 'classy',
'message' => 'Recorded',
'element' => 'flash_classy',
'params' => []
]
],
'stack' => [
[
'key' => 'flash',
'message' => 'This is a calling',
'element' => 'Flash/default',
'params' => []
],
[
'key' => 'notification',
'message' => 'This is a test of the emergency broadcasting system',
'element' => 'flash_helper',
'params' => [
'title' => 'Notice!',
'name' => 'Alert!'
]
],
[
'key' => 'classy',
'message' => 'Recorded',
'element' => 'flash_classy',
'params' => []
]
]
]
]);
Expand Down Expand Up @@ -169,4 +198,26 @@ public function testFlashWithTheme()
$expected = 'flash element from TestTheme';
$this->assertContains($expected, $result);
}

/**
* Test that when rendering a stack, messages are displayed in their
* respective element, in the order they were added in the stack
*
* @return void
*/
public function testFlashWithStack()
{
$result = $this->Flash->render('stack');
$expected = [
['div' => ['class' => 'message']], 'This is a calling', '/div',
['div' => ['id' => 'notificationLayout']],
'<h1', 'Alert!', '/h1',
'<h3', 'Notice!', '/h3',
'<p', 'This is a test of the emergency broadcasting system', '/p',
'/div',
['div' => ['id' => 'classy-message']], 'Recorded', '/div'
];
$this->assertHtml($expected, $result);
$this->assertNull($this->View->request->session()->read('Flash.stack'));
}
}

0 comments on commit e73e974

Please sign in to comment.