mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2024-11-15 03:18:26 +00:00
Merge branch 'master' into 2.3
Conflicts: lib/Cake/VERSION.txt
This commit is contained in:
commit
3c6b50953b
28 changed files with 390 additions and 49 deletions
|
@ -414,7 +414,7 @@ class ModelTask extends BakeTask {
|
|||
for ($i = 1, $m = $defaultChoice / 2; $i < $m; $i++) {
|
||||
$line = sprintf("%2d. %s", $i, $this->_validations[$i]);
|
||||
$optionText .= $line . str_repeat(" ", 31 - strlen($line));
|
||||
$optionText .= sprintf("%2d. %s", $m + $i, $this->_validations[$m + $i]);
|
||||
$optionText .= sprintf("%2d. %s\n", $m + $i, $this->_validations[$m + $i]);
|
||||
}
|
||||
$this->out($optionText);
|
||||
$this->out(__d('cake_console', "%s - Do not do any validation on this field.", $defaultChoice));
|
||||
|
|
|
@ -165,23 +165,13 @@ class Shell extends Object {
|
|||
if ($this->stdout == null) {
|
||||
$this->stdout = new ConsoleOutput('php://stdout');
|
||||
}
|
||||
CakeLog::config('stdout', array(
|
||||
'engine' => 'ConsoleLog',
|
||||
'types' => array('notice', 'info'),
|
||||
'stream' => $this->stdout,
|
||||
));
|
||||
if ($this->stderr == null) {
|
||||
$this->stderr = new ConsoleOutput('php://stderr');
|
||||
}
|
||||
CakeLog::config('stderr', array(
|
||||
'engine' => 'ConsoleLog',
|
||||
'types' => array('emergency', 'alert', 'critical', 'error', 'warning', 'debug'),
|
||||
'stream' => $this->stderr,
|
||||
));
|
||||
if ($this->stdin == null) {
|
||||
$this->stdin = new ConsoleInput('php://stdin');
|
||||
}
|
||||
|
||||
$this->_useLogger();
|
||||
$parent = get_parent_class($this);
|
||||
if ($this->tasks !== null && $this->tasks !== false) {
|
||||
$this->_mergeVars(array('tasks'), $parent, true);
|
||||
|
@ -379,6 +369,10 @@ class Shell extends Object {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!empty($this->params['quiet'])) {
|
||||
$this->_useLogger(false);
|
||||
}
|
||||
|
||||
$this->command = $command;
|
||||
if (!empty($this->params['help'])) {
|
||||
return $this->_displayHelp($command);
|
||||
|
@ -825,4 +819,29 @@ class Shell extends Object {
|
|||
return current(App::path('plugins')) . $pluginName . DS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to enable or disable logging stream output to stdout and stderr
|
||||
* If you don't wish to see in your stdout or stderr everything that is logged
|
||||
* through CakeLog, call this function with first param as false
|
||||
*
|
||||
* @param boolean $enable wheter to enable CakeLog output or not
|
||||
* @return void
|
||||
**/
|
||||
protected function _useLogger($enable = true) {
|
||||
if (!$enable) {
|
||||
CakeLog::drop('stdout');
|
||||
CakeLog::drop('stderr');
|
||||
return;
|
||||
}
|
||||
CakeLog::config('stdout', array(
|
||||
'engine' => 'ConsoleLog',
|
||||
'types' => array('notice', 'info'),
|
||||
'stream' => $this->stdout,
|
||||
));
|
||||
CakeLog::config('stderr', array(
|
||||
'engine' => 'ConsoleLog',
|
||||
'types' => array('emergency', 'alert', 'critical', 'error', 'warning', 'debug'),
|
||||
'stream' => $this->stderr,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -229,7 +229,7 @@ class SecurityComponent extends Component {
|
|||
}
|
||||
}
|
||||
$this->generateToken($controller->request);
|
||||
if ($isPost) {
|
||||
if ($isPost && is_array($controller->request->data)) {
|
||||
unset($controller->request->data['_Token']);
|
||||
}
|
||||
}
|
||||
|
@ -585,12 +585,13 @@ class SecurityComponent extends Component {
|
|||
* @param string $method Method to execute
|
||||
* @param array $params Parameters to send to method
|
||||
* @return mixed Controller callback method's response
|
||||
* @throws BadRequestException When a the blackholeCallback is not callable.
|
||||
*/
|
||||
protected function _callback(Controller $controller, $method, $params = array()) {
|
||||
if (is_callable(array($controller, $method))) {
|
||||
return call_user_func_array(array(&$controller, $method), empty($params) ? null : $params);
|
||||
} else {
|
||||
return null;
|
||||
throw new BadRequestException(__d('cake_dev', 'The request has been black-holed'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,11 +49,16 @@ class ConsoleLog extends BaseLog {
|
|||
*/
|
||||
public function __construct($config = array()) {
|
||||
parent::__construct($config);
|
||||
if (DS == '\\' && !(bool)env('ANSICON')) {
|
||||
$outputAs = ConsoleOutput::PLAIN;
|
||||
} else {
|
||||
$outputAs = ConsoleOutput::COLOR;
|
||||
}
|
||||
$config = Hash::merge(array(
|
||||
'stream' => 'php://stderr',
|
||||
'types' => null,
|
||||
'scopes' => array(),
|
||||
'outputAs' => ConsoleOutput::COLOR,
|
||||
'outputAs' => $outputAs,
|
||||
), $this->_config);
|
||||
$config = $this->config($config);
|
||||
if ($config['stream'] instanceof ConsoleOutput) {
|
||||
|
|
|
@ -393,6 +393,16 @@ class TranslateBehavior extends ModelBehavior {
|
|||
$conditions = array('model' => $model->alias, 'foreign_key' => $model->id);
|
||||
$RuntimeModel = $this->translateModel($model);
|
||||
|
||||
$fields = array_merge($this->settings[$model->alias], $this->runtime[$model->alias]['fields']);
|
||||
if ($created) {
|
||||
foreach ($fields as $field) {
|
||||
if (!isset($tempData[$field])) {
|
||||
//set the field value to an empty string
|
||||
$tempData[$field] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($tempData as $field => $value) {
|
||||
unset($conditions['content']);
|
||||
$conditions['field'] = $field;
|
||||
|
|
|
@ -124,11 +124,13 @@ class TreeBehavior extends ModelBehavior {
|
|||
*/
|
||||
public function beforeDelete(Model $Model, $cascade = true) {
|
||||
extract($this->settings[$Model->alias]);
|
||||
$data = current($Model->find('first', array(
|
||||
$data = $Model->find('first', array(
|
||||
'conditions' => array($Model->alias . '.' . $Model->primaryKey => $Model->id),
|
||||
'fields' => array($Model->alias . '.' . $left, $Model->alias . '.' . $right),
|
||||
'recursive' => -1)));
|
||||
$this->_deletedRow = $data;
|
||||
'recursive' => -1));
|
||||
if ($data) {
|
||||
$this->_deletedRow = current($data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -369,8 +371,7 @@ class TreeBehavior extends ModelBehavior {
|
|||
$valuePath = array('%s%s', '{n}.tree_prefix', $valuePath);
|
||||
|
||||
} else {
|
||||
$valuePath[0] = '{' . (count($valuePath) - 1) . '}' . $valuePath[0];
|
||||
$valuePath[] = '{n}.tree_prefix';
|
||||
array_unshift($valuePath, '%s' . $valuePath[0], '{n}.tree_prefix');
|
||||
}
|
||||
$order = $Model->alias . '.' . $left . ' asc';
|
||||
$results = $Model->find('all', compact('conditions', 'fields', 'order', 'recursive'));
|
||||
|
|
|
@ -285,6 +285,7 @@ class BehaviorCollection extends ObjectCollection implements CakeEventListener {
|
|||
'Model.beforeFind' => 'trigger',
|
||||
'Model.afterFind' => 'trigger',
|
||||
'Model.beforeValidate' => 'trigger',
|
||||
'Model.afterValidate' => 'trigger',
|
||||
'Model.beforeSave' => 'trigger',
|
||||
'Model.afterSave' => 'trigger',
|
||||
'Model.beforeDelete' => 'trigger',
|
||||
|
|
|
@ -146,6 +146,17 @@ class ModelBehavior extends Object {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* afterValidate is called just after model data was validated, you can use this callback
|
||||
* to perform any data cleanup or preparation if needed
|
||||
*
|
||||
* @param Model $model Model using this behavior
|
||||
* @return mixed False will stop this event from being passed to other behaviors
|
||||
*/
|
||||
public function afterValidate(Model $model) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* beforeSave is called before a model is saved. Returning false from a beforeSave callback
|
||||
* will abort the save operation.
|
||||
|
|
|
@ -175,7 +175,8 @@ class CakeRequest implements ArrayAccess {
|
|||
if (env('HTTP_X_HTTP_METHOD_OVERRIDE')) {
|
||||
$this->data['_method'] = env('HTTP_X_HTTP_METHOD_OVERRIDE');
|
||||
}
|
||||
if (isset($this->data['_method'])) {
|
||||
$isArray = is_array($this->data);
|
||||
if ($isArray && isset($this->data['_method'])) {
|
||||
if (!empty($_SERVER)) {
|
||||
$_SERVER['REQUEST_METHOD'] = $this->data['_method'];
|
||||
} else {
|
||||
|
@ -183,8 +184,7 @@ class CakeRequest implements ArrayAccess {
|
|||
}
|
||||
unset($this->data['_method']);
|
||||
}
|
||||
|
||||
if (isset($this->data['data'])) {
|
||||
if ($isArray && isset($this->data['data'])) {
|
||||
$data = $this->data['data'];
|
||||
if (count($this->data) <= 1) {
|
||||
$this->data = $data;
|
||||
|
|
|
@ -43,7 +43,7 @@ class Dispatcher implements CakeEventListener {
|
|||
/**
|
||||
* Event manager, used to handle dispatcher filters
|
||||
*
|
||||
* @var CakeEventMaanger
|
||||
* @var CakeEventManager
|
||||
*/
|
||||
protected $_eventManager;
|
||||
|
||||
|
@ -62,7 +62,7 @@ class Dispatcher implements CakeEventListener {
|
|||
* Returns the CakeEventManager instance or creates one if none was
|
||||
* creted. Attaches the default listeners and filters
|
||||
*
|
||||
* @return CakeEventmanger
|
||||
* @return CakeEventManager
|
||||
*/
|
||||
public function getEventManager() {
|
||||
if (!$this->_eventManager) {
|
||||
|
|
|
@ -497,9 +497,9 @@ class CakeRoute {
|
|||
$named = array();
|
||||
foreach ($params['named'] as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$flat = Hash::flatten($value, '][');
|
||||
$flat = Hash::flatten($value, '%5D%5B');
|
||||
foreach ($flat as $namedKey => $namedValue) {
|
||||
$named[] = $key . "[$namedKey]" . $separator . rawurlencode($namedValue);
|
||||
$named[] = $key . "%5B{$namedKey}%5D" . $separator . rawurlencode($namedValue);
|
||||
}
|
||||
} else {
|
||||
$named[] = $key . $separator . rawurlencode($value);
|
||||
|
|
|
@ -80,6 +80,10 @@ class ShellTestShell extends Shell {
|
|||
return $this->_mergeVars($properties, $class, $normalize);
|
||||
}
|
||||
|
||||
public function useLogger($enable = true) {
|
||||
$this->_useLogger($enable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -840,4 +844,32 @@ TEXT;
|
|||
$this->assertContains($this->Shell->testMessage, $contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that _useLogger works properly
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
public function testProtectedUseLogger() {
|
||||
CakeLog::drop('stdout');
|
||||
CakeLog::drop('stderr');
|
||||
$this->Shell->useLogger(true);
|
||||
$this->assertNotEmpty(CakeLog::stream('stdout'));
|
||||
$this->assertNotEmpty(CakeLog::stream('stderr'));
|
||||
$this->Shell->useLogger(false);
|
||||
$this->assertFalse(CakeLog::stream('stdout'));
|
||||
$this->assertFalse(CakeLog::stream('stderr'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test file and console and logging quiet output
|
||||
*/
|
||||
public function testQuietLog() {
|
||||
$output = $this->getMock('ConsoleOutput', array(), array(), '', false);
|
||||
$error = $this->getMock('ConsoleOutput', array(), array(), '', false);
|
||||
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
|
||||
$this->Shell = $this->getMock('ShellTestShell', array('_useLogger'), array($output, $error, $in));
|
||||
$this->Shell->expects($this->once())->method('_useLogger')->with(false);
|
||||
$this->Shell->runCommand('foo', array('--quiet'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -107,6 +107,20 @@ class SecurityTestController extends Controller {
|
|||
|
||||
}
|
||||
|
||||
class BrokenCallbackController extends Controller {
|
||||
|
||||
public $name = 'UncallableCallback';
|
||||
|
||||
public $components = array('Session', 'TestSecurity');
|
||||
|
||||
public function index() {
|
||||
}
|
||||
|
||||
protected function _fail() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* SecurityComponentTest class
|
||||
*
|
||||
|
@ -161,6 +175,25 @@ class SecurityComponentTest extends CakeTestCase {
|
|||
unset($this->Controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that requests are still blackholed when controller has incorrect
|
||||
* visibility keyword in the blackhole callback
|
||||
*
|
||||
* @expectedException BadRequestException
|
||||
*/
|
||||
public function testBlackholeWithBrokenCallback() {
|
||||
$request = new CakeRequest('posts/index', false);
|
||||
$request->addParams(array(
|
||||
'controller' => 'posts', 'action' => 'index')
|
||||
);
|
||||
$this->Controller = new BrokenCallbackController($request);
|
||||
$this->Controller->Components->init($this->Controller);
|
||||
$this->Controller->Security = $this->Controller->TestSecurity;
|
||||
$this->Controller->Security->blackHoleCallback = '_fail';
|
||||
$this->Controller->Security->startup($this->Controller);
|
||||
$this->Controller->Security->blackHole($this->Controller, 'csrf');
|
||||
}
|
||||
|
||||
/**
|
||||
* test that initialize can set properties.
|
||||
*
|
||||
|
|
|
@ -116,4 +116,21 @@ class ConsoleLogTest extends CakeTestCase {
|
|||
$this->assertContains($message, $logOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
* test default value of stream 'outputAs'
|
||||
*/
|
||||
public function testDefaultOutputAs() {
|
||||
TestCakeLog::config('test_console_log', array(
|
||||
'engine' => 'TestConsoleLog',
|
||||
));
|
||||
if (DS == '\\' && !(bool)env('ANSICON')) {
|
||||
$expected = ConsoleOutput::PLAIN;
|
||||
} else {
|
||||
$expected = ConsoleOutput::COLOR;
|
||||
}
|
||||
$stream = TestCakeLog::stream('test_console_log');
|
||||
$config = $stream->config();
|
||||
$this->assertEquals($expected, $config['outputAs']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -531,6 +531,34 @@ class TranslateBehaviorTest extends CakeTestCase {
|
|||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that saving only some of the translated fields allows the record to be found again.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSavePartialFields() {
|
||||
$this->loadFixtures('Translate', 'TranslatedItem');
|
||||
|
||||
$TestModel = new TranslatedItem();
|
||||
$TestModel->locale = 'spa';
|
||||
$data = array(
|
||||
'slug' => 'fourth_translated',
|
||||
'title' => 'Leyenda #4',
|
||||
);
|
||||
$TestModel->create($data);
|
||||
$TestModel->save();
|
||||
$result = $TestModel->read();
|
||||
$expected = array(
|
||||
'TranslatedItem' => array(
|
||||
'id' => $TestModel->id,
|
||||
'translated_article_id' => null,
|
||||
'locale' => 'spa',
|
||||
'content' => '',
|
||||
) + $data
|
||||
);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* testSaveUpdate method
|
||||
*
|
||||
|
|
|
@ -914,6 +914,18 @@ class TreeBehaviorNumberTest extends CakeTestCase {
|
|||
$this->assertSame($validTree, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test deleting a record that doesn't exist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDeleteDoesNotExist() {
|
||||
extract($this->settings);
|
||||
$this->Tree = new $modelClass();
|
||||
$this->Tree->initialize(2, 2);
|
||||
$this->Tree->delete(99999);
|
||||
}
|
||||
|
||||
/**
|
||||
* testRemove method
|
||||
*
|
||||
|
@ -1269,6 +1281,26 @@ class TreeBehaviorNumberTest extends CakeTestCase {
|
|||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the formatting options of generateTreeList()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGenerateTreeListFormatting() {
|
||||
extract($this->settings);
|
||||
$this->Tree = new $modelClass();
|
||||
$this->Tree->initialize(2, 2);
|
||||
|
||||
$result = $this->Tree->generateTreeList(
|
||||
null,
|
||||
"{n}.$modelClass.id",
|
||||
array('%s - %s', "{n}.$modelClass.id", "{n}.$modelClass.name")
|
||||
);
|
||||
$this->assertEquals('1 - 1. Root', $result[1]);
|
||||
$this->assertEquals('_2 - 1.1', $result[2]);
|
||||
$this->assertEquals('__3 - 1.1.1', $result[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* testArraySyntax method
|
||||
*
|
||||
|
|
|
@ -194,6 +194,29 @@ class TestBehavior extends ModelBehavior {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* afterValidate method
|
||||
*
|
||||
* @param Model $model
|
||||
* @param bool $cascade
|
||||
* @return void
|
||||
*/
|
||||
public function afterValidate(Model $model) {
|
||||
$settings = $this->settings[$model->alias];
|
||||
if (!isset($settings['afterValidate']) || $settings['afterValidate'] == 'off') {
|
||||
return parent::afterValidate($model);
|
||||
}
|
||||
switch ($settings['afterValidate']) {
|
||||
case 'on':
|
||||
return false;
|
||||
break;
|
||||
case 'test':
|
||||
$model->data = array('foo');
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* beforeDelete method
|
||||
*
|
||||
|
@ -966,6 +989,27 @@ class BehaviorCollectionTest extends CakeTestCase {
|
|||
$this->assertSame($Apple->whitelist, array('unknown', 'name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* testBehaviorValidateAfterCallback method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBehaviorValidateAfterCallback() {
|
||||
$Apple = new Apple();
|
||||
|
||||
$Apple->Behaviors->attach('Test');
|
||||
$this->assertSame($Apple->validates(), true);
|
||||
|
||||
$Apple->Behaviors->attach('Test', array('afterValidate' => 'on'));
|
||||
$this->assertSame($Apple->validates(), true);
|
||||
$this->assertSame($Apple->validationErrors, array());
|
||||
|
||||
$Apple->Behaviors->attach('Test', array('afterValidate' => 'test'));
|
||||
$Apple->data = array('bar');
|
||||
$Apple->validates();
|
||||
$this->assertEquals(array('foo'), $Apple->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* testBehaviorValidateMethods method
|
||||
*
|
||||
|
|
|
@ -73,6 +73,7 @@ class CakeValidationRuleTest extends CakeTestCase {
|
|||
$Rule->process('fieldName', $data, $methods);
|
||||
$this->assertTrue($Rule->isValid());
|
||||
}
|
||||
|
||||
/**
|
||||
* tests that passing custom validation methods work
|
||||
*
|
||||
|
@ -98,6 +99,24 @@ class CakeValidationRuleTest extends CakeTestCase {
|
|||
$this->assertFalse($Rule->isValid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure errors are triggered when validation is missing.
|
||||
*
|
||||
* @expectedException PHPUnit_Framework_Error_Warning
|
||||
* @expectedExceptionMessage Could not find validation handler totallyMissing for fieldName
|
||||
* @return void
|
||||
*/
|
||||
public function testCustomMethodMissingError() {
|
||||
$def = array('rule' => array('totallyMissing'));
|
||||
$data = array(
|
||||
'fieldName' => 'some data'
|
||||
);
|
||||
$methods = array('mytestrule' => array($this, 'myTestRule'));
|
||||
|
||||
$Rule = new CakeValidationRule($def);
|
||||
$Rule->process('fieldName', $data, $methods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test isRequired method
|
||||
*
|
||||
|
|
|
@ -300,6 +300,22 @@ class CakeRequestTest extends CakeTestCase {
|
|||
$this->assertEquals($data, $request->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* test parsing json PUT data into the object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testPutParsingJSON() {
|
||||
$_SERVER['REQUEST_METHOD'] = 'PUT';
|
||||
$_SERVER['CONTENT_TYPE'] = 'application/json';
|
||||
|
||||
$request = $this->getMock('TestCakeRequest', array('_readInput'));
|
||||
$request->expects($this->at(0))->method('_readInput')
|
||||
->will($this->returnValue('{Article":["title"]}'));
|
||||
$request->reConstruct();
|
||||
$this->assertEquals('{Article":["title"]}', $request->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* test parsing of FILES array
|
||||
*
|
||||
|
|
|
@ -1119,7 +1119,8 @@ class CakeEmailTest extends CakeTestCase {
|
|||
$this->CakeEmail->template('image');
|
||||
$this->CakeEmail->emailFormat('html');
|
||||
|
||||
$expected = '<img src="http://localhost/img/image.gif" alt="cool image" width="100" height="100" />';
|
||||
$server = env('SERVER_NAME') ? env('SERVER_NAME') : 'localhost';
|
||||
$expected = '<img src="http://' . $server . '/img/image.gif" alt="cool image" width="100" height="100" />';
|
||||
$result = $this->CakeEmail->send();
|
||||
$this->assertContains($expected, $result['message']);
|
||||
}
|
||||
|
|
|
@ -798,7 +798,7 @@ class CakeRouteTest extends CakeTestCase {
|
|||
)
|
||||
);
|
||||
$result = $route->match($url);
|
||||
$expected = '/posts/index/filter[0]:one/filter[model]:value';
|
||||
$expected = '/posts/index/filter%5B0%5D:one/filter%5Bmodel%5D:value';
|
||||
$this->assertEquals($expected, $result);
|
||||
|
||||
$url = array(
|
||||
|
@ -813,7 +813,7 @@ class CakeRouteTest extends CakeTestCase {
|
|||
)
|
||||
);
|
||||
$result = $route->match($url);
|
||||
$expected = '/posts/index/filter[0]:one/filter[model][0]:two/filter[model][order]:field';
|
||||
$expected = '/posts/index/filter%5B0%5D:one/filter%5Bmodel%5D%5B0%5D:two/filter%5Bmodel%5D%5Border%5D:field';
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
|
|
|
@ -1039,4 +1039,26 @@ XML;
|
|||
$this->assertContains('mark & mark', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that entity loading is disabled by default.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNoEntityLoading() {
|
||||
$file = CAKE . 'VERSION.txt';
|
||||
$xml = <<<XML
|
||||
<!DOCTYPE cakephp [
|
||||
<!ENTITY payload SYSTEM "file://$file" >]>
|
||||
<request>
|
||||
<xxe>&payload;</xxe>
|
||||
</request>
|
||||
XML;
|
||||
try {
|
||||
$result = Xml::build($xml);
|
||||
$this->assertEquals('', (string)$result->xxe);
|
||||
} catch (Exception $e) {
|
||||
$this->assertTrue(true, 'A warning was raised meaning external entities were not loaded');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -361,7 +361,14 @@ class HtmlHelperTest extends CakeTestCase {
|
|||
|
||||
$result = $this->Html->image('test.gif?one=two&three=four');
|
||||
$this->assertTags($result, array('img' => array('src' => 'img/test.gif?one=two&three=four', 'alt' => '')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that image() works with fullBase and a webroot not equal to /
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testImageWithFullBase() {
|
||||
$result = $this->Html->image('test.gif', array('fullBase' => true));
|
||||
$here = $this->Html->url('/', true);
|
||||
$this->assertTags($result, array('img' => array('src' => $here . 'img/test.gif', 'alt' => '')));
|
||||
|
@ -369,6 +376,15 @@ class HtmlHelperTest extends CakeTestCase {
|
|||
$result = $this->Html->image('sub/test.gif', array('fullBase' => true));
|
||||
$here = $this->Html->url('/', true);
|
||||
$this->assertTags($result, array('img' => array('src' => $here . 'img/sub/test.gif', 'alt' => '')));
|
||||
|
||||
$request = $this->Html->request;
|
||||
$request->webroot = '/myproject/';
|
||||
$request->base = '/myproject';
|
||||
Router::setRequestInfo($request);
|
||||
|
||||
$result = $this->Html->image('sub/test.gif', array('fullBase' => true));
|
||||
$here = $this->Html->url('/', true);
|
||||
$this->assertTags($result, array('img' => array('src' => $here . 'img/sub/test.gif', 'alt' => '')));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -194,6 +194,14 @@ class CakeTestFixture {
|
|||
$db->execute($db->createSchema($this->Schema), array('log' => false));
|
||||
$this->created[] = $db->configKeyName;
|
||||
} catch (Exception $e) {
|
||||
$msg = __d(
|
||||
'cake_dev',
|
||||
'Fixture creation for "%s" failed "%s"',
|
||||
$this->table,
|
||||
$e->getMessage()
|
||||
);
|
||||
CakeLog::error($msg);
|
||||
trigger_error($msg, E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -201,6 +201,9 @@ class CakeBaseReporter extends PHPUnit_TextUI_ResultPrinter {
|
|||
*/
|
||||
public function endTest(PHPUnit_Framework_Test $test, $time) {
|
||||
$this->numAssertions += $test->getNumAssertions();
|
||||
if ($test->hasFailed()) {
|
||||
return;
|
||||
}
|
||||
$this->paintPass($test, $time);
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,8 @@ class Xml {
|
|||
* ### Options
|
||||
*
|
||||
* - `return` Can be 'simplexml' to return object of SimpleXMLElement or 'domdocument' to return DOMDocument.
|
||||
* - `loadEntities` Defaults to false. Set to true to enable loading of `<!ENTITY` definitions. This
|
||||
* is disabled by default for security reasons.
|
||||
* - If using array as input, you can pass `options` from Xml::fromArray.
|
||||
*
|
||||
* @param string|array $input XML string, a path to a file, an URL or an array
|
||||
|
@ -86,32 +88,50 @@ class Xml {
|
|||
$options = array('return' => (string)$options);
|
||||
}
|
||||
$defaults = array(
|
||||
'return' => 'simplexml'
|
||||
'return' => 'simplexml',
|
||||
'loadEntities' => false,
|
||||
);
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
if (is_array($input) || is_object($input)) {
|
||||
return self::fromArray((array)$input, $options);
|
||||
} elseif (strpos($input, '<') !== false) {
|
||||
if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') {
|
||||
return new SimpleXMLElement($input, LIBXML_NOCDATA);
|
||||
}
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadXML($input);
|
||||
return $dom;
|
||||
return self::_loadXml($input, $options);
|
||||
} elseif (file_exists($input) || strpos($input, 'http://') === 0 || strpos($input, 'https://') === 0) {
|
||||
if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') {
|
||||
return new SimpleXMLElement($input, LIBXML_NOCDATA, true);
|
||||
}
|
||||
$dom = new DOMDocument();
|
||||
$dom->load($input);
|
||||
return $dom;
|
||||
$input = file_get_contents($input);
|
||||
return self::_loadXml($input, $options);
|
||||
} elseif (!is_string($input)) {
|
||||
throw new XmlException(__d('cake_dev', 'Invalid input.'));
|
||||
}
|
||||
throw new XmlException(__d('cake_dev', 'XML cannot be read.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the input data and create either a SimpleXmlElement object or a DOMDocument.
|
||||
*
|
||||
* @param string $input The input to load.
|
||||
* @param array $options The options to use. See Xml::build()
|
||||
* @return SimpleXmlElement|DOMDocument.
|
||||
*/
|
||||
protected static function _loadXml($input, $options) {
|
||||
$hasDisable = function_exists('libxml_disable_entity_loader');
|
||||
$internalErrors = libxml_use_internal_errors(true);
|
||||
if ($hasDisable && !$options['loadEntities']) {
|
||||
libxml_disable_entity_loader(true);
|
||||
}
|
||||
if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') {
|
||||
$xml = new SimpleXMLElement($input, LIBXML_NOCDATA);
|
||||
} else {
|
||||
$xml = new DOMDocument();
|
||||
$xml->loadXML($input);
|
||||
}
|
||||
if ($hasDisable && !$options['loadEntities']) {
|
||||
libxml_disable_entity_loader(false);
|
||||
}
|
||||
libxml_use_internal_errors($internalErrors);
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform an array into a SimpleXMLElement
|
||||
*
|
||||
|
|
|
@ -313,10 +313,12 @@ class Helper extends Object {
|
|||
$path = h($this->assetTimestamp($this->webroot($path)));
|
||||
|
||||
if (!empty($options['fullBase'])) {
|
||||
if ($path[0] == '/') {
|
||||
$path = substr($path, 1);
|
||||
$base = $this->url('/', true);
|
||||
$len = strlen($this->request->webroot);
|
||||
if ($len) {
|
||||
$base = substr($base, 0, -$len);
|
||||
}
|
||||
$path = $this->url('/', true) . $path;
|
||||
$path = $base . $path;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -701,7 +701,7 @@ class PaginatorHelper extends AppHelper {
|
|||
if ($offset < $start - 1) {
|
||||
$out .= $this->first($offset, compact('tag', 'separator', 'ellipsis', 'class'));
|
||||
} else {
|
||||
$out .= $this->first($offset, compact('tag', 'separator', 'class') + array('after' => $separator));
|
||||
$out .= $this->first($offset, compact('tag', 'separator', 'class', 'ellipsis') + array('after' => $separator));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -735,7 +735,7 @@ class PaginatorHelper extends AppHelper {
|
|||
if ($offset <= $last && $params['pageCount'] - $end > $offset) {
|
||||
$out .= $this->last($offset, compact('tag', 'separator', 'ellipsis', 'class'));
|
||||
} else {
|
||||
$out .= $this->last($offset, compact('tag', 'separator', 'class') + array('before' => $separator));
|
||||
$out .= $this->last($offset, compact('tag', 'separator', 'class', 'ellipsis') + array('before' => $separator));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue