Browse Source

Add FlashComponent

euromark 11 years ago
parent
commit
a89dc30e0c

+ 2 - 0
Controller/Component/CommonComponent.php

@@ -145,6 +145,7 @@ class CommonComponent extends Component {
 	 * @param string $message Message to output.
 	 * @param string $type Type ('error', 'warning', 'success', 'info' or custom class).
 	 * @return void
+	 * @deprecated Use FlashComponent::message() instead.
 	 */
 	public function flashMessage($message, $type = null) {
 		if (!$type) {
@@ -167,6 +168,7 @@ class CommonComponent extends Component {
 	 * @param string $message Message to output.
 	 * @param string $type Type ('error', 'warning', 'success', 'info' or custom class).
 	 * @return void
+	 * @deprecated Use FlashComponent::transientMessage() instead.
 	 */
 	public static function transientFlashMessage($message, $type = null) {
 		if (!$type) {

+ 103 - 0
Controller/Component/FlashComponent.php

@@ -0,0 +1,103 @@
+<?php
+
+App::uses('Component', 'Controller');
+App::uses('Sanitize', 'Utility');
+App::uses('Utility', 'Tools.Utility');
+
+/**
+ * A flash component to enhance flash message support with stackable messages, both
+ * persistent and transient.
+ *
+ * @author Mark Scherer
+ * @copyright 2012 Mark Scherer
+ * @license MIT
+ */
+class FlashComponent extends Component {
+
+	public $components = array('Session');
+
+	public $userModel = CLASS_USER;
+
+	/**
+	 * For automatic startup
+	 * for this helper the controller has to be passed as reference
+	 *
+	 * @return void
+	 */
+	public function initialize(Controller $Controller) {
+		parent::initialize($Controller);
+
+		$this->Controller = $Controller;
+	}
+
+	/**
+	 * Called after the Controller::beforeRender(), after the view class is loaded, and before the
+	 * Controller::render()
+	 *
+	 * @param object $Controller Controller with components to beforeRender
+	 * @return void
+	 */
+	public function beforeRender(Controller $Controller) {
+		if (Configure::read('Common.messages') !== false && $messages = $this->Session->read('Message')) {
+			foreach ($messages as $message) {
+				$this->flashMessage($message['message'], 'error');
+			}
+			$this->Session->delete('Message');
+		}
+
+		if ($this->Controller->request->is('ajax')) {
+			$ajaxMessages = array_merge(
+				(array)$this->Session->read('messages'),
+				(array)Configure::read('messages')
+			);
+			// The header can be read with JavaScript and a custom Message can be displayed
+			$this->Controller->response->header('X-Ajax-Flashmessage', json_encode($ajaxMessages));
+
+			$this->Session->delete('messages');
+		}
+	}
+
+	/**
+	 * Adds a flash message.
+	 * Updates "messages" session content (to enable multiple messages of one type).
+	 *
+	 * @param string $message Message to output.
+	 * @param string $type Type ('error', 'warning', 'success', 'info' or custom class).
+	 * @return void
+	 */
+	public function message($message, $type = null) {
+		if (!$type) {
+			$type = 'info';
+		}
+
+		$old = (array)$this->Session->read('messages');
+		if (isset($old[$type]) && count($old[$type]) > 99) {
+			array_shift($old[$type]);
+		}
+		$old[$type][] = $message;
+		$this->Session->write('messages', $old);
+	}
+
+	/**
+	 * Adds a transient flash message.
+	 * These flash messages that are not saved (only available for current view),
+	 * will be merged into the session flash ones prior to output.
+	 *
+	 * @param string $message Message to output.
+	 * @param string $type Type ('error', 'warning', 'success', 'info' or custom class).
+	 * @return void
+	 */
+	public static function transientMessage($message, $type = null) {
+		if (!$type) {
+			$type = 'info';
+		}
+
+		$old = (array)Configure::read('messages');
+		if (isset($old[$type]) && count($old[$type]) > 99) {
+			array_shift($old[$type]);
+		}
+		$old[$type][] = $message;
+		Configure::write('messages', $old);
+	}
+
+}

+ 84 - 0
Test/Case/Controller/Component/FlashComponentTest.php

@@ -0,0 +1,84 @@
+<?php
+
+App::uses('FlashComponent', 'Tools.Controller/Component');
+App::uses('Component', 'Controller');
+App::uses('CakeSession', 'Model/Datasource');
+App::uses('Controller', 'Controller');
+App::uses('AppModel', 'Model');
+
+/**
+ */
+class FlashComponentTest extends CakeTestCase {
+
+	public $fixtures = array('core.cake_session');
+
+	public function setUp() {
+		parent::setUp();
+
+		// BUGFIX for CakePHP2.5 - One has to write to the session before deleting actually works
+		CakeSession::write('Auth', '');
+		CakeSession::delete('Auth');
+
+		$this->Controller = new FlashComponentTestController(new CakeRequest, new CakeResponse);
+		$this->Controller->constructClasses();
+		$this->Controller->startupProcess();
+	}
+
+	public function tearDown() {
+		parent::tearDown();
+
+		unset($this->Controller);
+	}
+
+	/**
+	 * FlashComponentTest::testTransientFlashMessage()
+	 *
+	 * @return void
+	 */
+	public function testTransientMessage() {
+		$is = $this->Controller->Flash->transientMessage('xyz', 'success');
+		//$this->assertTrue($is);
+
+		$res = Configure::read('messages');
+		//debug($res);
+		$this->assertTrue(!empty($res));
+		$this->assertTrue(isset($res['success'][0]) && $res['success'][0] === 'xyz');
+	}
+
+	/**
+	 * FlashComponentTest::testFlashMessage()
+	 *
+	 * @return void
+	 */
+	public function testFlashMessage() {
+		$this->Controller->Session->delete('messages');
+		$is = $this->Controller->Flash->message('efg');
+
+		$res = $this->Controller->Session->read('messages');
+		$this->assertTrue(!empty($res));
+		$this->assertTrue(isset($res['info'][0]) && $res['info'][0] === 'efg');
+	}
+
+}
+
+// Use Controller instead of AppController to avoid conflicts
+class FlashComponentTestController extends Controller {
+
+	public $components = array('Session', 'Tools.Flash');
+
+	public $failed = false;
+
+	public $testHeaders = array();
+
+	public function fail() {
+		$this->failed = true;
+	}
+
+	public function redirect($url, $status = null, $exit = true) {
+		return $status;
+	}
+
+	public function header($status) {
+		$this->testHeaders[] = $status;
+	}
+}