浏览代码

ResetBehavior

euromark 11 年之前
父节点
当前提交
318744a67e

+ 161 - 0
src/Model/Behavior/ResetBehavior.php

@@ -0,0 +1,161 @@
+<?php
+namespace Tools\Model\Behavior;
+
+use Cake\Event\Event;
+use Cake\ORM\Behavior;
+use Cake\ORM\Entity;
+use Cake\ORM\Query;
+use Cake\Core\Configure;
+use Cake\ORM\Table;
+
+/**
+ * Allows the model to reset all records as batch command.
+ * This way any slugging, geocoding or other beforeValidate, beforeSave, ... callbacks
+ * can be retriggered for them.
+ *
+ * By default it will not update the modified timestamp and will re-save id and displayName.
+ * If you need more fields, you need to specify them manually.
+ *
+ * You can also disable validate callback or provide a conditions scope to match only a subset
+ * of records.
+ *
+ * For performance and memory reasons the records will only be processed in loops (not all at once).
+ * If you have time-sensitive data, you can modify the limit of records per loop as well as the
+ * timeout in between each loop.
+ * Remember to raise set_time_limit() if you do not run this via CLI.
+ *
+ * It is recommended to attach this behavior dynamically where needed:
+ *
+ *    $table->addBehavior('Tools.Reset', array(...));
+ *    $table->resetRecords();
+ *
+ * If you want to provide a callback function/method, you can either use object methods or
+ * static functions/methods:
+ *
+ *    'callback' => array($this, 'methodName')
+ *
+ * and
+ *
+ *    public function methodName(Entity $entity, &$fields) {}
+ *
+ * For tables with lots of records you might want to use a shell and the CLI to invoke the reset/update process.
+ *
+ * @author Mark Scherer
+ * @license MIT
+ * @version 1.0
+ */
+class ResetBehavior extends Behavior {
+
+	protected $_defaultConfig = array(
+		'limit' => 100, // batch of records per loop
+		'timeout' => null, // in seconds
+		'fields' => array(), // if not displayField
+		'updateFields' => array(), // if saved fields should be different from fields
+		'validate' => true, // trigger beforeValidate callback
+		'updateTimestamp' => false, // update modified/updated timestamp
+		'scope' => array(), // optional conditions
+		'callback' => null,
+	);
+
+	/**
+	 * Adding validation rules
+	 * also adds and merges config settings (direct + configure)
+	 *
+	 * @return void
+	 */
+	public function __construct(Table $table, array $config = []) {
+		$defaults = $this->_defaultConfig;
+		if ($configureDefaults = Configure::read('Reset')) {
+			$defaults = $configureDefaults + $defaults;
+		}
+		$config + $defaults;
+		parent::__construct($table, $config);
+
+		$this->_table = $table;
+	}
+
+	/**
+	 * Regenerate all records (including possible beforeValidate/beforeSave callbacks).
+	 *
+	 * @param Model $Model
+	 * @param array $conditions
+	 * @param int $recursive
+	 * @return int Modified records
+	 */
+	public function resetRecords($params = array()) {
+		$defaults = array(
+			'page' => 1,
+			'limit' => $this->_config['limit'],
+			'fields' => array(),
+			'order' => $this->_table->alias() . '.' . $this->_table->primaryKey() . ' ASC',
+			'conditions' => $this->_config['scope'],
+			//'recursive' => $this->_config['recursive'],
+		);
+		if (!empty($this->_config['fields'])) {
+			foreach ((array)$this->_config['fields'] as $field) {
+				if (!$this->_table->hasField($field)) {
+					throw new \Exception('Table does not have field ' . $field);
+				}
+			}
+			$defaults['fields'] = array_merge(array($this->_table->alias() . '.' . $this->_table->primaryKey()), $this->_config['fields']);
+		} else {
+			$defaults['fields'] = array($this->_table->alias() . '.' . $this->_table->primaryKey());
+			if ($this->_table->displayField() !== $this->_table->primaryKey()) {
+				$defaults['fields'][] = $this->_table->alias() . '.' . $this->_table->displayField();
+			}
+		}
+		if (!$this->_config['updateTimestamp']) {
+			$fields = array('modified', 'updated');
+			foreach ($fields as $field) {
+				if ($this->_table->schema()->column($field)) {
+					$defaults['fields'][] = $field;
+					break;
+				}
+			}
+		}
+
+		$params += $defaults;
+		$count = $this->_table->find('count', compact('conditions'));
+		$max = ini_get('max_execution_time');
+		if ($max) {
+			set_time_limit(max($max, $count / $this->_config['limit']));
+		}
+
+		$modified = 0;
+		while (($records = $this->_table->find('all', $params)->toArray())) {
+			foreach ($records as $record) {
+				$fieldList = $params['fields'];
+				if (!empty($updateFields)) {
+					$fieldList = $updateFields;
+				}
+				if ($fieldList && !in_array($this->_table->primaryKey(), $fieldList)) {
+					$fieldList[] = $this->_table->primaryKey();
+				}
+
+				if ($this->_config['callback']) {
+					if (is_callable($this->_config['callback'])) {
+						$parameters = array($record, &$fieldList);
+						$record = call_user_func_array($this->_config['callback'], $parameters);
+					} else {
+						$record = $this->_table->{$this->_config['callback']}($record, $fieldList);
+					}
+					if (!$record) {
+						continue;
+					}
+				}
+
+				$res = $this->_table->save($record, compact('validate', 'fieldList'));
+				if (!$res) {
+					throw new \Exception(print_r($this->_table->errors(), true));
+				}
+				$modified++;
+			}
+			$params['page']++;
+			if ($this->_config['timeout']) {
+				sleep((int)$this->_config['timeout']);
+			}
+		}
+		return $modified;
+	}
+
+}

