Browse Source

Add session component for BC, add Language

euromark 11 years ago
parent
commit
ca55b2f792

+ 10 - 10
src/Controller/Component/CommonComponent.php

@@ -21,7 +21,7 @@ if (!defined('CLASS_USER')) {
  */
 class CommonComponent extends Component {
 
-	public $components = array('Session', 'RequestHandler');
+	public $components = array('RequestHandler');
 
 	public $userModel = CLASS_USER;
 
@@ -36,13 +36,13 @@ class CommonComponent extends Component {
 
 		// Data preparation
 		if (!empty($this->Controller->request->data) && !Configure::read('DataPreparation.notrim')) {
-			$this->Controller->request->data = $this->trimDeep($this->Controller->request->data);
+			$this->Controller->request->data = Utility::trimDeep($this->Controller->request->data);
 		}
 		if (!empty($this->Controller->request->query) && !Configure::read('DataPreparation.notrim')) {
-			$this->Controller->request->query = $this->trimDeep($this->Controller->request->query);
+			$this->Controller->request->query = Utility::trimDeep($this->Controller->request->query);
 		}
 		if (!empty($this->Controller->request->params['pass']) && !Configure::read('DataPreparation.notrim')) {
-			$this->Controller->request->params['pass'] = $this->trimDeep($this->Controller->request->params['pass']);
+			$this->Controller->request->params['pass'] = Utility::trimDeep($this->Controller->request->params['pass']);
 		}
 		/*
 		// Auto layout switch
@@ -60,22 +60,22 @@ class CommonComponent extends Component {
 	 * @return void
 	 */
 	public function beforeRender(Event $event) {
-		if ($messages = $this->Session->read('Message')) {
+		if ($messages = $this->Controller->request->session()->read('Message')) {
 			foreach ($messages as $message) {
 				$this->flashMessage($message['message'], 'error');
 			}
-			$this->Session->delete('Message');
+			$this->Controller->request->session()->delete('Message');
 		}
 
 		if ($this->Controller->request->is('ajax')) {
 			$ajaxMessages = array_merge(
-				(array)$this->Session->read('messages'),
+				(array)$this->Controller->request->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');
+			$this->Controller->request->session()->delete('messages');
 		}
 
 		// Custom options
@@ -127,12 +127,12 @@ class CommonComponent extends Component {
 			$type = 'info';
 		}
 
-		$old = (array)$this->Session->read('messages');
+		$old = (array)$this->Controller->request->session()->read('messages');
 		if (isset($old[$type]) && count($old[$type]) > 99) {
 			array_shift($old[$type]);
 		}
 		$old[$type][] = $message;
-		$this->Session->write('messages', $old);
+		$this->Controller->request->session()->write('messages', $old);
 	}
 
 	/**

+ 147 - 0
src/Controller/Component/SessionComponent.php

@@ -0,0 +1,147 @@
+<?php
+namespace Tools\Controller\Component;
+
+use Cake\Controller\Component;
+
+/**
+ * The CakePHP SessionComponent provides a way to persist client data between
+ * page requests. It acts as a wrapper for the `$_SESSION` as well as providing
+ * convenience methods for several `$_SESSION` related functions.
+ *
+ * This class is here for backwards compatibility with CakePHP 2.x
+ */
+class SessionComponent extends Component {
+
+/**
+ * The Session object instance
+ *
+ * @var \Cake\Network\Session
+ */
+	protected $_session;
+
+/**
+ * Initialize properties.
+ *
+ * @param array $config The config data.
+ * @return void
+ */
+	public function initialize(array $config) {
+		$this->_session = $this->_registry->getController()->request->session();
+	}
+
+/**
+ * Used to write a value to a session key.
+ *
+ * In your controller: $this->Session->write('Controller.sessKey', 'session value');
+ *
+ * @param string $name The name of the key your are setting in the session.
+ *    This should be in a Controller.key format for better organizing
+ * @param string $value The value you want to store in a session.
+ * @return void
+ * @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::write
+ */
+	public function write($name, $value = null) {
+		$this->_session->write($name, $value);
+	}
+
+/**
+ * Used to read a session values for a key or return values for all keys.
+ *
+ * In your controller: $this->Session->read('Controller.sessKey');
+ * Calling the method without a param will return all session vars
+ *
+ * @param string $name the name of the session key you want to read
+ * @return mixed value from the session vars
+ * @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::read
+ */
+	public function read($name = null) {
+		return $this->_session->read($name);
+	}
+
+/**
+ * Wrapper for SessionComponent::del();
+ *
+ * In your controller: $this->Session->delete('Controller.sessKey');
+ *
+ * @param string $name the name of the session key you want to delete
+ * @return void
+ * @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::delete
+ */
+	public function delete($name) {
+		$this->_session->delete($name);
+	}
+
+/**
+ * Used to check if a session variable is set
+ *
+ * In your controller: $this->Session->check('Controller.sessKey');
+ *
+ * @param string $name the name of the session key you want to check
+ * @return bool true is session variable is set, false if not
+ * @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::check
+ */
+	public function check($name) {
+		return $this->_session->check($name);
+	}
+
+/**
+ * Used to renew a session id
+ *
+ * In your controller: $this->Session->renew();
+ *
+ * @return void
+ */
+	public function renew() {
+		$this->_session->renew();
+	}
+
+/**
+ * Used to destroy sessions
+ *
+ * In your controller: $this->Session->destroy();
+ *
+ * @return void
+ * @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::destroy
+ */
+	public function destroy() {
+		$this->_session->destroy();
+	}
+
+/**
+ * Get/Set the session id.
+ *
+ * When fetching the session id, the session will be started
+ * if it has not already been started. When setting the session id,
+ * the session will not be started.
+ *
+ * @param string $id Id to use (optional)
+ * @return string The current session id.
+ */
+	public function id($id = null) {
+		if ($id === null) {
+			$session = $this->_session;
+			$session->start();
+			return $session->id();
+		}
+		$this->_session->id($id);
+	}
+
+/**
+ * Returns a bool, whether or not the session has been started.
+ *
+ * @return bool
+ */
+	public function started() {
+		return $this->_session->started();
+	}
+
+/**
+ * Events supported by this component.
+ *
+ * @return array
+ */
+	public function implementedEvents() {
+		return [];
+	}
+
+}

+ 1 - 0
src/Controller/Controller.php

@@ -2,6 +2,7 @@
 namespace Tools\Controller;
 
 use Cake\Controller\Controller as CakeController;
+use Cake\Core\Configure;
 
 /**
  * DRY Controller stuff

+ 27 - 0
src/Model/Entity/Entity.php

@@ -4,4 +4,31 @@ namespace Tools\Model\Entity;
 use Cake\ORM\Entity as CakeEntity;
 
 class Entity extends CakeEntity {
+
+	/**
+	 * The main method for any enumeration, should be called statically
+	 * Now also supports reordering/filtering
+	 *
+	 * @link http://www.dereuromark.de/2010/06/24/static-enums-or-semihardcoded-attributes/
+	 * @param string $value or array $keys or NULL for complete array result
+	 * @param array $options (actual data)
+	 * @return mixed string/array
+	 */
+	public static function enum($value, array $options, $default = null) {
+		if ($value !== null && !is_array($value)) {
+			if (array_key_exists($value, $options)) {
+				return $options[$value];
+			}
+			return $default;
+		}
+		if ($value !== null) {
+			$newOptions = array();
+			foreach ($value as $v) {
+				$newOptions[$v] = $options[$v];
+			}
+			return $newOptions;
+		}
+		return $options;
+	}
+
 }

+ 33 - 0
src/Model/Table/Table.php

@@ -5,6 +5,7 @@ namespace Tools\Model\Table;
 use Cake\ORM\Table as CakeTable;
 use Cake\Validation\Validator;
 use Cake\Utility\Inflector;
+use Cake\Core\Configure;
 
 class Table extends CakeTable {
 
@@ -124,6 +125,38 @@ class Table extends CakeTable {
 	}
 
 	/**
+	 * Table::field()
+	 *
+	 * @param string $name
+	 * @param array $options
+	 * @return mixed Field value or null if not available
+	 */
+	public function field($name, array $options = array()) {
+		$result = $this->find('all', $options)->first();
+		if (!$result) {
+			return null;
+		}
+		return $result->get($name);
+	}
+
+	/**
+	 * Overwrite to allow markNew => auto
+	 *
+	 * @param array $data The data to build an entity with.
+	 * @param array $options A list of options for the object hydration.
+	 * @return \Cake\Datasource\EntityInterface
+	 */
+	public function newEntity(array $data = [], array $options = []) {
+		$options += ['markNew' => Configure::read('Entity.autoMarkNew') ? 'auto' : null];
+		if (isset($options['markNew']) && $options['markNew'] === 'auto') {
+			$this->_primaryKey = (array)$this->primaryKey();
+			$this->_primaryKey = $this->_primaryKey[0];
+			$options['markNew'] = !empty($data[$this->_primaryKey]);
+		}
+		return parent::newEntity($data, $options);
+	}
+
+	/**
 	 * truncate()
 	 *
 	 * @return void

+ 89 - 0
src/Utility/Language.php

@@ -0,0 +1,89 @@
+<?php
+
+namespace Tools\Utility;
+
+class Language {
+
+	public static function parseLanguageList($languageList = null) {
+		if ($languageList === null) {
+			if (empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
+				return array();
+			}
+			$languageList = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
+		}
+		$languages = array();
+		$languageRanges = explode(',', trim($languageList));
+		foreach ($languageRanges as $languageRange) {
+			if (preg_match('/(\*|[a-zA-Z0-9]{1,8}(?:-[a-zA-Z0-9]{1,8})*)(?:\s*;\s*q\s*=\s*(0(?:\.\d{0,3})|1(?:\.0{0,3})))?/', trim($languageRange), $match)) {
+				if (!isset($match[2])) {
+					$match[2] = '1.0';
+				} else {
+					$match[2] = (string)floatval($match[2]);
+				}
+				if (!isset($languages[$match[2]])) {
+					if ($match[2] === '1') {
+						$match[2] = '1.0';
+					}
+					$languages[$match[2]] = array();
+				}
+				$languages[$match[2]][] = strtolower($match[1]);
+			}
+		}
+		krsort($languages);
+		return $languages;
+	}
+
+	/**
+	 * Compares two parsed arrays of language tags and find the matches
+	 *
+	 * @return array
+	 */
+	public static function findMatches(array $accepted, array $available = []) {
+		$matches = array();
+		if (!$available) {
+			$available = static::parseLanguageList();
+		}
+		foreach ($accepted as $acceptedValue) {
+			foreach ($available as $availableQuality => $availableValues) {
+				$availableQuality = (float)$availableQuality;
+				if ($availableQuality === 0.0) {
+					continue;
+				}
+
+				foreach ($availableValues as $availableValue) {
+					$matchingGrade = static::_matchLanguage($acceptedValue, $availableValue);
+					if ($matchingGrade > 0) {
+						$q = (string)($availableQuality * $matchingGrade);
+						if ($q === '1') {
+							$q = '1.0';
+						}
+						if (!isset($matches[$q])) {
+							$matches[$q] = array();
+						}
+						if (!in_array($availableValue, $matches[$q])) {
+							$matches[$q][] = $availableValue;
+						}
+					}
+				}
+			}
+		}
+		krsort($matches);
+		return $matches;
+	}
+
+	/**
+	 * Compare two language tags and distinguish the degree of matching
+	 *
+	 * @return float
+	 */
+	protected static function _matchLanguage($a, $b) {
+		$a = explode('-', $a);
+		$b = explode('-', $b);
+		for ($i = 0, $n = min(count($a), count($b)); $i < $n; $i++) {
+			if ($a[$i] !== $b[$i])
+				break;
+		}
+		return $i === 0 ? 0 : (float)$i / count($a);
+	}
+
+}

+ 2 - 2
src/View/Helper/CommonHelper.php

@@ -54,11 +54,11 @@ class CommonHelper extends Helper {
 			$html .= '</div>';
 			if ($types) {
 				foreach ($types as $type) {
-					CakeSession::delete('messages.' . $type);
+					$this->request->session()->delete('messages.' . $type);
 					Configure::delete('messages.' . $type);
 				}
 			} else {
-				CakeSession::delete('messages');
+				$this->request->session()->delete('messages');
 				Configure::delete('messages');
 			}
 		}

+ 100 - 0
tests/TestCase/Utility/LanguageTest.php

@@ -0,0 +1,100 @@
+<?php
+namespace Tools\TestCase\Utility;
+
+use Tools\Utility\Language;
+use Cake\TestSuite\TestCase;
+
+class LanguageTest extends TestCase {
+
+	public function setUp() {
+		parent::setUp();
+
+		$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4';
+	}
+
+	/**
+	 * LanguageTest::testAll()
+	 *
+	 * @return void
+	 */
+	public function testParseLanguageListEmpty() {
+		$_SERVER['HTTP_ACCEPT_LANGUAGE'] = '';
+		$res = Language::parseLanguageList();
+		$this->assertSame([], $res);
+	}
+
+	/**
+	 * LanguageTest::testAll()
+	 *
+	 * @return void
+	 */
+	public function testParseLanguageList() {
+		$res = Language::parseLanguageList();
+		$expected = [
+			'1.0' => [
+				'de-de'
+			],
+			'0.8' => [
+				'de'
+			],
+			'0.6' => [
+				'en-us'
+			],
+			'0.4' => [
+				'en'
+			]
+		];
+		$this->assertSame($expected, $res);
+	}
+
+	/**
+	 * LanguageTest::testFindMatches()
+	 *
+	 * @return void
+	 */
+	public function testFindMatches() {
+		$res = Language::findMatches([]);
+		$this->assertSame([], $res);
+
+		$res = Language::findMatches(['de', 'en']);
+		$expected = [
+			'1.0' => [
+				'de-de'
+			],
+			'0.8' => [
+				'de'
+			],
+			'0.6' => [
+				'en-us'
+			],
+			'0.4' => [
+				'en'
+			]
+		];
+		$this->assertSame($expected, $res);
+
+		$res = Language::findMatches(['de']);
+		$expected = [
+			'1.0' => [
+				'de-de'
+			],
+			'0.8' => [
+				'de'
+			]
+		];
+		$this->assertSame($expected, $res);
+
+		$res = Language::findMatches(['cs', 'en']);
+		$expected = [
+			'0.6' => [
+				'en-us'
+			],
+			'0.4' => [
+				'en'
+			]
+		];
+		$this->assertSame($expected, $res);
+	}
+
+}
+