Skip to content

Commit

Permalink
Merge branch '2.x' into 2.next
Browse files Browse the repository at this point in the history
  • Loading branch information
markstory committed Oct 28, 2016
2 parents cf7473a + 1a58d15 commit 135a24e
Show file tree
Hide file tree
Showing 25 changed files with 444 additions and 87 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -14,6 +14,9 @@
#################################
/nbproject
.idea
/.project
/.buildpath
/.settings/

# OS generated files #
######################
Expand Down
14 changes: 0 additions & 14 deletions app/View/Elements/Flash/default.ctp
@@ -1,15 +1 @@
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package app.View.Emails.html
* @since CakePHP(tm) v 0.10.0.1076
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
<div id="<?php echo $key; ?>Message" class="<?php echo !empty($params['class']) ? $params['class'] : 'message'; ?>"><?php echo $message; ?></div>
2 changes: 1 addition & 1 deletion app/composer.json
Expand Up @@ -23,7 +23,7 @@
},
"require-dev": {
"phpunit/phpunit": "3.7.*",
"cakephp/cakephp": "~2.8"
"cakephp/cakephp": "~2.9"
},
"suggest": {
"cakephp/cakephp-codesniffer": "Easily check code formatting against the CakePHP coding standards."
Expand Down
2 changes: 1 addition & 1 deletion lib/Cake/Console/ShellDispatcher.php
Expand Up @@ -134,7 +134,7 @@ protected function _bootstrap() {
if (!defined('TMP') && !is_dir(APP . 'tmp')) {
define('TMP', CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'Templates' . DS . 'skel' . DS . 'tmp' . DS);
}
$boot = file_exists(ROOT . DS . APP_DIR . DS . 'Config' . DS . 'bootstrap.php');

require CORE_PATH . 'Cake' . DS . 'bootstrap.php';

if (!file_exists(APP . 'Config' . DS . 'core.php')) {
Expand Down
6 changes: 6 additions & 0 deletions lib/Cake/Model/CakeSchema.php
Expand Up @@ -403,8 +403,14 @@ public function write($object, $options = array()) {
* @param string $table Table name you want returned.
* @param array $fields Array of field information to generate the table with.
* @return string Variable declaration for a schema class.
* @throws Exception
*/
public function generateTable($table, $fields) {
// Valid var name regex (http://www.php.net/manual/en/language.variables.basics.php)
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $table)) {
throw new Exception("Invalid table name '{$table}'");
}

$out = "\tpublic \${$table} = array(\n";
if (is_array($fields)) {
$cols = array();
Expand Down
10 changes: 5 additions & 5 deletions lib/Cake/Model/Datasource/CakeSession.php
Expand Up @@ -230,9 +230,12 @@ public static function started() {
* @return bool True if variable is there
*/
public static function check($name) {
if (empty($name) || !static::_hasSession() || !static::start()) {
if (!static::_hasSession() || !static::start()) {
return false;
}
if (isset($_SESSION[$name])) {
return true;
}

return Hash::get($_SESSION, $name) !== null;
}
Expand Down Expand Up @@ -380,9 +383,6 @@ public static function userAgent($userAgent = null) {
* session not started, or provided name not found in the session, false on failure.
*/
public static function read($name = null) {
if (empty($name) && $name !== null) {
return null;
}
if (!static::_hasSession() || !static::start()) {
return null;
}
Expand Down Expand Up @@ -418,7 +418,7 @@ protected static function _returnSessionVars() {
* @return bool True if the write was successful, false if the write failed
*/
public static function write($name, $value = null) {
if (empty($name) || !static::start()) {
if (!static::start()) {
return false;
}

Expand Down
53 changes: 53 additions & 0 deletions lib/Cake/Model/Datasource/Database/Mysql.php
Expand Up @@ -849,4 +849,57 @@ protected function _unsigned($real) {
return strpos(strtolower($real), 'unsigned') !== false;
}

/**
* Inserts multiple values into a table. Uses a single query in order to insert
* multiple rows.
*
* @param string $table The table being inserted into.
* @param array $fields The array of field/column names being inserted.
* @param array $values The array of values to insert. The values should
* be an array of rows. Each row should have values keyed by the column name.
* Each row must have the values in the same order as $fields.
* @return bool
*/
public function insertMulti($table, $fields, $values) {
$table = $this->fullTableName($table);
$holder = implode(', ', array_fill(0, count($fields), '?'));
$fields = implode(', ', array_map(array($this, 'name'), $fields));
$pdoMap = array(
'integer' => PDO::PARAM_INT,
'float' => PDO::PARAM_STR,
'boolean' => PDO::PARAM_BOOL,
'string' => PDO::PARAM_STR,
'text' => PDO::PARAM_STR
);
$columnMap = array();
$rowHolder = "({$holder})";
$sql = "INSERT INTO {$table} ({$fields}) VALUES ";
$countRows = count($values);
for ($i = 0; $i < $countRows; $i++) {
if ($i !== 0) {
$sql .= ',';
}
$sql .= " $rowHolder";
}
$statement = $this->_connection->prepare($sql);
foreach ($values[key($values)] as $key => $val) {
$type = $this->introspectType($val);
$columnMap[$key] = $pdoMap[$type];
}
$valuesList = array();
$i = 1;
foreach ($values as $value) {
foreach ($value as $col => $val) {
$valuesList[] = $val;
$statement->bindValue($i, $val, $columnMap[$col]);
$i++;
}
}
$result = $statement->execute();
$statement->closeCursor();
if ($this->fullDebug) {
$this->logQuery($sql, $valuesList);
}
return $result;
}
}
13 changes: 4 additions & 9 deletions lib/Cake/Model/Datasource/Database/Postgres.php
Expand Up @@ -727,19 +727,14 @@ public function column($real) {
* @return int An integer representing the length of the column
*/
public function length($real) {
$col = str_replace(array(')', 'unsigned'), '', $real);
$limit = null;

if (strpos($col, '(') !== false) {
list($col, $limit) = explode('(', $col);
$col = $real;
if (strpos($real, '(') !== false) {
list($col, $limit) = explode('(', $real);
}
if ($col === 'uuid') {
return 36;
}
if ($limit) {
return (int)$limit;
}
return null;
return parent::length($real);
}

/**
Expand Down
57 changes: 24 additions & 33 deletions lib/Cake/Model/Datasource/DboSource.php
Expand Up @@ -3097,54 +3097,45 @@ public function hasAny(Model $Model, $sql) {
* @return mixed An integer or string representing the length of the column, or null for unknown length.
*/
public function length($real) {
if (!preg_match_all('/([\w\s]+)(?:\((\d+)(?:,(\d+))?\))?(\sunsigned)?(\szerofill)?/', $real, $result)) {
$col = str_replace(array(')', 'unsigned'), '', $real);
$limit = null;

if (strpos($col, '(') !== false) {
list($col, $limit) = explode('(', $col);
}
if ($limit !== null) {
return (int)$limit;
}
return null;
}

preg_match('/([\w\s]+)(?:\((.+?)\))?(\sunsigned)?/i', $real, $result);
$types = array(
'int' => 1, 'tinyint' => 1, 'smallint' => 1, 'mediumint' => 1, 'integer' => 1, 'bigint' => 1
);

list($real, $type, $length, $offset, $sign) = $result;
$typeArr = $type;
$type = $type[0];
$length = $length[0];
$offset = $offset[0];
$type = $length = null;
if (isset($result[1])) {
$type = $result[1];
}
if (isset($result[2])) {
$length = $result[2];
}
$sign = isset($result[3]);

$isFloat = in_array($type, array('dec', 'decimal', 'float', 'numeric', 'double'));
if ($isFloat && $offset) {
return $length . ',' . $offset;
if ($isFloat && strpos($length, ',') !== false) {
return $length;
}

if (($real[0] == $type) && (count($real) === 1)) {
if ($length === null) {
return null;
}

if (isset($types[$type])) {
$length += $types[$type];
if (!empty($sign)) {
$length--;
}
} elseif (in_array($type, array('enum', 'set'))) {
$length = 0;
foreach ($typeArr as $key => $enumValue) {
if ($key === 0) {
continue;
}
return (int)$length;
}
if (in_array($type, array('enum', 'set'))) {
$values = array_map(function ($value) {
return trim(trim($value), '\'"');
}, explode(',', $length));

$maxLength = 0;
foreach ($values as $key => $enumValue) {
$tmpLength = strlen($enumValue);
if ($tmpLength > $length) {
$length = $tmpLength;
if ($tmpLength > $maxLength) {
$maxLength = $tmpLength;
}
}
return $maxLength;
}
return (int)$length;
}
Expand Down
18 changes: 16 additions & 2 deletions lib/Cake/Model/Model.php
Expand Up @@ -473,9 +473,16 @@ class Model extends CakeObject implements CakeEventListener {

/**
* List of behaviors to load when the model object is initialized. Settings can be
* passed to behaviors by using the behavior name as index. Eg:
* passed to behaviors by using the behavior name as index.
*
* public $actsAs = array('Translate', 'MyBehavior' => array('setting1' => 'value1'))
* For example:
*
* ```
* public $actsAs = array(
* 'Translate',
* 'MyBehavior' => array('setting1' => 'value1')
* );
* ```
*
* @var array
* @link http://book.cakephp.org/2.0/en/models/behaviors.html#using-behaviors
Expand Down Expand Up @@ -3446,12 +3453,19 @@ public function isUnique($fields, $or = true) {
* - 3rd param: If 2nd argument is provided, a boolean flag for enabling/disabled
* query caching.
*
* If the query cache param as 2nd or 3rd argument is not given then the model's
* default `$cacheQueries` value is used.
*
* @param string $sql SQL statement
* @return mixed Resultset array or boolean indicating success / failure depending on the query executed
* @link http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#model-query
*/
public function query($sql) {
$params = func_get_args();
// use $this->cacheQueries as default when argument not explicitly given already
if (count($params) === 1 || count($params) === 2 && !is_bool($params[1])) {
$params[] = $this->cacheQueries;
}
$db = $this->getDataSource();
return call_user_func_array(array(&$db, 'query'), $params);
}
Expand Down
1 change: 1 addition & 0 deletions lib/Cake/Routing/Router.php
Expand Up @@ -523,6 +523,7 @@ public static function namedConfig() {
* - 'id' - The regular expression fragment to use when matching IDs. By default, matches
* integer values and UUIDs.
* - 'prefix' - URL prefix to use for the generated routes. Defaults to '/'.
* - 'connectOptions' – Custom options for connecting the routes.
*
* @param string|array $controller A controller name or array of controller names (i.e. "Posts" or "ListItems")
* @param array $options Options to use when generating REST routes
Expand Down
16 changes: 16 additions & 0 deletions lib/Cake/Test/Case/Model/CakeSchemaTest.php
Expand Up @@ -686,6 +686,22 @@ public function testGenerateTable() {
$this->assertRegExp('/\'type\' \=\> \'fulltext\'/', $result);
}

/**
* test that tables with unsupported name are not getting through
*
* @return void
*/
public function testGenerateInvalidTable() {
$invalidTableName = 'invalid name !@#$%^&*()';
$expectedException = "Invalid table name '{$invalidTableName}'";
try{
$this->Schema->generateTable($invalidTableName, array());
$this->fail("Expected exception \"{$expectedException}\" not thrown");
} catch (Exception $e) {
$this->assertEquals($expectedException, $e->getMessage());
}
}

/**
* testSchemaWrite method
*
Expand Down
23 changes: 19 additions & 4 deletions lib/Cake/Test/Case/Model/Datasource/CakeSessionTest.php
Expand Up @@ -307,9 +307,9 @@ public function testWriteArray() {
* @return void
*/
public function testWriteEmptyKey() {
$this->assertFalse(TestCakeSession::write('', 'graham'));
$this->assertFalse(TestCakeSession::write('', ''));
$this->assertFalse(TestCakeSession::write(''));
$this->assertTrue(TestCakeSession::write('', 'graham'));
$this->assertTrue(TestCakeSession::write('', ''));
$this->assertTrue(TestCakeSession::write(''));
}

/**
Expand Down Expand Up @@ -403,6 +403,17 @@ public function testDelete() {
$this->assertFalse(TestCakeSession::check('Clearing'));
}

/**
* test delete
*
* @return void
*/
public function testDeleteEmptyString() {
TestCakeSession::write('', 'empty string');
$this->assertTrue(TestCakeSession::delete(''));
$this->assertFalse(TestCakeSession::check(''));
}

/**
* testClear method
*
Expand Down Expand Up @@ -500,6 +511,10 @@ public function testKeyExploit() {
* @return void
*/
public function testReadingSavedEmpty() {
TestCakeSession::write('', 'empty string');
$this->assertTrue(TestCakeSession::check(''));
$this->assertEquals('empty string', TestCakeSession::read(''));

TestCakeSession::write('SessionTestCase', 0);
$this->assertEquals(0, TestCakeSession::read('SessionTestCase'));

Expand All @@ -511,7 +526,7 @@ public function testReadingSavedEmpty() {
$this->assertFalse(TestCakeSession::read('SessionTestCase'));

TestCakeSession::write('SessionTestCase', null);
$this->assertEquals(null, TestCakeSession::read('SessionTestCase'));
$this->assertNull(TestCakeSession::read('SessionTestCase'));
}

/**
Expand Down

0 comments on commit 135a24e

Please sign in to comment.