+ 3 - 3
src/Model/Behavior/SluggedBehavior.php

@@ -124,11 +124,11 @@ class SluggedBehavior extends Behavior {
 				if (strpos($field, '.')) {
 					list($alias, $field) = explode('.', $field);
 					if (!$Model->$alias->hasField($field)) {
-						throw new Exception('(SluggedBehavior::setup) model ' . $Model->$alias->name . ' is missing the field ' . $field .
+						throw new \Exception('(SluggedBehavior::setup) model ' . $Model->$alias->name . ' is missing the field ' . $field .
 							' (specified in the setup for model ' . $Model->name . ') ');
 					}
 				} elseif (!$Model->hasField($field)) {
-					throw new Exception('(SluggedBehavior::setup) model ' . $Model->name . ' is missing the field ' . $field . ' specified in the setup.');
+					throw new \Exception('(SluggedBehavior::setup) model ' . $Model->name . ' is missing the field ' . $field . ' specified in the setup.');
 				}
 			}
 		}
@@ -382,7 +382,7 @@ class SluggedBehavior extends Behavior {
 					'fieldList' => array_merge(array($this->_table->primaryKey(), $slugField), $label)
 				);
 				if (!$Model->save($row, $options)) {
-					throw new RuntimeException(print_r($row[$this->_table->alias()], true) . ': ' . print_r($Model->validationErrors, true));
+					throw new \Exception(print_r($row[$this->_table->alias()], true) . ': ' . print_r($Model->validationErrors, true));
 				}
 			}
 			$params['page']++;

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

@@ -253,6 +253,9 @@ class Table extends CakeTable {
 		if ($type === 'first') {
 			return parent::find('all', $options)->first();
 		}
+		if ($type === 'count') {
+			return parent::find('all', $options)->count();
+		}
 		return parent::find($type, $options);
 	}
 

+ 14 - 20
src/Network/Email/Email.php

@@ -289,20 +289,15 @@ class Email extends CakeEmail {
 		return false;
 	}
 
