Merge branch '2.6' into 2.7

This commit is contained in:
mark_story 2015-03-23 22:50:09 -04:00
commit 3151c53255
20 changed files with 284 additions and 24 deletions

View file

@ -104,7 +104,7 @@ class MemcacheEngine extends CacheEngine {
* @return array Array containing host, port * @return array Array containing host, port
*/ */
protected function _parseServerString($server) { protected function _parseServerString($server) {
if ($server[0] === 'u') { if (strpos($server, 'unix://') === 0) {
return array($server, 0); return array($server, 0);
} }
if (substr($server, 0, 1) === '[') { if (substr($server, 0, 1) === '[') {

View file

@ -185,7 +185,7 @@ class MemcachedEngine extends CacheEngine {
* @return array Array containing host, port * @return array Array containing host, port
*/ */
protected function _parseServerString($server) { protected function _parseServerString($server) {
if ($server[0] === 'u') { if (strpos($server, 'unix://') === 0) {
return array($server, 0); return array($server, 0);
} }
if (substr($server, 0, 1) === '[') { if (substr($server, 0, 1) === '[') {

View file

@ -448,7 +448,7 @@ class ExtractTask extends AppShell {
if ($categoryName !== 'LC_TIME') { if ($categoryName !== 'LC_TIME') {
$this->_addTranslation($categoryName, $domain, $singular, $details); $this->_addTranslation($categoryName, $domain, $singular, $details);
} }
} else { } elseif (!is_array($this->_tokens[$count - 1]) || $this->_tokens[$count - 1][0] != T_FUNCTION) {
$this->_markerError($this->_file, $line, $functionName, $count); $this->_markerError($this->_file, $line, $functionName, $count);
} }
} }

View file

@ -1,7 +1,5 @@
<?php <?php
/** /**
* The Plugin Task handles creating an empty plugin, ready to be used
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org) * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* *

View file

@ -875,10 +875,12 @@ class App {
'Vendor' => array( 'Vendor' => array(
'%s' . 'Vendor' . DS, '%s' . 'Vendor' . DS,
ROOT . DS . 'vendors' . DS, ROOT . DS . 'vendors' . DS,
dirname(dirname(CAKE)) . DS . 'vendors' . DS
), ),
'Plugin' => array( 'Plugin' => array(
APP . 'Plugin' . DS, APP . 'Plugin' . DS,
ROOT . DS . 'plugins' . DS ROOT . DS . 'plugins' . DS,
dirname(dirname(CAKE)) . DS . 'plugins' . DS
) )
); );
} }

View file

@ -1,7 +1,5 @@
<?php <?php
/** /**
* PostgreSQL layer for DBO.
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org) * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* *
@ -558,7 +556,11 @@ class Postgres extends DboSource {
$colList[] = 'ALTER COLUMN ' . $fieldName . ' SET DEFAULT NULL'; $colList[] = 'ALTER COLUMN ' . $fieldName . ' SET DEFAULT NULL';
$colList[] = 'ALTER COLUMN ' . $fieldName . ' TYPE ' . str_replace(array($fieldName, 'NOT NULL'), '', $this->buildColumn($col)) . ' USING CASE WHEN TRUE THEN 1 ELSE 0 END'; $colList[] = 'ALTER COLUMN ' . $fieldName . ' TYPE ' . str_replace(array($fieldName, 'NOT NULL'), '', $this->buildColumn($col)) . ' USING CASE WHEN TRUE THEN 1 ELSE 0 END';
} else { } else {
$colList[] = 'ALTER COLUMN ' . $fieldName . ' TYPE ' . str_replace(array($fieldName, 'NOT NULL'), '', $this->buildColumn($col)); if ($original['type'] === 'text' && $col['type'] === 'integer') {
$colList[] = 'ALTER COLUMN ' . $fieldName . ' TYPE ' . str_replace(array($fieldName, 'NOT NULL'), '', $this->buildColumn($col)) . " USING cast({$fieldName} as INTEGER)";
} else {
$colList[] = 'ALTER COLUMN ' . $fieldName . ' TYPE ' . str_replace(array($fieldName, 'NOT NULL'), '', $this->buildColumn($col));
}
} }
if (isset($nullable)) { if (isset($nullable)) {

View file

@ -130,7 +130,7 @@ class CakeSocket {
} }
$scheme = null; $scheme = null;
if (!empty($this->config['protocol']) && strpos($this->config['host'], '://') === false) { if (!empty($this->config['protocol']) && strpos($this->config['host'], '://') === false && empty($this->config['proxy'])) {
$scheme = $this->config['protocol'] . '://'; $scheme = $this->config['protocol'] . '://';
} }
@ -169,6 +169,28 @@ class CakeSocket {
$this->connected = is_resource($this->connection); $this->connected = is_resource($this->connection);
if ($this->connected) { if ($this->connected) {
stream_set_timeout($this->connection, $this->config['timeout']); stream_set_timeout($this->connection, $this->config['timeout']);
if (!empty($this->config['request']) &&
$this->config['request']['uri']['scheme'] === 'https' &&
!empty($this->config['proxy'])
) {
$req = array();
$req[] = 'CONNECT ' . $this->config['request']['uri']['host'] . ':' .
$this->config['request']['uri']['port'] . ' HTTP/1.1';
$req[] = 'Host: ' . $this->config['host'];
$req[] = 'User-Agent: php proxy';
fwrite($this->connection, implode("\r\n", $req) . "\r\n\r\n");
while (!feof($this->connection)) {
$s = rtrim(fgets($this->connection, 4096));
if (preg_match('/^$/', $s)) {
break;
}
}
$this->enableCrypto('tls', 'client');
}
} }
return $this->connected; return $this->connected;
} }

View file

@ -652,6 +652,7 @@ class HttpSocket extends CakeSocket {
} }
$this->config['host'] = $this->_proxy['host']; $this->config['host'] = $this->_proxy['host'];
$this->config['port'] = $this->_proxy['port']; $this->config['port'] = $this->_proxy['port'];
$this->config['proxy'] = true;
if (empty($this->_proxy['method']) || !isset($this->_proxy['user'], $this->_proxy['pass'])) { if (empty($this->_proxy['method']) || !isset($this->_proxy['user'], $this->_proxy['pass'])) {
return; return;
@ -717,6 +718,20 @@ class HttpSocket extends CakeSocket {
} }
unset($this->config[$key]); unset($this->config[$key]);
} }
if (version_compare(PHP_VERSION, '5.3.2', '>=')) {
if (empty($this->config['context']['ssl']['SNI_enabled'])) {
$this->config['context']['ssl']['SNI_enabled'] = true;
}
if (version_compare(PHP_VERSION, '5.6.0', '>=')) {
if (empty($this->config['context']['ssl']['peer_name'])) {
$this->config['context']['ssl']['peer_name'] = $host;
}
} else {
if (empty($this->config['context']['ssl']['SNI_server_name'])) {
$this->config['context']['ssl']['SNI_server_name'] = $host;
}
}
}
if (empty($this->config['context']['ssl']['cafile'])) { if (empty($this->config['context']['ssl']['cafile'])) {
$this->config['context']['ssl']['cafile'] = CAKE . 'Config' . DS . 'cacert.pem'; $this->config['context']['ssl']['cafile'] = CAKE . 'Config' . DS . 'cacert.pem';
} }
@ -926,7 +941,7 @@ class HttpSocket extends CakeSocket {
$request['uri'] = $this->_parseUri($request['uri']); $request['uri'] = $this->_parseUri($request['uri']);
$request += array('method' => 'GET'); $request += array('method' => 'GET');
if (!empty($this->_proxy['host'])) { if (!empty($this->_proxy['host']) && $request['uri']['scheme'] !== 'https') {
$request['uri'] = $this->_buildUri($request['uri'], '%scheme://%host:%port/%path?%query'); $request['uri'] = $this->_buildUri($request['uri'], '%scheme://%host:%port/%path?%query');
} else { } else {
$request['uri'] = $this->_buildUri($request['uri'], '/%path?%query'); $request['uri'] = $this->_buildUri($request['uri'], '/%path?%query');

View file

@ -161,6 +161,17 @@ class MemcacheEngineTest extends CakeTestCase {
$this->assertTrue($result); $this->assertTrue($result);
} }
/**
* test domain starts with u
*
* @return void
*/
public function testParseServerStringWithU() {
$Memcached = new TestMemcachedEngine();
$result = $Memcached->parseServerString('udomain.net:13211');
$this->assertEquals(array('udomain.net', '13211'), $result);
}
/** /**
* test non latin domains. * test non latin domains.
* *

View file

@ -400,6 +400,17 @@ class MemcachedEngineTest extends CakeTestCase {
$this->assertTrue($result); $this->assertTrue($result);
} }
/**
* test domain starts with u
*
* @return void
*/
public function testParseServerStringWithU() {
$Memcached = new TestMemcachedEngine();
$result = $Memcached->parseServerString('udomain.net:13211');
$this->assertEquals(array('udomain.net', '13211'), $result);
}
/** /**
* test non latin domains. * test non latin domains.
* *

View file

@ -58,7 +58,7 @@ class PluginTaskTest extends CakeTestCase {
array_splice($paths, $i, 1); array_splice($paths, $i, 1);
} }
} }
$this->_testPath = array_push($paths, TMP . 'tests' . DS); $this->_testPath = array_push($paths, TMP . 'tests' . DS) - 1;
App::build(array('plugins' => $paths)); App::build(array('plugins' => $paths));
} }
@ -80,17 +80,23 @@ class PluginTaskTest extends CakeTestCase {
* @return void * @return void
*/ */
public function testBakeFoldersAndFiles() { public function testBakeFoldersAndFiles() {
$this->Task->expects($this->at(0))->method('in')->will($this->returnValue($this->_testPath)); $this->Task->expects($this->at(0))
$this->Task->expects($this->at(1))->method('in')->will($this->returnValue('y')); ->method('in')
->will($this->returnValue($this->_testPath));
$this->Task->expects($this->at(1))
->method('in')
->will($this->returnValue('y'));
$path = $this->Task->path . 'BakeTestPlugin'; $path = $this->Task->path . 'BakeTestPlugin';
$file = $path . DS . 'Controller' . DS . 'BakeTestPluginAppController.php'; $file = $path . DS . 'Controller' . DS . 'BakeTestPluginAppController.php';
$this->Task->expects($this->at(2))->method('createFile') $this->Task->expects($this->at(2))
->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything()); ->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$file = $path . DS . 'Model' . DS . 'BakeTestPluginAppModel.php'; $file = $path . DS . 'Model' . DS . 'BakeTestPluginAppModel.php';
$this->Task->expects($this->at(3))->method('createFile') $this->Task->expects($this->at(3))
->method('createFile')
->with($file, new PHPUnit_Framework_Constraint_IsAnything()); ->with($file, new PHPUnit_Framework_Constraint_IsAnything());
$this->Task->bake('BakeTestPlugin'); $this->Task->bake('BakeTestPlugin');

View file

@ -731,6 +731,42 @@ class PostgresTest extends CakeTestCase {
$this->Dbo->query($this->Dbo->dropSchema($Old)); $this->Dbo->query($this->Dbo->dropSchema($Old));
} }
/**
* Test the alterSchema changing text to integer
*
* @return void
*/
public function testAlterSchemaTextToIntegerField() {
$default = array(
'connection' => 'test',
'name' => 'TextField',
'text_fields' => array(
'id' => array('type' => 'integer', 'key' => 'primary'),
'name' => array('type' => 'string', 'length' => 50),
'active' => array('type' => 'text', 'null' => false),
)
);
$Old = new CakeSchema($default);
$result = $this->Dbo->query($this->Dbo->createSchema($Old));
$this->assertTrue($result);
$modified = $default;
$modified['text_fields']['active'] = array('type' => 'integer', 'null' => true);
$New = new CakeSchema($modified);
$this->Dbo->query($this->Dbo->alterSchema($New->compare($Old)));
$result = $this->Dbo->describe('text_fields');
$this->Dbo->query($this->Dbo->dropSchema($Old));
$expected = array(
'type' => 'integer',
'null' => true,
'default' => null,
'length' => null,
);
$this->assertEquals($expected, $result['active']);
}
/** /**
* Test the alter index capabilities of postgres * Test the alter index capabilities of postgres
* *

View file

@ -317,11 +317,18 @@ class HttpSocketTest extends CakeTestCase {
'verify_peer' => true, 'verify_peer' => true,
'allow_self_signed' => false, 'allow_self_signed' => false,
'verify_depth' => 5, 'verify_depth' => 5,
'SNI_enabled' => true,
'CN_match' => 'www.cakephp.org', 'CN_match' => 'www.cakephp.org',
'cafile' => CAKE . 'Config' . DS . 'cacert.pem' 'cafile' => CAKE . 'Config' . DS . 'cacert.pem'
) )
); );
if (version_compare(PHP_VERSION, '5.6.0', '>=')) {
$context['ssl']['peer_name'] = 'www.cakephp.org';
} else {
$context['ssl']['SNI_server_name'] = 'www.cakephp.org';
}
$tests = array( $tests = array(
array( array(
'request' => 'http://www.cakephp.org/?foo=bar', 'request' => 'http://www.cakephp.org/?foo=bar',

View file

@ -8642,6 +8642,7 @@ class FormHelperTest extends CakeTestCase {
'escape' => false, 'escape' => false,
'url' => array( 'url' => array(
'action' => 'edit', 'action' => 'edit',
'0',
'myparam' 'myparam'
) )
)); ));
@ -8649,7 +8650,7 @@ class FormHelperTest extends CakeTestCase {
'form' => array( 'form' => array(
'id' => 'ContactAddForm', 'id' => 'ContactAddForm',
'method' => 'post', 'method' => 'post',
'action' => '/contacts/edit/myparam', 'action' => '/contacts/edit/0/myparam',
'accept-charset' => $encoding 'accept-charset' => $encoding
), ),
'div' => array('style' => 'display:none;'), 'div' => array('style' => 'display:none;'),
@ -8667,8 +8668,8 @@ class FormHelperTest extends CakeTestCase {
public function testCreateNoErrorsWithMockModel() { public function testCreateNoErrorsWithMockModel() {
$encoding = strtolower(Configure::read('App.encoding')); $encoding = strtolower(Configure::read('App.encoding'));
$ContactMock = $this->getMockBuilder('Contact') $ContactMock = $this->getMockBuilder('Contact')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
ClassRegistry::removeObject('Contact'); ClassRegistry::removeObject('Contact');
ClassRegistry::addObject('Contact', $ContactMock); ClassRegistry::addObject('Contact', $ContactMock);
$result = $this->Form->create('Contact', array('type' => 'GET')); $result = $this->Form->create('Contact', array('type' => 'GET'));

View file

@ -1260,6 +1260,14 @@ class PaginatorHelperTest extends CakeTestCase {
'paramType' => 'named' 'paramType' => 'named'
) )
); );
$result = $this->Paginator->sort('title', 'Title', array('model' => 'Client'));
$expected = array(
'a' => array('href' => '/index/sort:title/direction:asc'),
'Title',
'/a'
);
$this->assertTags($result, $expected);
$result = $this->Paginator->next('Next', array('model' => 'Client')); $result = $this->Paginator->next('Next', array('model' => 'Client'));
$expected = array( $expected = array(
'span' => array('class' => 'next'), 'span' => array('class' => 'next'),
@ -1277,6 +1285,39 @@ class PaginatorHelperTest extends CakeTestCase {
$this->assertTags($result, $expected); $this->assertTags($result, $expected);
} }
/**
* Test creating paging links for missing models.
*
* @return void
*/
public function testPagingLinksMissingModel() {
$result = $this->Paginator->sort('title', 'Title', array('model' => 'Missing'));
$expected = array(
'a' => array('href' => '/index/sort:title/direction:asc'),
'Title',
'/a'
);
$this->assertTags($result, $expected);
$result = $this->Paginator->next('Next', array('model' => 'Missing'));
$expected = array(
'span' => array('class' => 'next'),
'a' => array('href' => '/index/page:2', 'rel' => 'next'),
'Next',
'/a',
'/span'
);
$this->assertTags($result, $expected);
$result = $this->Paginator->prev('Prev', array('model' => 'Missing'));
$expected = array(
'span' => array('class' => 'prev'),
'Prev',
'/span'
);
$this->assertTags($result, $expected);
}
/** /**
* testGenericLinks method * testGenericLinks method
* *

View file

@ -28,6 +28,11 @@ App::uses('JsonView', 'View');
*/ */
class JsonViewTest extends CakeTestCase { class JsonViewTest extends CakeTestCase {
/**
* setUp method
*
* @return void
**/
public function setUp() { public function setUp() {
parent::setUp(); parent::setUp();
Configure::write('debug', 0); Configure::write('debug', 0);
@ -156,6 +161,20 @@ class JsonViewTest extends CakeTestCase {
); );
} }
/**
* Custom error handler for use while testing methods that use json_encode
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @param array $errcontext
* @return void
* @throws CakeException
**/
public function jsonEncodeErrorHandler($errno, $errstr, $errfile, $errline, $errcontext) {
throw new CakeException($errstr, 0, $errno, $errfile, $errline);
}
/** /**
* Test render with a valid string in _serialize. * Test render with a valid string in _serialize.
* *
@ -306,4 +325,56 @@ class JsonViewTest extends CakeTestCase {
$this->assertSame($expected, $output); $this->assertSame($expected, $output);
$this->assertSame('application/javascript', $Response->type()); $this->assertSame('application/javascript', $Response->type());
} }
/**
* JsonViewTest::testRenderInvalidJSON()
*
* @return void
*/
public function testRenderInvalidJSON() {
$Request = new CakeRequest();
$Response = new CakeResponse();
$Controller = new Controller($Request, $Response);
// non utf-8 stuff
$data = array('data' => array('foo' => 'bar' . chr('0x97')));
$Controller->set($data);
$Controller->set('_serialize', 'data');
$View = new JsonView($Controller);
// Use a custom error handler
set_error_handler(array($this, 'jsonEncodeErrorHandler'));
try {
$View->render();
restore_error_handler();
$this->fail('Failed asserting that exception of type "CakeException" is thrown.');
} catch (CakeException $e) {
restore_error_handler();
$this->assertRegExp('/UTF-8/', $e->getMessage());
return;
}
}
/**
* JsonViewTest::testRenderJSONBoolFalse()
*
* @return void
*/
public function testRenderJSONBoolFalse() {
$Request = new CakeRequest();
$Response = new CakeResponse();
$Controller = new Controller($Request, $Response);
// encoding a false, ensure this doesn't trigger exception
$data = false;
$Controller->set($data);
$Controller->set('_serialize', 'data');
$View = new JsonView($Controller);
$output = $View->render();
$this->assertSame('null', $output);
}
} }

View file

@ -408,7 +408,7 @@ class FormHelper extends AppHelper {
'action' => $options['action'], 'action' => $options['action'],
); );
$options['action'] = array_merge($actionDefaults, (array)$options['url']); $options['action'] = array_merge($actionDefaults, (array)$options['url']);
if (empty($options['action'][0]) && !empty($id)) { if (!isset($options['action'][0]) && !empty($id)) {
$options['action'][0] = $id; $options['action'][0] = $id;
} }
} elseif (is_string($options['url'])) { } elseif (is_string($options['url'])) {

View file

@ -120,7 +120,7 @@ class PaginatorHelper extends AppHelper {
* Gets the current paging parameters from the resultset for the given model * Gets the current paging parameters from the resultset for the given model
* *
* @param string $model Optional model name. Uses the default if none is specified. * @param string $model Optional model name. Uses the default if none is specified.
* @return array|null The array of paging parameters for the paginated resultset. * @return array The array of paging parameters for the paginated resultset.
* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/paginator.html#PaginatorHelper::params * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/paginator.html#PaginatorHelper::params
*/ */
public function params($model = null) { public function params($model = null) {
@ -128,7 +128,14 @@ class PaginatorHelper extends AppHelper {
$model = $this->defaultModel(); $model = $this->defaultModel();
} }
if (!isset($this->request->params['paging']) || empty($this->request->params['paging'][$model])) { if (!isset($this->request->params['paging']) || empty($this->request->params['paging'][$model])) {
return null; return array(
'prevPage' => false,
'nextPage' => true,
'paramType' => 'named',
'pageCount' => 1,
'options' => array(),
'page' => 1
);
} }
return $this->request->params['paging'][$model]; return $this->request->params['paging'][$model];
} }

View file

@ -126,6 +126,7 @@ class JsonView extends View {
* Serialize view vars * Serialize view vars
* *
* @param array $serialize The viewVars that need to be serialized * @param array $serialize The viewVars that need to be serialized
* @throws CakeException
* @return string The serialized data * @return string The serialized data
*/ */
protected function _serialize($serialize) { protected function _serialize($serialize) {
@ -145,10 +146,17 @@ class JsonView extends View {
} }
if (version_compare(PHP_VERSION, '5.4.0', '>=') && Configure::read('debug')) { if (version_compare(PHP_VERSION, '5.4.0', '>=') && Configure::read('debug')) {
return json_encode($data, JSON_PRETTY_PRINT); $json = json_encode($data, JSON_PRETTY_PRINT);
} else {
$json = json_encode($data);
} }
return json_encode($data); if (function_exists('json_last_error') && json_last_error() !== JSON_ERROR_NONE) {
throw new CakeException(json_last_error_msg());
} elseif ($json === false) {
throw new CakeException('Failed to parse JSON');
}
return $json;
} }
} }

View file

@ -1061,3 +1061,25 @@ if (!function_exists('convertSlash')) {
} }
} }
if (!function_exists('json_last_error_msg')) {
/**
* Provides the fallback implementation of json_last_error_msg() available in PHP 5.5 and above.
*
* @return string Error message.
*/
function json_last_error_msg() {
static $errors = array(
JSON_ERROR_NONE => '',
JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
JSON_ERROR_SYNTAX => 'Syntax error',
JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
);
$error = json_last_error();
return array_key_exists($error, $errors) ? $errors[$error] : "Unknown error ({$error})";
}
}