├── views
└── elements
│ └── flash_message.html.php
├── config
└── bootstrap.php
├── .travis.yml
├── README.md
├── composer.json
├── extensions
├── helper
│ └── FlashMessage.php
└── storage
│ └── FlashMessage.php
└── tests
└── cases
└── extensions
└── storage
└── FlashMessageTest.php
/views/elements/flash_message.html.php:
--------------------------------------------------------------------------------
1 |
6 |
>
7 | =$message; ?>
8 |
--------------------------------------------------------------------------------
/config/bootstrap.php:
--------------------------------------------------------------------------------
1 | next($self, $params, $chain));
8 | });
9 |
10 | ?>
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.3
5 | - 5.4
6 |
7 | before_script:
8 | - mkdir ../libraries
9 | - git clone --branch=master --depth=100 --quiet git://github.com/UnionOfRAD/lithium.git ../libraries/lithium
10 |
11 | script: ../libraries/lithium/console/li3 test --filters=Profiler tests/cases
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flash Message Plugin for Lithium
2 |
3 | The Flash Message (`li3_flash_message`) plugin provides a straightforward interface for displaying status messages to the user.
4 |
5 |
6 | ## Goals
7 |
8 | - Use existing session storage
9 | - Eliminate message content from controllers
10 | - Easily localize messages
11 | - Use filters to integrate into existing workflow
12 |
13 |
14 | ## Integration
15 |
16 | ```
17 |
24 | ```
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uor/li3_flash_message",
3 | "description": "The Flash Message plugin for Lithium provides a straightforward interface for displaying status messages to the user.",
4 | "type": "lithium-library",
5 | "version": "dev-master",
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "The Lithium Community",
10 | "homepage": "http://github.com/uor/li3_flash_message/graphs/contributors"
11 | },
12 | {
13 | "name": "Michael Hüneburg",
14 | "email": "hello@michaelhue.com",
15 | "homepage": "http://michaelhue.com",
16 | "role": "Developer"
17 | }
18 | ],
19 | "require": {
20 | "composer/installers": "*"
21 | },
22 | "suggest": {
23 | "UnionOfRAD/lithium": "Lithium is required for this plugin."
24 | },
25 | "minimum-stability": "dev"
26 | }
27 |
--------------------------------------------------------------------------------
/extensions/helper/FlashMessage.php:
--------------------------------------------------------------------------------
1 | 'li3_flash_message\extensions\storage\FlashMessage'
27 | );
28 |
29 | /**
30 | * Outputs a flash message using a template. The message will be cleared afterwards.
31 | * With defaults settings it looks for the template
32 | * `app/views/elements/flash_message.html.php`. If it doesn't exist, the plugin's view
33 | * at `li3_flash_message/views/elements/flash_message.html.php` will be used. Use this
34 | * file as a starting point for your own flash message element. In order to use a
35 | * different template, adjust `$options['type']` and `$options['template']` to your needs.
36 | *
37 | * @param string [$key] Optional message key.
38 | * @param array [$options] Optional options.
39 | * - type: Template type that will be rendered.
40 | * - template: Name of the template that will be rendered.
41 | * - data: Additional data for the template.
42 | * - options: Additional options that will be passed to the renderer.
43 | * @return string Returns the rendered template.
44 | */
45 | public function show($key = 'flash_message', array $options = array()) {
46 | $defaults = array(
47 | 'type' => 'element',
48 | 'template' => 'flash_message',
49 | 'data' => array(),
50 | 'options' => array()
51 | );
52 | $options += $defaults;
53 |
54 | $storage = $this->_classes['storage'];
55 | $view = $this->_context->view();
56 | $type = array($options['type'] => $options['template']);
57 |
58 | if (!$flash = $storage::read($key)) {
59 | return;
60 | }
61 | $data = $options['data'] + array('message' => $flash['message']) + $flash['attrs'];
62 | $storage::clear($key);
63 |
64 | try {
65 | return $view->render($type, $data, $options['options']);
66 | } catch (TemplateException $e) {
67 | return $view->render($type, $data, array('library' => 'li3_flash_message'));
68 | }
69 | }
70 | }
71 |
72 | ?>
--------------------------------------------------------------------------------
/extensions/storage/FlashMessage.php:
--------------------------------------------------------------------------------
1 | redirect('Posts::index', array('message' => 'Post not found!'));
26 | * }
27 | *
28 | * // View
29 | * =$this->flashMessage->output(); ?>
30 | * }}}
31 | */
32 | class FlashMessage extends \lithium\core\StaticObject {
33 |
34 | /**
35 | * Class dependencies.
36 | *
37 | * @var array
38 | */
39 | protected static $_classes = array(
40 | 'session' => 'lithium\storage\Session'
41 | );
42 |
43 | /**
44 | * Configuration directives for writing, storing, and rendering flash messages.
45 | *
46 | * @var array
47 | */
48 | protected static $_session = array(
49 | 'config' => 'default',
50 | 'base' => null
51 | );
52 |
53 | /**
54 | * The library containing the `messages.php` config file.
55 | *
56 | * @var array
57 | */
58 | protected static $_library = true;
59 |
60 | /**
61 | * Stores message keys.
62 | *
63 | * @var array
64 | */
65 | protected static $_messages = null;
66 |
67 | /**
68 | * Used to set configuration parameters for `FlashMessage`.
69 | *
70 | * @see li3_flash_message\extensions\storage\FlashMessage::$_config
71 | * @param array $config Possible key settings:
72 | * - `'classes'` _array_: Sets class dependencies (i.e. `'session'`).
73 | * - `'session'` _array_: Configuration for accessing and manipulating session
74 | * data.
75 | * @return array If no parameters are passed, returns an associative array with the current
76 | * configuration, otherwise returns `null`.
77 | */
78 | public static function config(array $config = array()) {
79 | if (!$config) {
80 | return array('session' => static::$_session) + array('classes' => static::$_classes);
81 | }
82 |
83 | foreach ($config as $key => $val) {
84 | $key = "_{$key}";
85 | if (isset(static::${$key})) {
86 | static::${$key} = is_array($val) ? $val + static::${$key} : $val;
87 | }
88 | }
89 | }
90 |
91 | /**
92 | * Binds the messaging system to a controller to enable `'message'` option flags in various
93 | * controller methods, such as `render()` and `redirect()`.
94 | *
95 | * @param object $controller An instance of `lithium\action\Controller`.
96 | * @param array $options Options.
97 | * @return object Returns the passed `$controller` instance.
98 | */
99 | public static function bindTo($controller, array $options = array()) {
100 | if (!method_exists($controller, 'applyFilter')) {
101 | return $controller;
102 | }
103 |
104 | $controller->applyFilter('redirect', function($self, $params, $chain) use ($options) {
105 | $options =& $params['options'];
106 |
107 | if (isset($params['options']['message'])) {
108 | FlashMessage::write($params['options']['message']);
109 | unset($params['options']['message']);
110 | }
111 | return $chain->next($self, $params, $chain);
112 | });
113 |
114 | return $controller;
115 | }
116 |
117 | /**
118 | * Writes a flash message.
119 | *
120 | * @todo Add closure support to messages
121 | * @param mixed $message Message the message to be stored.
122 | * @param array $attrs Optional attributes that will be available in the view.
123 | * @param string $key Optional key to store multiple flash messages.
124 | * @return boolean True on successful write, false otherwise.
125 | */
126 | public static function write($message, array $attrs = array(), $key = 'flash_message') {
127 | $session = static::$_classes['session'];
128 | $key = static::_key($key);
129 | $name = static::$_session['config'];
130 |
131 | if (static::$_messages === null) {
132 | $path = Libraries::get(static::$_library, 'path') . '/config/messages.php';
133 | static::$_messages = file_exists($path) ? include $path : array();
134 | }
135 |
136 | $message = static::_translate($message, $attrs);
137 |
138 | return $session::write($key, compact('message', 'attrs'), compact('name'));
139 | }
140 |
141 | /**
142 | * Recursive message translation.
143 | *
144 | * @param mixed $message Message the message to be stored.
145 | * @param array $attrs Optional attributes that will be available in the view.
146 | * @return array
147 | */
148 | protected static function _translate($message, array $attrs) {
149 | if (is_string($message)) {
150 | if (isset(static::$_messages[$message])) {
151 | $message = static::$_messages[$message];
152 | }
153 | $message = String::insert($message, $attrs);
154 | } elseif (is_array($message)) {
155 | foreach ($message as $index => $value) {
156 | $message[$index] = static::_translate($value, $attrs);
157 | }
158 | }
159 | return $message;
160 | }
161 | /**
162 | * Reads a flash message.
163 | *
164 | * @param string [$key] Optional key.
165 | * @return array The stored flash message.
166 | */
167 | public static function read($key = 'flash_message') {
168 | $session = static::$_classes['session'];
169 | $key = static::_key($key);
170 | return $session::read($key, array('name' => static::$_session['config']));
171 | }
172 |
173 | /**
174 | * Delete a flash messages from the session.
175 | *
176 | * @return boolean
177 | */
178 | public static function clear($key = 'flash_message') {
179 | $session = static::$_classes['session'];
180 | $key = static::_key($key);
181 | return $session::delete($key, array('name' => static::$_session['config']));
182 | }
183 |
184 | /**
185 | * Reset the class.
186 | */
187 | public static function reset() {
188 | static::$_library = true;
189 | static::$_messages = null;
190 | static::$_classes = array(
191 | 'session' => 'lithium\storage\Session'
192 | );
193 | static::$_session = array(
194 | 'config' => 'default',
195 | 'base' => null
196 | );
197 | }
198 |
199 | /**
200 | * Helper for building the key
201 | *
202 | * @param string $key The key.
203 | * @return string The complete key.
204 | */
205 | protected static function _key($key) {
206 | $base = static::$_session['base'];
207 | return ($base ? "{$base}." : '') . $key;
208 | }
209 | }
210 |
211 | ?>
--------------------------------------------------------------------------------
/tests/cases/extensions/storage/FlashMessageTest.php:
--------------------------------------------------------------------------------
1 | array(
20 | 'adapter' => 'Memory'
21 | )
22 | ));
23 | }
24 |
25 | public function tearDown() {
26 | Session::delete('default');
27 | FlashMessage::reset();
28 | }
29 |
30 | public function testConfig() {
31 | $result = FlashMessage::config();
32 | $expected = array(
33 | 'session' => array('config' => 'default', 'base' => null),
34 | 'classes' => array('session' => 'lithium\storage\Session')
35 | );
36 | $this->assertEqual($expected, $result);
37 |
38 | FlashMessage::config(array('session' => array('base' => 'message')));
39 | $result = FlashMessage::config();
40 | $expected = array(
41 | 'session' => array('config' => 'default', 'base' => 'message'),
42 | 'classes' => array('session' => 'lithium\storage\Session')
43 | );
44 | $this->assertEqual($expected, $result);
45 | }
46 |
47 | public function testReset() {
48 | FlashMessage::config(array('session' => array('base' => 'message')));
49 | FlashMessage::reset();
50 | $result = FlashMessage::config();
51 | $expected = array(
52 | 'session' => array('config' => 'default', 'base' => null),
53 | 'classes' => array('session' => 'lithium\storage\Session')
54 | );
55 | $this->assertEqual($expected, $result);
56 | }
57 |
58 | public function testWrite() {
59 | FlashMessage::write('Foo');
60 | $expected = array('message' => 'Foo', 'attrs' => array());
61 | $result = Session::read('flash_message');
62 | $this->assertEqual($expected, $result);
63 |
64 | FlashMessage::write('Foo 2', array('type' => 'notice'));
65 | $expected = array('message' => 'Foo 2', 'attrs' => array('type' => 'notice'));
66 | $result = Session::read('flash_message');
67 | $this->assertEqual($expected, $result);
68 |
69 | FlashMessage::write('Foo 3', array(), 'TestKey');
70 | $expected = array('message' => 'Foo 3', 'attrs' => array());
71 | $result = Session::read('TestKey');
72 | $this->assertEqual($expected, $result);
73 | }
74 |
75 | public function testRead() {
76 | FlashMessage::write('Foo');
77 | $expected = array('message' => 'Foo', 'attrs' => array());
78 | $result = FlashMessage::read();
79 | $this->assertEqual($expected, $result);
80 |
81 | FlashMessage::write('Foo 2', array('type' => 'notice'));
82 | $expected = array('message' => 'Foo 2', 'attrs' => array('type' => 'notice'));
83 | $result = FlashMessage::read();
84 | $this->assertEqual($expected, $result);
85 |
86 | FlashMessage::write('Foo 3', array(), 'TestKey');
87 | $expected = array('message' => 'Foo 3', 'attrs' => array());
88 | $result = FlashMessage::read('TestKey');
89 | $this->assertEqual($expected, $result);
90 | }
91 |
92 | public function testClear() {
93 | FlashMessage::write('Foo');
94 | FlashMessage::clear();
95 | $result = FlashMessage::read();
96 | $this->assertNull($result);
97 |
98 | FlashMessage::write('Foo 2', array(), 'TestKey');
99 | FlashMessage::clear('TestKey');
100 | $result = FlashMessage::read('TestKey');
101 | $this->assertNull($result);
102 |
103 | FlashMessage::write('Foo 3', array(), 'TestKey2');
104 | FlashMessage::write('Foo 4', array(), 'TestKey3');
105 | FlashMessage::clear();
106 | $result = FlashMessage::read();
107 | $this->assertNull($result);
108 | }
109 |
110 | public function testWriteWithBase() {
111 | FlashMessage::config(array('session' => array('base' => 'message')));
112 | FlashMessage::write('Foo');
113 | $expected = array('message' => 'Foo', 'attrs' => array());
114 | $result = Session::read('message.flash_message');
115 | $this->assertEqual($expected, $result);
116 |
117 | FlashMessage::write('Foo 2', array('type' => 'notice'));
118 | $expected = array('message' => 'Foo 2', 'attrs' => array('type' => 'notice'));
119 | $result = Session::read('message.flash_message');
120 | $this->assertEqual($expected, $result);
121 |
122 | FlashMessage::write('Foo 3', array(), 'TestKey');
123 | $expected = array('message' => 'Foo 3', 'attrs' => array());
124 | $result = Session::read('message.TestKey');
125 | $this->assertEqual($expected, $result);
126 | }
127 |
128 | public function testReadWithBase() {
129 | FlashMessage::config(array('session' => array('base' => 'message')));
130 | FlashMessage::write('Foo');
131 | $expected = array('message' => 'Foo', 'attrs' => array());
132 | $result = FlashMessage::read();
133 | $this->assertEqual($expected, $result);
134 |
135 | FlashMessage::write('Foo 2', array('type' => 'notice'));
136 | $expected = array('message' => 'Foo 2', 'attrs' => array('type' => 'notice'));
137 | $result = FlashMessage::read();
138 | $this->assertEqual($expected, $result);
139 |
140 | FlashMessage::write('Foo 3', array(), 'TestKey');
141 | $expected = array('message' => 'Foo 3', 'attrs' => array());
142 | $result = FlashMessage::read('TestKey');
143 | $this->assertEqual($expected, $result);
144 | }
145 |
146 | public function testClearWithBase() {
147 | FlashMessage::config(array('session' => array('base' => 'message')));
148 | FlashMessage::write('Foo');
149 | FlashMessage::clear();
150 | $result = FlashMessage::read('flash_message');
151 | $this->assertNull($result);
152 |
153 | FlashMessage::write('Foo 2', array(), 'TestKey');
154 | FlashMessage::clear('TestKey');
155 | $result = FlashMessage::read('TestKey');
156 | $this->assertNull($result);
157 |
158 | FlashMessage::write('Foo 3', array(), 'TestKey2');
159 | FlashMessage::write('Foo 4', array(), 'TestKey3');
160 | FlashMessage::clear();
161 | $result = FlashMessage::read();
162 | $this->assertNull($result);
163 | }
164 |
165 | public function testMessageWithParameters() {
166 | FlashMessage::write('{:name}: the most rad php framework', array('name' => 'Lithium'));
167 | $result = FlashMessage::read('flash_message');
168 | $expected = array(
169 | 'message' => 'Lithium: the most rad php framework',
170 | 'attrs' => array('name' => 'Lithium')
171 | );
172 | $this->assertEqual($expected, $result);
173 | }
174 |
175 | public function testArrayOfStringAsMessage() {
176 | $messages = array(
177 | 'Name can\'t be empty.',
178 | 'Email required',
179 | 'Phone is invalid.'
180 | );
181 | FlashMessage::write($messages);
182 |
183 | $expected = array(
184 | 'message' => $messages,
185 | 'attrs' => array()
186 | );
187 | $result = FlashMessage::read('flash_message');
188 | $this->assertEqual($expected, $result);
189 | }
190 |
191 | public function testNestedArrayAsMessage() {
192 | $messages = array(
193 | 'name' => array(
194 | 'Name is required.'
195 | ),
196 | 'email' => array(
197 | 'Email can\'t be empty.',
198 | 'Email is invalid.'
199 | ),
200 | 'phone' => array(
201 | 'Invalid phone number.'
202 | )
203 | );
204 | FlashMessage::write($messages);
205 |
206 | $expected = array(
207 | 'message' => $messages,
208 | 'attrs' => array()
209 | );
210 | $result = FlashMessage::read('flash_message');
211 | $this->assertEqual($expected, $result);
212 | }
213 |
214 | public function testMessageTranslation() {
215 | $testApp = Libraries::get(true, 'resources') . '/tmp/tests/test_app';
216 | mkdir($testApp . '/config', 0777, true);
217 |
218 | $body = << 'Hello World.',
222 | 'advice' => 'Whatever advice you give, be short.',
223 | 'error' => 'To err is human, but for a real disaster you need a computer.'
224 | );
225 | ?>
226 | EOD;
227 | $filepath = $testApp . '/config/messages.php';
228 | file_put_contents($filepath, $body);
229 |
230 | Libraries::add('test_app', array('path' => $testApp));
231 |
232 | FlashMessage::config(array('library' => 'test_app'));
233 |
234 | $messages = array('hello', 'advice', 'error');
235 | FlashMessage::write($messages);
236 |
237 | $expected = array(
238 | 'message' => array(
239 | 'Hello World.',
240 | 'Whatever advice you give, be short.',
241 | 'To err is human, but for a real disaster you need a computer.'
242 | ),
243 | 'attrs' => array()
244 | );
245 | $result = FlashMessage::read('flash_message');
246 | $this->assertEqual($expected, $result);
247 |
248 | $message = 'hello';
249 | FlashMessage::write($message);
250 |
251 | $expected = array(
252 | 'message' => 'Hello World.',
253 | 'attrs' => array()
254 | );
255 | $result = FlashMessage::read('flash_message');
256 | $this->assertEqual($expected, $result);
257 |
258 | $this->_cleanUp();
259 | }
260 | }
261 |
262 | ?>
--------------------------------------------------------------------------------