-	/**
-	 * Try to determine the mimetype by filename.
-	 * Uses finfo_open() if availble, otherwise guesses it via file extension.
-	 *
-	 * @param string $filename
-	 * @return string Mimetype
-	 */
-	protected function _getMime($filename) {
-		$mimeType = Utility::getMimeType($filename);
-		if (!$mimeType) {
-			$ext = pathinfo($filename, PATHINFO_EXTENSION);
-			$mimeType = $this->_getMimeByExtension($ext);
+	protected function _getMimeByExtension($ext, $default = 'application/octet-stream') {
+		if (!isset($this->_Mime)) {
+			$this->_Mime = new Mime();
 		}
-		return $mimeType;
+		$mime = $this->_Mime->getMimeTypeByAlias($ext);
+		if (!$mime) {
+			$mime = $default;
+		}
+		return $mime;
 	}
 
 	/**
@@ -312,16 +307,15 @@ class Email extends CakeEmail {
 	 * @param string $defaultMimeType
 	 * @return string Mimetype (falls back to `application/octet-stream`)
 	 */
-	protected function _getMimeByExtension($ext, $default = 'application/octet-stream') {
-		if (!$ext) {
-			return $default;
-		}
+	protected function _getMime($filename, $default = 'application/octet-stream') {
 		if (!isset($this->_Mime)) {
 			$this->_Mime = new Mime();
 		}
-		$mime = $this->_Mime->getMimeType($ext);
-		if (!$mime) {
-			$mime = $default;
+		$mime = $this->_Mime->detectMimeType($filename);
+		// Some environments falsely return the default too fast, better fallback to extension here
+		if (!$mime || $mime === $default) {
+			$ext = pathinfo($filename, PATHINFO_EXTENSION);
+			$mime = $this->_Mime->getMimeTypeByAlias($ext);
 		}
 		return $mime;
 	}

+ 63 - 29
src/Utility/Mime.php

@@ -714,7 +714,7 @@ class Mime extends Response {
 	 *
 	 * @return array
 	 */
-	public function getMimeTypes($coreHasPrecedence = false) {
+	public function mimeTypes($coreHasPrecedence = false) {
 		if ($coreHasPrecedence) {
 			return $this->_mimeTypes += $this->_mimeTypesExt;
 		}
@@ -722,7 +722,7 @@ class Mime extends Response {
 	}
 
 	/**
-	 * Returns the primary mime type definition for an alias
+	 * Returns the primary mime type definition for an alias/extension.
 	 *
 	 * e.g `getMimeType('pdf'); // returns 'application/pdf'`
 	 *
@@ -731,9 +731,9 @@ class Mime extends Response {
 	 * @param bool $coreHasPrecedence
 	 * @return mixed string mapped mime type or false if $alias is not mapped
 	 */
-	public function getMimeType($alias, $primaryOnly = true, $coreHasPrecedence = false) {
+	public function getMimeTypeByAlias($alias, $primaryOnly = true, $coreHasPrecedence = false) {
 		if (empty($this->_mimeTypeTmp)) {
-			$this->_mimeTypesTmp = $this->getMimeTypes($coreHasPrecedence);
+			$this->_mimeTypesTmp = $this->mimeTypes($coreHasPrecedence);
 		}
 		if (!isset($this->_mimeTypesTmp[$alias])) {
 			return false;
@@ -750,7 +750,7 @@ class Mime extends Response {
 	 *
 	 * e.g `mapType('application/pdf'); // returns 'pdf'`
 	 *
-	 * @param mixed $ctype Either a string content type to map, or an array of types.
+	 * @param string|array $ctype Either a string content type to map, or an array of types.
 	 * @return mixed Aliases for the types provided.
 	 */
 	public function mapType($ctype) {
@@ -760,19 +760,14 @@ class Mime extends Response {
 	/**
 	 * Retrieve the corresponding MIME type, if one exists
 	 *
-	 * @param String $file File Name (relative location such as "image_test.jpg" or full "http://site.com/path/to/image_test.jpg")
-	 * @return String MIMEType - The type of the file passed in the argument
+	 * @param string $file File Name (relative location such as "image_test.jpg" or full "http://site.com/path/to/image_test.jpg")
+	 * @return string MIMEType - The type of the file passed in the argument
 	 */
-	public function extractMimeType($file = null) {
-		if (!is_file($file)) {
-			return false;
-		}
-		/**
-		* Attempts to retrieve file info from FINFO
-		* If FINFO functions are not available then try to retrieve MIME type from pre-defined MIMEs
-		* If MIME type doesn't exist, then try (as a last resort) to use the (deprecated) mime_content_type function
-		* If all else fails, just return application/octet-stream
-		*/
+	public function detectMimeType($file = null) {
+		// Attempts to retrieve file info from FINFO
+		// If FINFO functions are not available then try to retrieve MIME type from pre-defined MIMEs
+		// If MIME type doesn't exist, then try (as a last resort) to use the (deprecated) mime_content_type function
+		// If all else fails, just return application/octet-stream
 		if (!function_exists("finfo_open")) {
 			if (function_exists("mime_content_type")) {
 				$type = mime_content_type($file);
@@ -781,15 +776,57 @@ class Mime extends Response {
 				}
 			}
 			$extension = $this->_getExtension($file);
-			if ($mimeType = $this->getMimeType($extension)) {
+			if ($mimeType = $this->getMimeTypeByAlias($extension)) {
 				return $mimeType;
 			}
 			return "application/octet-stream";
 		}
-		$finfo = finfo_open(FILEINFO_MIME_TYPE);
-		$mimeType = finfo_file($finfo, $file);
-		finfo_close($finfo);
-		return $mimeType;
+		return $this->_detectMimeType($file);
+	}
+
+	/**
+	 * Utility::getMimeType()
+	 *
+	 * @param string $file File
+	 * @return string Mime type
+	 */
+	public static function _detectMimeType($file) {
+		if (!function_exists('finfo_open')) {
+			//throw new InternalErrorException('finfo_open() required - please enable');
+		}
+
+		// Treat non local files differently
+		$pattern = '~^https?://~i';
+		if (preg_match($pattern, $file)) {
+			$headers = @get_headers($file);
+			if (!preg_match("|\b200\b|", $headers[0])) {
+				return '';
+			}
+			foreach ($headers as $header) {
+				if (strpos($header, 'Content-Type:') === 0) {
+					return trim(substr($header, 13));
+				}
+			}
+			return '';
+		}
+
+		if (!is_file($file)) {
+			return '';
+		}
+
+		$finfo = finfo_open(FILEINFO_MIME);
+		$mimetype = finfo_file($finfo, $file);
+		if (($pos = strpos($mimetype, ';')) !== false) {
+			$mimetype = substr($mimetype, 0, $pos);
+		}
+		if ($mimetype) {
+			return $mimetype;
+		}
+		$extension = $this->_getExtension($file);
+		if ($mimeType = $this->getMimeTypeByAlias($extension)) {
+			return $mimeType;
+		}
+		return "application/octet-stream";
 	}
 
 	/**
@@ -818,13 +855,10 @@ class Mime extends Response {
 	 * @param String $file The full file name
 	 * @return String ext The file extension
 	 */
-	protected function _getExtension($file = null) {
-		if ($file !== null) {
-			$pieces = explode('.', $file);
-			$ext = strtolower(array_pop($pieces));
-			return $ext;
-		}
-		return false;
+	protected function _getExtension($file) {
+		$pieces = explode('.', $file);
+		$ext = strtolower(array_pop($pieces));
+		return $ext;
 	}
 
 }

+ 1 - 34
src/Utility/Utility.php

@@ -245,40 +245,6 @@ class Utility {
 	}
 
 	/**
-	 * Utility::getMimeType()
-	 *
-	 * @param string $file File
-	 * @return string Mime type
-	 */
-	public static function getMimeType($file) {
-		if (!function_exists('finfo_open')) {
-			throw new InternalErrorException('finfo_open() required - please enable');
-		}
-
-		// Treat non local files differently
-		$pattern = '~^https?://~i';
-		if (preg_match($pattern, $file)) {
-			$headers = @get_headers($file);
-			if (!preg_match("|\b200\b|", $headers[0])) {
-				return '';
-			}
-			foreach ($headers as $header) {
-				if (strpos($header, 'Content-Type:') === 0) {
-					return trim(substr($header, 13));
-				}
-			}
-			return '';
-		}
-
-		$finfo = finfo_open(FILEINFO_MIME);
-		$mimetype = finfo_file($finfo, $file);
-		if (($pos = strpos($mimetype, ';')) !== false) {
-			$mimetype = substr($mimetype, 0, $pos);
-		}
-		return $mimetype;
-	}
-
-	/**
 	 * Parse headers from a specific URL content.
 	 *
 	 * @param string $url
@@ -410,6 +376,7 @@ class Utility {
 	 *
 	 * @param array
 	 * @return bool
+	 * @deprecated Not sure this is useful for CakePHP 3.0
 	 */
 	public static function isValidSaveAll($array) {
 		if (empty($array)) {

+ 3 - 2
src/View/Helper/ObfuscateHelper.php

@@ -169,8 +169,9 @@ class ObfuscateHelper extends Helper {
 			if ($replacement !== null) {
 				$str = preg_replace("/({$delim})(" . str_replace('\*', '\w*?', preg_quote($badword, '/')) . ")({$delim})/i", "\\1{$replacement}\\3", $str);
 			} else {
-				$str = preg_replace("/({$delim})(" . str_replace('\*', '\w*?', preg_quote($badword, '/')) . ")({$delim})/ie", "'\\1'.str_repeat('#', strlen('\\2')).'\\3'",
-					$str);
+				$str = preg_replace_callback("/({$delim})(" . str_replace('\*', '\w*?', preg_quote($badword, '/')) . ")({$delim})/i", function($matches) {
+					return $matches[1] . str_repeat('#', strlen($matches[2])). $matches[3];
+				}, $str);
 			}
 		}
 

+ 41 - 0
tests/Fixture/ResetCommentsFixture.php

@@ -0,0 +1,41 @@
+<?php
+namespace Tools\Test\Fixture;
+
+use Cake\TestSuite\Fixture\TestFixture;
+
+/**
+ * For ResetBehavior
+ */
+class ResetCommentsFixture extends TestFixture {
+
+/**
+ * fields property
+ *
+ * @var array
+ */
+	public $fields = array(
+		'id' => ['type' => 'integer'],
+		'article_id' => ['type' => 'integer', 'null' => false],
+		'user_id' => ['type' => 'integer', 'null' => false],
+		'comment' => 'text',
+		'published' => ['type' => 'string', 'length' => 1, 'default' => 'N'],
+		'created' => 'datetime',
+		'updated' => 'datetime',
+		'_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]]
+	);
+
+/**
+ * records property
+ *
+ * @var array
+ */
+	public $records = array(
+		array('article_id' => 1, 'user_id' => 2, 'comment' => 'First Comment for First Article', 'published' => 'Y', 'created' => '2007-03-18 10:45:23', 'updated' => '2007-03-18 10:47:31'),
+		array('article_id' => 1, 'user_id' => 4, 'comment' => 'Second Comment for First Article', 'published' => 'Y', 'created' => '2007-03-18 10:47:23', 'updated' => '2007-03-18 10:49:31'),
+		array('article_id' => 1, 'user_id' => 1, 'comment' => 'Third Comment for First Article', 'published' => 'Y', 'created' => '2007-03-18 10:49:23', 'updated' => '2007-03-18 10:51:31'),
+		array('article_id' => 1, 'user_id' => 1, 'comment' => 'Fourth Comment for First Article', 'published' => 'N', 'created' => '2007-03-18 10:51:23', 'updated' => '2007-03-18 10:53:31'),
+		array('article_id' => 2, 'user_id' => 1, 'comment' => 'First Comment for Second Article', 'published' => 'Y', 'created' => '2007-03-18 10:53:23', 'updated' => '2007-03-18 10:55:31'),
+		array('article_id' => 2, 'user_id' => 2, 'comment' => 'Second Comment for Second Article', 'published' => 'Y', 'created' => '2007-03-18 10:55:23', 'updated' => '2007-03-18 10:57:31')
+	);
+
+}

+ 8 - 8
tests/Fixture/RolesFixture.php

@@ -16,14 +16,14 @@ class RolesFixture extends TestFixture {
 	 */
 	public $fields = array(
 		'id' => ['type' => 'integer'],
-		'name' => array('type' => 'string', 'null' => false, 'length' => 64, 'collate' => 'utf8_unicode_ci', 'comment' => '', 'charset' => 'utf8'),
-		'description' => array('type' => 'string', 'null' => false, 'default' => null, 'collate' => 'utf8_unicode_ci', 'comment' => '', 'charset' => 'utf8'),
-		'alias' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 20, 'collate' => 'utf8_unicode_ci', 'comment' => '', 'charset' => 'utf8'),
-		'default_role' => array('type' => 'boolean', 'null' => false, 'default' => false, 'collate' => null, 'comment' => 'set at register'),
-		'created' => array('type' => 'datetime', 'null' => true, 'default' => null, 'collate' => null, 'comment' => ''),
-		'modified' => array('type' => 'datetime', 'null' => true, 'default' => null, 'collate' => null, 'comment' => ''),
-		'sort' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => 10, 'collate' => null, 'comment' => ''),
-		'active' => array('type' => 'boolean', 'null' => false, 'default' => false, 'collate' => null, 'comment' => ''),
+		'name' => ['type' => 'string', 'null' => false, 'length' => 64, 'collate' => 'utf8_unicode_ci', 'comment' => '', 'charset' => 'utf8'],
+		'description' => ['type' => 'string', 'null' => false, 'default' => null, 'collate' => 'utf8_unicode_ci', 'comment' => '', 'charset' => 'utf8'],
+		'alias' => ['type' => 'string', 'null' => false, 'default' => null, 'length' => 20, 'collate' => 'utf8_unicode_ci', 'comment' => '', 'charset' => 'utf8'],
+		'default_role' => ['type' => 'boolean', 'null' => false, 'default' => false, 'collate' => null, 'comment' => 'set at register'],
+		'created' => ['type' => 'datetime', 'null' => true, 'default' => null, 'collate' => null, 'comment' => ''],
+		'modified' => ['type' => 'datetime', 'null' => true, 'default' => null, 'collate' => null, 'comment' => ''],
+		'sort' => ['type' => 'integer', 'null' => false, 'default' => '0', 'length' => 10, 'collate' => null, 'comment' => ''],
+		'active' => ['type' => 'boolean', 'null' => false, 'default' => false, 'collate' => null, 'comment' => ''],
 		'_constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]]
 	);
 

+ 44 - 0
tests/TestApp/Model/Table/ResetCommentsTable.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace TestApp\Model\Table;
+
+use Tools\Model\Table\Table;
+use Cake\ORM\Entity;
+
+class ResetCommentsTable extends Table {
+
+	public function initialize(array $config) {
+		$this->displayField('comment');
+		parent::initialize($config);
+	}
+
+	public function customCallback(Entity $record, &$updateFields) {
+		$record->comment .= ' xyz';
+		$fields[] = 'some_other_field';
+		return $record;
+	}
+
+	public function customObjectCallback(Entity $record, &$updateFields) {
+		$record['comment'] .= ' xxx';
+		$updateFields[] = 'some_other_field';
+		return $record;
+	}
+
+	public static function customStaticCallback(Entity $record, &$updateFields) {
+		$record['comment'] .= ' yyy';
+		$updateFields[] = 'some_other_field';
+		return $record;
+	}
+
+	public static function fieldsCallback(Entity $record, &$updateFields) {
+		$record['comment'] = 'foo';
+		return $record;
+	}
+
+	public static function fieldsCallbackAuto(Entity $record, &$updateFields) {
+		$record['comment'] = 'bar';
+		$updateFields[] = 'comment';
+		return $record;
+	}
+
+}

+ 177 - 0
tests/TestCase/Model/Behavior/ResetBehaviorTest.php

@@ -0,0 +1,177 @@
+<?php
+
+namespace Tools\Model\Behavior;
+
+use Tools\Model\Behavior\ResetBehavior;
+use Tools\TestSuite\TestCase;
+//use App\Model\AppModel;
+use Cake\ORM\TableRegistry;
+use Tools\Model\Table\Table;
+use Cake\Core\Configure;
+
+class ResetBehaviorTest extends TestCase {
+
+	public $ResetBehavior;
+
+	public $Table;
+
+	public $fixtures = array('plugin.tools.reset_comments');
+
+	public function setUp() {
+		parent::setUp();
+
+		Configure::write('App.namespace', 'TestApp');
+
+		//set_time_limit(10);
+
+		$this->Table = TableRegistry::get('ResetComments');
+		$this->Table->addBehavior('Tools.Reset');
+	}
+
+	public function tearDown() {
+		TableRegistry::clear();
+
+		parent::tearDown();
+	}
+
+	/**
+	 * ResetBehaviorTest::testResetRecords()
+	 *
+	 * @return void
+	 */
+	public function testResetRecords() {
+		$x = $this->Table->find('all', array('fields' => array('comment'), 'order' => array('updated' => 'DESC')))->first();
+
+		$result = $this->Table->resetRecords();
+		$this->assertTrue((bool)$result);
+
+		$y = $this->Table->find('all', array('fields' => array('comment'), 'order' => array('updated' => 'DESC')))->first();
+		$this->assertSame($x->toArray(), $y->toArray());
+	}
+
+	/**
+	 * ResetBehaviorTest::testResetRecordsWithUpdatedTimestamp()
+	 *
+	 * @return void
+	 */
+	public function _testResetRecordsWithUpdatedTimestamp() {
+		$this->Table->removeBehavior('Reset');
+		$this->Table->addBehavior('Tools.Reset', array('updateTimestamp' => true));
+
+		$x = $this->Table->find('all', array('order' => array('updated' => 'DESC')))->first();
+		$this->assertTrue($x['updated'] < '2007-12-31');
+
+		$result = $this->Table->resetRecords();
+		$this->assertTrue((bool)$result);
+
+		$x = $this->Table->find('all', array('order' => array('updated' => 'ASC')))->first();
+		$this->assertTrue($x['updated'] > (date('Y') - 1) . '-12-31');
+	}
+
+	/**
+	 * ResetBehaviorTest::testResetWithCallback()
+	 *
+	 * @return void
+	 */
+	public function testResetWithCallback() {
+		$this->Table->removeBehavior('Reset');
+		$this->Table->addBehavior('Tools.Reset', array('callback' => 'customCallback'));
+
+		$x = $this->Table->find('all', array('conditions' => array('id' => 6)))->first();
+		$this->assertEquals('Second Comment for Second Article', $x['comment']);
+
+		$result = $this->Table->resetRecords();
+		$this->assertTrue((bool)$result);
+
+		$x = $this->Table->find('all', array('conditions' => array('id' => 6)))->first();
+		$expected = 'Second Comment for Second Article xyz';
+		$this->assertEquals($expected, $x['comment']);
+	}
+
+	/**
+	 * ResetBehaviorTest::testResetWithObjectCallback()
+	 *
+	 * @return void
+	 */
+	public function testResetWithObjectCallback() {
+		$this->Table->removeBehavior('Reset');
+		$this->Table->addBehavior('Tools.Reset', array('callback' => array($this->Table, 'customObjectCallback')));
+
+		$x = $this->Table->find('first', array('conditions' => array('id' => 6)));
+		$this->assertEquals('Second Comment for Second Article', $x['comment']);
+
+		$result = $this->Table->resetRecords();
+		$this->assertTrue((bool)$result);
+
+		$x = $this->Table->find('first', array('conditions' => array('id' => 6)));
+		$expected = 'Second Comment for Second Article xxx';
+		$this->assertEquals($expected, $x['comment']);
+	}
+
+	/**
+	 * ResetBehaviorTest::testResetWithStaticCallback()
+	 *
+	 * @return void
+	 */
+	public function testResetWithStaticCallback() {
+		$this->Table->removeBehavior('Reset');
+		$this->Table->addBehavior('Tools.Reset', array('callback' => 'TestApp\Model\Table\ResetCommentsTable::customStaticCallback'));
+
+		$x = $this->Table->find('first', array('conditions' => array('id' => 6)));
+		$this->assertEquals('Second Comment for Second Article', $x['comment']);
+
+		$result = $this->Table->resetRecords();
+		$this->assertTrue((bool)$result);
+
+		$x = $this->Table->find('first', array('conditions' => array('id' => 6)));
+		$expected = 'Second Comment for Second Article yyy';
+		$this->assertEquals($expected, $x['comment']);
+	}
+
+	/**
+	 * ResetBehaviorTest::testResetWithCallbackAndFields()
+	 *
+	 * @return void
+	 */
+	public function testResetWithCallbackAndFields() {
+		$this->Table->removeBehavior('Reset');
+		$this->Table->addBehavior('Tools.Reset', array(
+			'fields' => array('id'),
+			'updateFields' => array('comment'),
+			'callback' => 'TestApp\Model\Table\ResetCommentsTable::fieldsCallback'));
+
+		$x = $this->Table->find('first', array('conditions' => array('id' => 6)));
+		$this->assertEquals('Second Comment for Second Article', $x['comment']);
+
+		$result = $this->Table->resetRecords();
+		$this->assertTrue((bool)$result);
+
+		$x = $this->Table->find('first', array('conditions' => array('id' => 6)));
+		$expected = 'foo';
+		$this->assertEquals($expected, $x['comment']);
+	}
+
+	/**
+	 * ResetBehaviorTest::testResetWithCallbackAndFieldsAutoAdded()
+	 *
+	 * @return void
+	 */
+	public function testResetWithCallbackAndFieldsAutoAdded() {
+		$this->Table->removeBehavior('Reset');
+		$this->Table->addBehavior('Tools.Reset', array(
+			'fields' => array('id'),
+			'updateFields' => array('id'),
+			'callback' => 'TestApp\Model\Table\ResetCommentsTable::fieldsCallbackAuto'));
+
+		$x = $this->Table->find('first', array('conditions' => array('id' => 6)));
+		$this->assertEquals('Second Comment for Second Article', $x['comment']);
+
+		$result = $this->Table->resetRecords();
+		$this->assertTrue((bool)$result);
+
+		$x = $this->Table->find('first', array('conditions' => array('id' => 6)));
+		$expected = 'bar';
+		$this->assertEquals($expected, $x['comment']);
+	}
+
+}

+ 1 - 1
tests/TestCase/Network/Email/EmailTest.php

@@ -218,7 +218,7 @@ class EmailTest extends TestCase {
 			//'data' => $content,
 			'mimetype' => 'image/jpeg',
 		);
-		$this->assertEquals($expected, $res['hotel.gif']);#
+		$this->assertEquals($expected, $res['hotel.gif']);
 		$this->assertSame(2, count($res));
 	}
 

+ 29 - 10
tests/TestCase/Utility/MimeTest.php

@@ -4,6 +4,7 @@ namespace Tools\TestCase\Utility;
 use Tools\Utility\Mime;
 use Cake\TestSuite\TestCase;
 use Cake\Network\Response;
+use Cake\Core\Plugin;
 
 class MimeTest extends TestCase {
 
@@ -21,37 +22,37 @@ class MimeTest extends TestCase {
 	}
 
 	public function testAll() {
-		$res = $this->Mime->getMimeTypes();
+		$res = $this->Mime->mimeTypes();
 		$this->assertTrue(is_array($res) && count($res) > 100);
 	}
 
 	public function testSingle() {
-		$res = $this->Mime->getMimeType('odxs');
+		$res = $this->Mime->getMimeTypeByAlias('odxs');
 		$this->assertFalse($res);
 
-		$res = $this->Mime->getMimeType('ods');
+		$res = $this->Mime->getMimeTypeByAlias('ods');
 		$this->assertEquals('application/vnd.oasis.opendocument.spreadsheet', $res);
 	}
 
 	public function testOverwrite() {
-		$res = $this->Mime->getMimeType('ics');
+		$res = $this->Mime->getMimeTypeByAlias('ics');
 		$this->assertEquals('application/ics', $res);
 	}
 
 	public function testReverseToSingle() {
-		$res = $this->Mime->getMimeType('html');
+		$res = $this->Mime->getMimeTypeByAlias('html');
 		$this->assertEquals('text/html', $res);
 
-		$res = $this->Mime->getMimeType('csv');
+		$res = $this->Mime->getMimeTypeByAlias('csv');
 		$this->assertEquals('text/csv', $res);
 	}
 
 	public function testReverseToMultiple() {
-		$res = $this->Mime->getMimeType('html', false);
+		$res = $this->Mime->getMimeTypeByAlias('html', false);
 		$this->assertTrue(is_array($res));
 		$this->assertSame(2, count($res));
 
-		$res = $this->Mime->getMimeType('csv', false);
+		$res = $this->Mime->getMimeTypeByAlias('csv', false);
 		$this->assertTrue(is_array($res)); //  && count($res) > 2
 		$this->assertSame(2, count($res));
 	}
@@ -61,7 +62,7 @@ class MimeTest extends TestCase {
 	 */
 	public function testCorrectFileExtension() {
 		file_put_contents(TMP . 'sometest.txt', 'xyz');
-		$is = $this->Mime->extractMimeType(TMP . 'sometest.txt');
+		$is = $this->Mime->detectMimeType(TMP . 'sometest.txt');
 		//pr($is);
 		$this->assertEquals($is, 'text/plain');
 	}
@@ -71,12 +72,30 @@ class MimeTest extends TestCase {
 	 */
 	public function testWrongFileExtension() {
 		file_put_contents(TMP . 'sometest.zip', 'xyz');
-		$is = $this->Mime->extractMimeType(TMP . 'sometest.zip');
+		$is = $this->Mime->detectMimeType(TMP . 'sometest.zip');
 		//pr($is);
 		$this->assertEquals($is, 'text/plain');
 		//Test failes? finfo_open not availaible??
 	}
 
+
+	/**
+	 * testgetMimeTypeByAlias()
+	 *
+	 * @cover detectMimeType
+	 * @return void
+	 */
+	public function testgetMimeTypeByAlias() {
+		$res = $this->Mime->detectMimeType('http://www.spiegel.de/static/sys/v10/icons/home_v2.png');
+		$this->assertEquals('image/png', $res);
+
+		$res = $this->Mime->detectMimeType('http://www.spiegel.de/static/sys/v10/icons/home_v2_inexistent.png');
+		$this->assertEquals('', $res);
+
+		$res = $this->Mime->detectMimeType(Plugin::path('Tools') . 'tests' . DS . 'test_files' . DS . 'img' . DS . 'hotel.jpg');
+		$this->assertEquals('image/jpeg', $res);
+	}
+
 	/**
 	 * Test fake files
 	 */

+ 0 - 17
tests/TestCase/Utility/UtilityTest.php

@@ -196,23 +196,6 @@ class UtilityTest extends TestCase {
 	}
 
 	/**
-	 * UtilityTest::testGetMimeType()
-	 *
-	 * @covers Utility::getMimeType
-	 * @return void
-	 */
-	public function testGetMimeType() {
-		$res = Utility::getMimeType('http://www.spiegel.de/static/sys/v10/icons/home_v2.png');
-		$this->assertEquals('image/png', $res);
-
-		$res = Utility::getMimeType('http://www.spiegel.de/static/sys/v10/icons/home_v2_inexistent.png');
-		$this->assertEquals('', $res);
-
-		$res = Utility::getMimeType(Plugin::path('Tools') . 'tests' . DS . 'test_files' . DS . 'img' . DS . 'hotel.jpg');
-		$this->assertEquals('image/jpeg', $res);
-	}
-
-	/**
 	 * UtilityTest::testFileExists()
 	 *
 	 * @covers Utility::fileExists