├── tests ├── bootstrap.php └── MessagesTest.php ├── .gitignore ├── CONTRIBUTING.md ├── phpunit.xml.dist ├── LICENSE.md ├── .github └── workflows │ └── tests.yml ├── composer.json ├── README.md └── src └── Messages.php /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | tests 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | src 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2015 Josh Lockhart 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | tests: 7 | name: Tests PHP ${{ matrix.php }} 8 | runs-on: ubuntu-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | php: [ 8.1, 8.2, 8.3, 8.4, 8.5 ] 13 | include: 14 | - php: 8.4 15 | analysis: true 16 | 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | 21 | - name: Set up PHP ${{ matrix.php }} 22 | uses: shivammathur/setup-php@v2 23 | with: 24 | php-version: ${{ matrix.php }} 25 | coverage: xdebug 26 | 27 | - name: Install dependencies 28 | run: composer install --prefer-dist --no-progress --no-suggest 29 | 30 | - name: Tests 31 | run: composer test:coverage 32 | 33 | - name: Upload coverage results to Coveralls 34 | if: matrix.analysis 35 | env: 36 | COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | run: | 38 | composer require php-coveralls/php-coveralls -n -W 39 | vendor/bin/php-coveralls --coverage_clover=build/coverage/clover.xml -o build/coverage/coveralls.json -v 40 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slim/flash", 3 | "type": "library", 4 | "description": "Slim Framework Flash message service provider", 5 | "keywords": ["slim","framework","provider","flash","message"], 6 | "homepage": "http://slimframework.com", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Josh Lockhart", 11 | "email": "hello@joshlockhart.com", 12 | "homepage": "http://joshlockhart.com" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=5.5.0" 17 | }, 18 | "require-dev": { 19 | "phpunit/phpunit": "^10.0" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "Slim\\Flash\\": "src" 24 | } 25 | }, 26 | "autoload-dev": { 27 | "psr-4": { 28 | "Slim\\Flash\\Tests\\": "tests" 29 | } 30 | }, 31 | "scripts": { 32 | "check": [ 33 | "@test:coverage" 34 | ], 35 | "test": "phpunit --do-not-cache-result --colors=always", 36 | "test:coverage": [ 37 | "@putenv XDEBUG_MODE=coverage", 38 | "phpunit --do-not-cache-result --colors=always --coverage-clover build/coverage/clover.xml --coverage-html build/coverage --coverage-text" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Slim Framework Flash Messages 2 | 3 | [![Build Status](https://travis-ci.org/slimphp/Slim-Flash.svg?branch=master)](https://travis-ci.org/slimphp/Slim-Flash) 4 | 5 | This repository contains a Slim Framework Flash messages service provider. This enables you to define transient messages that persist only from the current request to the next request. 6 | 7 | ## Install 8 | 9 | Via Composer 10 | 11 | ``` bash 12 | $ composer require slim/flash 13 | ``` 14 | 15 | Requires Slim 3.0.0 or newer. 16 | 17 | ## Usage 18 | 19 | ### Slim 4 20 | 21 | This example assumes that you have `php-di/php-di` installed. 22 | 23 | ```php 24 | addDefinitions( 37 | [ 38 | 'flash' => function () { 39 | $storage = []; 40 | return new Messages($storage); 41 | } 42 | ] 43 | ); 44 | 45 | AppFactory::setContainer($containerBuilder->build()); 46 | 47 | $app = AppFactory::create(); 48 | 49 | // Add session start middleware 50 | $app->add( 51 | function ($request, $next) { 52 | // Start PHP session 53 | if (session_status() !== PHP_SESSION_ACTIVE) { 54 | session_start(); 55 | } 56 | 57 | // Change flash message storage 58 | $this->get('flash')->__construct($_SESSION); 59 | 60 | return $next->handle($request); 61 | } 62 | ); 63 | 64 | $app->addErrorMiddleware(true, true, true); 65 | 66 | // Add routes 67 | $app->get( 68 | '/', 69 | function ($request, $response) { 70 | // Set flash message for next request 71 | $this->get('flash')->addMessage('Test', 'This is a message'); 72 | 73 | // Redirect 74 | $url = RouteContext::fromRequest($request)->getRouteParser()->urlFor('bar'); 75 | 76 | return $response->withStatus(302)->withHeader('Location', $url); 77 | } 78 | ); 79 | 80 | $app->get( 81 | '/bar', 82 | function ($request, $response) { 83 | $flash = $this->get('flash'); 84 | 85 | // Get flash messages from previous request 86 | $messages = $flash->getMessages(); 87 | print_r($messages); 88 | 89 | // Get the first message from a specific key 90 | $test = $flash->getFirstMessage('Test'); 91 | print_r($test); 92 | 93 | return $response; 94 | } 95 | )->setName('bar'); 96 | 97 | $app->run(); 98 | ``` 99 | 100 | ### Slim 3 101 | 102 | ```php 103 | // Start PHP session 104 | session_start(); 105 | 106 | $app = new \Slim\App(); 107 | 108 | // Fetch DI Container 109 | $container = $app->getContainer(); 110 | 111 | // Register provider 112 | $container['flash'] = function () { 113 | return new \Slim\Flash\Messages(); 114 | }; 115 | 116 | $app->get('/foo', function ($req, $res, $args) { 117 | // Set flash message for next request 118 | $this->flash->addMessage('Test', 'This is a message'); 119 | 120 | // Redirect 121 | return $res->withStatus(302)->withHeader('Location', '/bar'); 122 | }); 123 | 124 | $app->get('/bar', function ($req, $res, $args) { 125 | // Get flash messages from previous request 126 | $messages = $this->flash->getMessages(); 127 | print_r($messages); 128 | 129 | // Get the first message from a specific key 130 | $test = $this->flash->getFirstMessage('Test'); 131 | print_r($test); 132 | }); 133 | 134 | $app->run(); 135 | ``` 136 | 137 | > Please note that a message could be a string, object or array. Please check what your storage can handle. 138 | 139 | ### Using with Twig-View 140 | 141 | If you use [Twig-View](https://github.com/slimphp/Twig-View), then [slim-twig-flash](https://github.com/kanellov/slim-twig-flash) may be a useful integration package. 142 | 143 | 144 | ## Testing 145 | 146 | ``` bash 147 | $ phpunit 148 | ``` 149 | 150 | ## Contributing 151 | 152 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 153 | 154 | ## Security 155 | 156 | If you discover any security related issues, please email security@slimframework.com instead of using the issue tracker. 157 | 158 | ## Credits 159 | 160 | - [Josh Lockhart](https://github.com/codeguy) 161 | - [All Contributors](../../contributors) 162 | 163 | ## License 164 | 165 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 166 | -------------------------------------------------------------------------------- /src/Messages.php: -------------------------------------------------------------------------------- 1 | storageKey = $storageKey; 59 | } 60 | 61 | // Set storage 62 | if (is_array($storage) || $storage instanceof ArrayAccess) { 63 | $this->storage = &$storage; 64 | } elseif (is_null($storage)) { 65 | if (!isset($_SESSION)) { 66 | throw new RuntimeException('Flash messages middleware failed. Session not found.'); 67 | } 68 | $this->storage = &$_SESSION; 69 | } else { 70 | throw new InvalidArgumentException('Flash messages storage must be an array or implement \ArrayAccess'); 71 | } 72 | 73 | // Load messages from previous request 74 | if (isset($this->storage[$this->storageKey]) && is_array($this->storage[$this->storageKey])) { 75 | $this->fromPrevious = $this->storage[$this->storageKey]; 76 | } 77 | $this->storage[$this->storageKey] = []; 78 | } 79 | 80 | /** 81 | * Add flash message for the next request 82 | * 83 | * @param string $key The key to store the message under 84 | * @param mixed $message Message to show on next request 85 | */ 86 | public function addMessage($key, $message) 87 | { 88 | // Create Array for this key 89 | if (!isset($this->storage[$this->storageKey][$key])) { 90 | $this->storage[$this->storageKey][$key] = []; 91 | } 92 | 93 | // Push onto the array 94 | $this->storage[$this->storageKey][$key][] = $message; 95 | } 96 | 97 | /** 98 | * Add flash message for current request 99 | * 100 | * @param string $key The key to store the message under 101 | * @param mixed $message Message to show for the current request 102 | */ 103 | public function addMessageNow($key, $message) 104 | { 105 | // Create Array for this key 106 | if (!isset($this->forNow[$key])) { 107 | $this->forNow[$key] = []; 108 | } 109 | 110 | // Push onto the array 111 | $this->forNow[$key][] = $message; 112 | } 113 | 114 | /** 115 | * Get flash messages 116 | * 117 | * @return array Messages to show for current request 118 | */ 119 | public function getMessages() 120 | { 121 | $messages = $this->fromPrevious; 122 | 123 | foreach ($this->forNow as $key => $values) { 124 | if (!isset($messages[$key])) { 125 | $messages[$key] = []; 126 | } 127 | 128 | foreach ($values as $value) { 129 | array_push($messages[$key], $value); 130 | } 131 | } 132 | 133 | return $messages; 134 | } 135 | 136 | /** 137 | * Get Flash Message 138 | * 139 | * @param string $key The key to get the message from 140 | * @return mixed|null Returns the message 141 | */ 142 | public function getMessage($key) 143 | { 144 | $messages = $this->getMessages(); 145 | 146 | // If the key exists then return all messages or null 147 | return (isset($messages[$key])) ? $messages[$key] : null; 148 | } 149 | 150 | /** 151 | * Get the first Flash message 152 | * 153 | * @param string $key The key to get the message from 154 | * @param string $default Default value if key doesn't exist 155 | * @return mixed Returns the message 156 | */ 157 | public function getFirstMessage($key, $default = null) 158 | { 159 | $messages = self::getMessage($key); 160 | if (is_array($messages) && count($messages) > 0) { 161 | return $messages[0]; 162 | } 163 | 164 | return $default; 165 | } 166 | 167 | /** 168 | * Has Flash Message 169 | * 170 | * @param string $key The key to get the message from 171 | * @return bool Whether the message is set or not 172 | */ 173 | public function hasMessage($key) 174 | { 175 | $messages = $this->getMessages(); 176 | return isset($messages[$key]); 177 | } 178 | 179 | /** 180 | * Clear all messages 181 | * 182 | * @return void 183 | */ 184 | public function clearMessages() 185 | { 186 | if (isset($this->storage[$this->storageKey])) { 187 | $this->storage[$this->storageKey] = []; 188 | } 189 | 190 | $this->fromPrevious = []; 191 | $this->forNow = []; 192 | } 193 | 194 | /** 195 | * Clear specific message 196 | * 197 | * @param String $key The key to clear 198 | * @return void 199 | */ 200 | public function clearMessage($key) 201 | { 202 | if (isset($this->storage[$this->storageKey][$key])) { 203 | unset($this->storage[$this->storageKey][$key]); 204 | } 205 | 206 | if (isset($this->fromPrevious[$key])) { 207 | unset($this->fromPrevious[$key]); 208 | } 209 | 210 | if (isset($this->forNow[$key])) { 211 | unset($this->forNow[$key]); 212 | } 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /tests/MessagesTest.php: -------------------------------------------------------------------------------- 1 | ['Test']]; 15 | $flash = new Messages($storage); 16 | 17 | $this->assertEquals(['Test'], $flash->getMessages()); 18 | } 19 | 20 | // Test a string can be added to a message array for the current request 21 | public function testAddMessageFromAnIntegerForCurrentRequest() 22 | { 23 | $storage = ['slimFlash' => []]; 24 | $flash = new Messages($storage); 25 | 26 | $flash->addMessageNow('key', 46); 27 | $flash->addMessageNow('key', 48); 28 | 29 | $messages = $flash->getMessages(); 30 | $this->assertEquals(['46','48'], $messages['key']); 31 | 32 | $this->assertArrayHasKey('slimFlash', $storage); 33 | $this->assertEmpty($storage['slimFlash']); 34 | } 35 | 36 | // Test a string can be added to a message array for the current request 37 | public function testAddMessageFromStringForCurrentRequest() 38 | { 39 | $storage = ['slimFlash' => []]; 40 | $flash = new Messages($storage); 41 | 42 | $flash->addMessageNow('key', 'value'); 43 | 44 | $messages = $flash->getMessages(); 45 | $this->assertEquals(['value'], $messages['key']); 46 | 47 | $this->assertArrayHasKey('slimFlash', $storage); 48 | $this->assertEmpty($storage['slimFlash']); 49 | } 50 | 51 | // Test an array can be added to a message array for the current request 52 | public function testAddMessageFromArrayForCurrentRequest() 53 | { 54 | $storage = ['slimFlash' => []]; 55 | $flash = new Messages($storage); 56 | 57 | $formData = [ 58 | 'username' => 'Scooby Doo', 59 | 'emailAddress' => 'scooby@mysteryinc.org', 60 | ]; 61 | 62 | $flash->addMessageNow('old', $formData); 63 | 64 | $messages = $flash->getMessages(); 65 | $this->assertEquals($formData, $messages['old'][0]); 66 | 67 | $this->assertArrayHasKey('slimFlash', $storage); 68 | $this->assertEmpty($storage['slimFlash']); 69 | } 70 | 71 | // Test an object can be added to a message array for the current request 72 | public function testAddMessageFromObjectForCurrentRequest() 73 | { 74 | $storage = ['slimFlash' => []]; 75 | $flash = new Messages($storage); 76 | 77 | $user = new \stdClass(); 78 | $user->name = 'Scooby Doo'; 79 | $user->emailAddress = 'scooby@mysteryinc.org'; 80 | 81 | $flash->addMessageNow('user', $user); 82 | 83 | $messages = $flash->getMessages(); 84 | $this->assertInstanceOf(\stdClass::class, $messages['user'][0]); 85 | 86 | $this->assertArrayHasKey('slimFlash', $storage); 87 | $this->assertEmpty($storage['slimFlash']); 88 | } 89 | 90 | // Test a string can be added to a message array for the next request 91 | public function testAddMessageFromAnIntegerForNextRequest() 92 | { 93 | $storage = ['slimFlash' => []]; 94 | $flash = new Messages($storage); 95 | 96 | $flash->addMessage('key', 46); 97 | $flash->addMessage('key', 48); 98 | 99 | $this->assertArrayHasKey('slimFlash', $storage); 100 | $this->assertEquals(['46', '48'], $storage['slimFlash']['key']); 101 | } 102 | 103 | // Test a string can be added to a message array for the next request 104 | public function testAddMessageFromStringForNextRequest() 105 | { 106 | $storage = ['slimFlash' => []]; 107 | $flash = new Messages($storage); 108 | 109 | $flash->addMessage('key', 'value'); 110 | 111 | $this->assertArrayHasKey('slimFlash', $storage); 112 | $this->assertEquals(['value'], $storage['slimFlash']['key']); 113 | } 114 | 115 | // Test an array can be added to a message array for the next request 116 | public function testAddMessageFromArrayForNextRequest() 117 | { 118 | $storage = ['slimFlash' => []]; 119 | $flash = new Messages($storage); 120 | 121 | $formData = [ 122 | 'username' => 'Scooby Doo', 123 | 'emailAddress' => 'scooby@mysteryinc.org', 124 | ]; 125 | 126 | $flash->addMessage('old', $formData); 127 | 128 | $this->assertArrayHasKey('slimFlash', $storage); 129 | $this->assertEquals($formData, $storage['slimFlash']['old'][0]); 130 | } 131 | 132 | // Test an object can be added to a message array for the next request 133 | public function testAddMessageFromObjectForNextRequest() 134 | { 135 | $storage = ['slimFlash' => []]; 136 | $flash = new Messages($storage); 137 | 138 | $user = new \stdClass(); 139 | $user->name = 'Scooby Doo'; 140 | $user->emailAddress = 'scooby@mysteryinc.org'; 141 | 142 | $flash->addMessage('user', $user); 143 | 144 | $this->assertArrayHasKey('slimFlash', $storage); 145 | $this->assertInstanceOf(\stdClass::class, $storage['slimFlash']['user'][0]); 146 | } 147 | 148 | // Test get empty messages from previous request 149 | public function testGetEmptyMessagesFromPrevRequest() 150 | { 151 | $storage = []; 152 | $flash = new Messages($storage); 153 | 154 | $this->assertEquals([], $flash->getMessages()); 155 | } 156 | 157 | // Test set messages for current request 158 | public function testSetMessagesForCurrentRequest() 159 | { 160 | $storage = ['slimFlash' => [ 'error' => ['An error']]]; 161 | 162 | $flash = new Messages($storage); 163 | $flash->addMessageNow('error', 'Another error'); 164 | $flash->addMessageNow('success', 'A success'); 165 | $flash->addMessageNow('info', 'An info'); 166 | 167 | $messages = $flash->getMessages(); 168 | $this->assertEquals(['An error', 'Another error'], $messages['error']); 169 | $this->assertEquals(['A success'], $messages['success']); 170 | $this->assertEquals(['An info'], $messages['info']); 171 | 172 | $this->assertArrayHasKey('slimFlash', $storage); 173 | $this->assertEmpty($storage['slimFlash']); 174 | } 175 | 176 | // Test set messages for next request 177 | public function testSetMessagesForNextRequest() 178 | { 179 | $storage = []; 180 | 181 | $flash = new Messages($storage); 182 | $flash->addMessage('Test', 'Test'); 183 | $flash->addMessage('Test', 'Test2'); 184 | 185 | $this->assertArrayHasKey('slimFlash', $storage); 186 | $this->assertEquals(['Test', 'Test2'], $storage['slimFlash']['Test']); 187 | } 188 | 189 | //Test getting the message from the key 190 | public function testGetMessageFromKey() 191 | { 192 | $storage = ['slimFlash' => [ 'Test' => ['Test', 'Test2']]]; 193 | $flash = new Messages($storage); 194 | 195 | $this->assertEquals(['Test', 'Test2'], $flash->getMessage('Test')); 196 | } 197 | 198 | //Test getting the first message from the key 199 | public function testGetFirstMessageFromKey() 200 | { 201 | $storage = ['slimFlash' => [ 'Test' => ['Test', 'Test2']]]; 202 | $flash = new Messages($storage); 203 | 204 | $this->assertEquals('Test', $flash->getFirstMessage('Test')); 205 | } 206 | 207 | //Test getting the default message if the key doesn't exist 208 | public function testDefaultFromGetFirstMessageFromKeyIfKeyDoesntExist() 209 | { 210 | $storage = ['slimFlash' => []]; 211 | $flash = new Messages($storage); 212 | 213 | $this->assertEquals('This', $flash->getFirstMessage('Test', 'This')); 214 | } 215 | 216 | //Test getting the message from the key 217 | public function testGetMessageFromKeyIncludingCurrent() 218 | { 219 | $storage = ['slimFlash' => [ 'Test' => ['Test', 'Test2']]]; 220 | $flash = new Messages($storage); 221 | $flash->addMessageNow('Test', 'Test3'); 222 | 223 | $messages = $flash->getMessages(); 224 | 225 | $this->assertEquals(['Test', 'Test2','Test3'], $flash->getMessage('Test')); 226 | } 227 | 228 | public function testHasMessage() 229 | { 230 | $storage = ['slimFlash' => []]; 231 | $flash = new Messages($storage); 232 | $this->assertFalse($flash->hasMessage('Test')); 233 | 234 | $storage = ['slimFlash' => [ 'Test' => ['Test']]]; 235 | $flash = new Messages($storage); 236 | $this->assertTrue($flash->hasMessage('Test')); 237 | } 238 | 239 | public function testClearMessages() 240 | { 241 | $storage = ['slimFlash' => []]; 242 | $flash = new Messages($storage); 243 | 244 | $storage = ['slimFlash' => [ 'Test' => ['Test']]]; 245 | $flash = new Messages($storage); 246 | $flash->addMessageNow('Now', 'hear this'); 247 | $this->assertTrue($flash->hasMessage('Test')); 248 | $this->assertTrue($flash->hasMessage('Now')); 249 | 250 | $flash->clearMessages(); 251 | $this->assertFalse($flash->hasMessage('Test')); 252 | $this->assertFalse($flash->hasMessage('Now')); 253 | } 254 | 255 | public function testClearMessage() 256 | { 257 | $storage = ['slimFlash' => []]; 258 | $flash = new Messages($storage); 259 | 260 | $storage = ['slimFlash' => [ 'Test' => ['Test'], 'Foo' => ['Bar']]]; 261 | $flash = new Messages($storage); 262 | $flash->addMessageNow('Now', 'hear this'); 263 | $this->assertTrue($flash->hasMessage('Test')); 264 | $this->assertTrue($flash->hasMessage('Foo')); 265 | $this->assertTrue($flash->hasMessage('Now')); 266 | 267 | $flash->clearMessage('Test'); 268 | $flash->clearMessage('Now'); 269 | $this->assertFalse($flash->hasMessage('Test')); 270 | $this->assertFalse($flash->hasMessage('Now')); 271 | $this->assertTrue($flash->hasMessage('Foo')); 272 | } 273 | 274 | public function testSettingCustomStorageKey() 275 | { 276 | $storage = ['some-key' => [ 'Test' => ['Test']]]; 277 | $flash = new Messages($storage); 278 | $this->assertFalse($flash->hasMessage('Test')); 279 | 280 | $flash = new Messages($storage, 'some-key'); 281 | $this->assertTrue($flash->hasMessage('Test')); 282 | } 283 | } 284 | --------------------------------------------------------------------------------