mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2025-01-31 09:06:17 +00:00
Merge branch '1.3' into 2.0
Conflicts: cake/libs/configure.php cake/libs/model/connection_manager.php cake/libs/model/model.php cake/tests/cases/libs/model/datasources/dbo/dbo_postgres.test.php cake/tests/cases/libs/view/helpers/text.test.php
This commit is contained in:
commit
d88da3d579
29 changed files with 389 additions and 45 deletions
|
@ -272,8 +272,9 @@ class ControllerTask extends BakeTask {
|
||||||
*/
|
*/
|
||||||
public function bakeActions($controllerName, $admin = null, $wannaUseSession = true) {
|
public function bakeActions($controllerName, $admin = null, $wannaUseSession = true) {
|
||||||
$currentModelName = $modelImport = $this->_modelName($controllerName);
|
$currentModelName = $modelImport = $this->_modelName($controllerName);
|
||||||
if ($this->plugin) {
|
$plugin = $this->plugin;
|
||||||
$modelImport = $this->plugin . '.' . $modelImport;
|
if ($plugin) {
|
||||||
|
$modelImport = $plugin . '.' . $modelImport;
|
||||||
}
|
}
|
||||||
if (!App::import('Model', $modelImport)) {
|
if (!App::import('Model', $modelImport)) {
|
||||||
$this->err(__('You must have a model for this class to build basic methods. Please try again.'));
|
$this->err(__('You must have a model for this class to build basic methods. Please try again.'));
|
||||||
|
@ -287,7 +288,7 @@ class ControllerTask extends BakeTask {
|
||||||
$singularHumanName = $this->_singularHumanName($controllerName);
|
$singularHumanName = $this->_singularHumanName($controllerName);
|
||||||
$pluralHumanName = $this->_pluralName($controllerName);
|
$pluralHumanName = $this->_pluralName($controllerName);
|
||||||
|
|
||||||
$this->Template->set(compact('admin', 'controllerPath', 'pluralName', 'singularName', 'singularHumanName',
|
$this->Template->set(compact('plugin', 'admin', 'controllerPath', 'pluralName', 'singularName', 'singularHumanName',
|
||||||
'pluralHumanName', 'modelObj', 'wannaUseSession', 'currentModelName'));
|
'pluralHumanName', 'modelObj', 'wannaUseSession', 'currentModelName'));
|
||||||
$actions = $this->Template->generate('actions', 'controller_actions');
|
$actions = $this->Template->generate('actions', 'controller_actions');
|
||||||
return $actions;
|
return $actions;
|
||||||
|
|
|
@ -362,6 +362,9 @@ class ViewTask extends BakeTask {
|
||||||
if ($content === true) {
|
if ($content === true) {
|
||||||
$content = $this->getContent($action);
|
$content = $this->getContent($action);
|
||||||
}
|
}
|
||||||
|
if (empty($content)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
$path = $this->getPath();
|
$path = $this->getPath();
|
||||||
$filename = $path . $this->controllerPath . DS . Inflector::underscore($action) . '.ctp';
|
$filename = $path . $this->controllerPath . DS . Inflector::underscore($action) . '.ctp';
|
||||||
return $this->createFile($filename, $content);
|
return $this->createFile($filename, $content);
|
||||||
|
|
|
@ -87,6 +87,7 @@ class Configure {
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
self::$_values[$names[0]][$names[1]][$names[2]] = $value;
|
self::$_values[$names[0]][$names[1]][$names[2]] = $value;
|
||||||
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
$names = explode('.', $name, 2);
|
$names = explode('.', $name, 2);
|
||||||
if (!isset(self::$_values[$names[0]])) {
|
if (!isset(self::$_values[$names[0]])) {
|
||||||
|
@ -1230,4 +1231,4 @@ class App {
|
||||||
Cache::write('object_map', self::$__objects, '_cake_core_');
|
Cache::write('object_map', self::$__objects, '_cake_core_');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -738,19 +738,16 @@ class EmailComponent extends Component {
|
||||||
* @access private
|
* @access private
|
||||||
*/
|
*/
|
||||||
function _formatAddress($string, $smtp = false) {
|
function _formatAddress($string, $smtp = false) {
|
||||||
if (strpos($string, '<') !== false) {
|
$hasAlias = preg_match('/(.+)\s<(.+)>/', $string, $matches);
|
||||||
$value = explode('<', $string);
|
if ($hasAlias) {
|
||||||
if ($smtp) {
|
return $this->_strip($matches[1] . ' <' . $matches[2] . '>');
|
||||||
$string = '<' . $value[1];
|
|
||||||
} else {
|
|
||||||
$string = $this->_encode($value[0]) . ' <' . $value[1];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return $this->_strip($string);
|
return $this->_strip($string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove certain elements (such as bcc:, to:, %0a) from given value
|
* Remove certain elements (such as bcc:, to:, %0a) from given value.
|
||||||
|
* Helps prevent header injection / mainipulation on user content.
|
||||||
*
|
*
|
||||||
* @param string $value Value to strip
|
* @param string $value Value to strip
|
||||||
* @param boolean $message Set to true to indicate main message content
|
* @param boolean $message Set to true to indicate main message content
|
||||||
|
|
|
@ -106,6 +106,7 @@ class ErrorHandler extends Object {
|
||||||
if (!in_array(strtolower($method), array_map('strtolower', get_class_methods($this)))) {
|
if (!in_array(strtolower($method), array_map('strtolower', get_class_methods($this)))) {
|
||||||
$method = 'error';
|
$method = 'error';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($method !== 'error') {
|
if ($method !== 'error') {
|
||||||
if (Configure::read('debug') == 0) {
|
if (Configure::read('debug') == 0) {
|
||||||
$parentClass = get_parent_class($this);
|
$parentClass = get_parent_class($this);
|
||||||
|
@ -116,7 +117,7 @@ class ErrorHandler extends Object {
|
||||||
if (in_array(strtolower($method), $parentMethods)) {
|
if (in_array(strtolower($method), $parentMethods)) {
|
||||||
$method = 'error404';
|
$method = 'error404';
|
||||||
}
|
}
|
||||||
if (isset($code) && $code == 500) {
|
if (isset($messages[0]['code']) && $messages[0]['code'] == 500) {
|
||||||
$method = 'error500';
|
$method = 'error500';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ class Inflector {
|
||||||
'/(c)hild$/i' => '\1hildren',
|
'/(c)hild$/i' => '\1hildren',
|
||||||
'/(buffal|tomat)o$/i' => '\1\2oes',
|
'/(buffal|tomat)o$/i' => '\1\2oes',
|
||||||
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i',
|
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i',
|
||||||
'/us$/' => 'uses',
|
'/us$/i' => 'uses',
|
||||||
'/(alias)$/i' => '\1es',
|
'/(alias)$/i' => '\1es',
|
||||||
'/(ax|cris|test)is$/i' => '\1es',
|
'/(ax|cris|test)is$/i' => '\1es',
|
||||||
'/s$/' => 's',
|
'/s$/' => 's',
|
||||||
|
|
|
@ -278,7 +278,7 @@ class TreeBehavior extends ModelBehavior {
|
||||||
if (!$id) {
|
if (!$id) {
|
||||||
$conditions = $scope;
|
$conditions = $scope;
|
||||||
} else {
|
} else {
|
||||||
$result = array_values($Model->find('first', array(
|
$result = array_values((array)$Model->find('first', array(
|
||||||
'conditions' => array($scope, $Model->escapeField() => $id),
|
'conditions' => array($scope, $Model->escapeField() => $id),
|
||||||
'fields' => array($left, $right),
|
'fields' => array($left, $right),
|
||||||
'recursive' => $recursive
|
'recursive' => $recursive
|
||||||
|
|
|
@ -657,16 +657,19 @@ class DboMysql extends DboMysqlBase {
|
||||||
if ($data === '') {
|
if ($data === '') {
|
||||||
return 'NULL';
|
return 'NULL';
|
||||||
}
|
}
|
||||||
if ((is_int($data) || is_float($data) || $data === '0') || (
|
if (is_float($data)) {
|
||||||
|
return sprintf('%F', $data);
|
||||||
|
}
|
||||||
|
if ((is_int($data) || $data === '0') || (
|
||||||
is_numeric($data) && strpos($data, ',') === false &&
|
is_numeric($data) && strpos($data, ',') === false &&
|
||||||
$data[0] != '0' && strpos($data, 'e') === false)) {
|
$data[0] != '0' && strpos($data, 'e') === false)
|
||||||
return $data;
|
) {
|
||||||
}
|
return $data;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
$data = "'" . mysql_real_escape_string($data, $this->connection) . "'";
|
return "'" . mysql_real_escape_string($data, $this->connection) . "'";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return $data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -299,8 +299,11 @@ class DboPostgres extends DboSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch($column) {
|
switch($column) {
|
||||||
case 'inet':
|
|
||||||
case 'float':
|
case 'float':
|
||||||
|
if (is_float($data)) {
|
||||||
|
$data = sprintf('%F', $data);
|
||||||
|
}
|
||||||
|
case 'inet':
|
||||||
case 'integer':
|
case 'integer':
|
||||||
case 'date':
|
case 'date':
|
||||||
case 'datetime':
|
case 'datetime':
|
||||||
|
|
|
@ -54,7 +54,7 @@ class DboSource extends DataSource {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caches result from query parsing operations. Cached results for both DboSource::name() and
|
* Caches result from query parsing operations. Cached results for both DboSource::name() and
|
||||||
* DboSource::conditions() will be stored here. Method caching uses `crc32()` which is
|
* DboSource::conditions() will be stored here. Method caching uses `crc32()` which is
|
||||||
* fast but can collisions more easily than other hashing algorithms. If you have problems
|
* fast but can collisions more easily than other hashing algorithms. If you have problems
|
||||||
* with collisions, set DboSource::$cacheMethods to false.
|
* with collisions, set DboSource::$cacheMethods to false.
|
||||||
*
|
*
|
||||||
|
@ -504,7 +504,7 @@ class DboSource extends DataSource {
|
||||||
* because the method uses a simple hashing algorithm it can infrequently have collisions.
|
* because the method uses a simple hashing algorithm it can infrequently have collisions.
|
||||||
* Setting DboSource::$cacheMethods to false will disable the memory cache.
|
* Setting DboSource::$cacheMethods to false will disable the memory cache.
|
||||||
*
|
*
|
||||||
* @param mixed $data Either a string with a column to quote. An array of columns to quote or an
|
* @param mixed $data Either a string with a column to quote. An array of columns to quote or an
|
||||||
* object from DboSource::expression() or DboSource::identifier()
|
* object from DboSource::expression() or DboSource::identifier()
|
||||||
* @return string SQL field
|
* @return string SQL field
|
||||||
*/
|
*/
|
||||||
|
@ -611,7 +611,7 @@ class DboSource extends DataSource {
|
||||||
$controller = null;
|
$controller = null;
|
||||||
$View =& new View($controller, false);
|
$View =& new View($controller, false);
|
||||||
$View->set('logs', array($this->configKeyName => $log));
|
$View->set('logs', array($this->configKeyName => $log));
|
||||||
echo $View->element('sql_dump');
|
echo $View->element('sql_dump', array('_forced_from_dbo_' => true));
|
||||||
} else {
|
} else {
|
||||||
foreach ($log['log'] as $k => $i) {
|
foreach ($log['log'] as $k => $i) {
|
||||||
print (($k + 1) . ". {$i['query']} {$i['error']}\n");
|
print (($k + 1) . ". {$i['query']} {$i['error']}\n");
|
||||||
|
@ -822,6 +822,10 @@ class DboSource extends DataSource {
|
||||||
$stack = array($assoc);
|
$stack = array($assoc);
|
||||||
$db->queryAssociation($model, $linkModel, $type, $assoc, $assocData, $array, true, $resultSet, $model->recursive - 1, $stack);
|
$db->queryAssociation($model, $linkModel, $type, $assoc, $assocData, $array, true, $resultSet, $model->recursive - 1, $stack);
|
||||||
unset($db);
|
unset($db);
|
||||||
|
|
||||||
|
if ($type === 'hasMany') {
|
||||||
|
$filtered []= $assoc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1613,6 +1613,7 @@ class Model extends Object {
|
||||||
|
|
||||||
if (Set::numeric(array_keys($data))) {
|
if (Set::numeric(array_keys($data))) {
|
||||||
while ($validates) {
|
while ($validates) {
|
||||||
|
$return = array();
|
||||||
foreach ($data as $key => $record) {
|
foreach ($data as $key => $record) {
|
||||||
if (!$currentValidates = $this->__save($record, $options)) {
|
if (!$currentValidates = $this->__save($record, $options)) {
|
||||||
$validationErrors[$key] = $this->validationErrors;
|
$validationErrors[$key] = $this->validationErrors;
|
||||||
|
@ -1644,7 +1645,6 @@ class Model extends Object {
|
||||||
break;
|
break;
|
||||||
case ($options['validate'] === 'first'):
|
case ($options['validate'] === 'first'):
|
||||||
$options['validate'] = true;
|
$options['validate'] = true;
|
||||||
$return = array();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if ($options['atomic']) {
|
if ($options['atomic']) {
|
||||||
|
@ -2522,7 +2522,7 @@ class Model extends Object {
|
||||||
$_validate = $this->validate;
|
$_validate = $this->validate;
|
||||||
$whitelist = $this->whitelist;
|
$whitelist = $this->whitelist;
|
||||||
|
|
||||||
if (array_key_exists('fieldList', $options)) {
|
if (!empty($options['fieldList'])) {
|
||||||
$whitelist = $options['fieldList'];
|
$whitelist = $options['fieldList'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
if (!class_exists('ConnectionManager') || Configure::read('debug') < 2) {
|
if (!class_exists('ConnectionManager') || Configure::read('debug') < 2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!isset($logs)):
|
$noLogs = !isset($logs);
|
||||||
|
if ($noLogs):
|
||||||
$sources = ConnectionManager::sourceList();
|
$sources = ConnectionManager::sourceList();
|
||||||
|
|
||||||
$logs = array();
|
$logs = array();
|
||||||
|
@ -31,8 +32,9 @@ if (!isset($logs)):
|
||||||
endif;
|
endif;
|
||||||
$logs[$source] = $db->getLog();
|
$logs[$source] = $db->getLog();
|
||||||
endforeach;
|
endforeach;
|
||||||
|
endif;
|
||||||
|
|
||||||
|
if ($noLogs || isset($_forced_from_dbo_)):
|
||||||
foreach ($logs as $source => $logInfo):
|
foreach ($logs as $source => $logInfo):
|
||||||
$text = $logInfo['count'] > 1 ? 'queries' : 'query';
|
$text = $logInfo['count'] > 1 ? 'queries' : 'query';
|
||||||
printf(
|
printf(
|
||||||
|
@ -52,6 +54,8 @@ if (!isset($logs)):
|
||||||
?>
|
?>
|
||||||
</tbody></table>
|
</tbody></table>
|
||||||
<?php
|
<?php
|
||||||
endforeach;
|
endforeach;
|
||||||
|
else:
|
||||||
|
echo '<p>Encountered unexpected $logs cannot generate SQL log</p>';
|
||||||
endif;
|
endif;
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -477,7 +477,11 @@ class Helper extends Object {
|
||||||
if (ClassRegistry::isKeySet($model)) {
|
if (ClassRegistry::isKeySet($model)) {
|
||||||
$ModelObj =& ClassRegistry::getObject($model);
|
$ModelObj =& ClassRegistry::getObject($model);
|
||||||
for ($i = 0; $i < $count; $i++) {
|
for ($i = 0; $i < $count; $i++) {
|
||||||
if ($ModelObj->hasField($parts[$i]) || array_key_exists($parts[$i], $ModelObj->validate)) {
|
if (
|
||||||
|
is_a($ModelObj, 'Model') &&
|
||||||
|
($ModelObj->hasField($parts[$i]) ||
|
||||||
|
array_key_exists($parts[$i], $ModelObj->validate))
|
||||||
|
) {
|
||||||
$hasField = $i;
|
$hasField = $i;
|
||||||
if ($hasField === 0 || ($hasField === 1 && is_numeric($parts[0]))) {
|
if ($hasField === 0 || ($hasField === 1 && is_numeric($parts[0]))) {
|
||||||
$sameScope = true;
|
$sameScope = true;
|
||||||
|
|
|
@ -170,7 +170,7 @@ class FormHelper extends AppHelper {
|
||||||
* ### Options:
|
* ### Options:
|
||||||
*
|
*
|
||||||
* - `type` Form method defaults to POST
|
* - `type` Form method defaults to POST
|
||||||
* - `action` The Action the form submits to. Can be a string or array,
|
* - `action` The controller action the form submits to, (optional).
|
||||||
* - `url` The url the form submits to. Can be a string or a url array,
|
* - `url` The url the form submits to. Can be a string or a url array,
|
||||||
* - `default` Allows for the creation of Ajax forms.
|
* - `default` Allows for the creation of Ajax forms.
|
||||||
* - `onsubmit` Used in conjunction with 'default' to create ajax forms.
|
* - `onsubmit` Used in conjunction with 'default' to create ajax forms.
|
||||||
|
@ -1449,7 +1449,8 @@ class FormHelper extends AppHelper {
|
||||||
$hiddenAttributes = array(
|
$hiddenAttributes = array(
|
||||||
'value' => '',
|
'value' => '',
|
||||||
'id' => $attributes['id'] . ($style ? '' : '_'),
|
'id' => $attributes['id'] . ($style ? '' : '_'),
|
||||||
'secure' => false
|
'secure' => false,
|
||||||
|
'name' => $attributes['name']
|
||||||
);
|
);
|
||||||
$select[] = $this->hidden(null, $hiddenAttributes);
|
$select[] = $this->hidden(null, $hiddenAttributes);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1483,7 +1484,7 @@ class FormHelper extends AppHelper {
|
||||||
$selected,
|
$selected,
|
||||||
array(),
|
array(),
|
||||||
$showParents,
|
$showParents,
|
||||||
array('escape' => $escapeOptions, 'style' => $style)
|
array('escape' => $escapeOptions, 'style' => $style, 'name' => $attributes['name'])
|
||||||
));
|
));
|
||||||
|
|
||||||
$template = ($style == 'checkbox') ? 'checkboxmultipleend' : 'selectend';
|
$template = ($style == 'checkbox') ? 'checkboxmultipleend' : 'selectend';
|
||||||
|
@ -2027,7 +2028,7 @@ class FormHelper extends AppHelper {
|
||||||
$label['class'] = 'selected';
|
$label['class'] = 'selected';
|
||||||
}
|
}
|
||||||
|
|
||||||
list($name) = array_values($this->_name());
|
$name = $attributes['name'];
|
||||||
|
|
||||||
if (empty($attributes['class'])) {
|
if (empty($attributes['class'])) {
|
||||||
$attributes['class'] = 'checkbox';
|
$attributes['class'] = 'checkbox';
|
||||||
|
|
|
@ -328,6 +328,8 @@ class ControllerTaskTest extends CakeTestCase {
|
||||||
$this->Task->plugin = 'controllerTest';
|
$this->Task->plugin = 'controllerTest';
|
||||||
$path = APP . 'plugins' . DS . 'controller_test' . DS . 'controllers' . DS . 'articles_controller.php';
|
$path = APP . 'plugins' . DS . 'controller_test' . DS . 'controllers' . DS . 'articles_controller.php';
|
||||||
$this->Task->bake('Articles', '--actions--', array(), array(), array());
|
$this->Task->bake('Articles', '--actions--', array(), array(), array());
|
||||||
|
|
||||||
|
$this->assertEqual($this->Task->Template->templateVars['plugin'], 'ControllerTest');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -380,6 +380,19 @@ class ViewTaskTest extends CakeTestCase {
|
||||||
$this->Task->bake('index', true);
|
$this->Task->bake('index', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test that baking a view with no template doesn't make a file.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function testBakeWithNoTemplate() {
|
||||||
|
$this->Task->controllerName = 'ViewTaskComments';
|
||||||
|
$this->Task->controllerPath = 'view_task_comments';
|
||||||
|
|
||||||
|
$this->Task->expectNever('createFile');
|
||||||
|
$this->Task->bake('delete', true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* test bake() with a -plugin param
|
* test bake() with a -plugin param
|
||||||
*
|
*
|
||||||
|
|
|
@ -138,6 +138,15 @@ class EmailTestComponent extends EmailComponent {
|
||||||
function strip($content, $message = false) {
|
function strip($content, $message = false) {
|
||||||
return parent::_strip($content, $message);
|
return parent::_strip($content, $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for testing.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function formatAddress($string, $smtp = false) {
|
||||||
|
return parent::_formatAddress($string, $smtp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1155,4 +1164,23 @@ HTMLBLOC;
|
||||||
);
|
);
|
||||||
$this->assertEqual($expected, $result);
|
$this->assertEqual($expected, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that _formatName doesn't jack up email addresses with alias parts.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function testFormatAddressAliases() {
|
||||||
|
$result = $this->Controller->EmailTest->formatAddress('email@example.com');
|
||||||
|
$this->assertEqual($result, 'email@example.com');
|
||||||
|
|
||||||
|
$result = $this->Controller->EmailTest->formatAddress('alias <email@example.com>');
|
||||||
|
$this->assertEqual($result, 'alias <email@example.com>');
|
||||||
|
|
||||||
|
$result = $this->Controller->EmailTest->formatAddress('email@example.com');
|
||||||
|
$this->assertEqual($result, 'email@example.com');
|
||||||
|
|
||||||
|
$result = $this->Controller->EmailTest->formatAddress('<email@example.com>');
|
||||||
|
$this->assertEqual($result, '<email@example.com>');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -607,4 +607,22 @@ class ErrorHandlerTest extends CakeTestCase {
|
||||||
$this->assertPattern('/<em>Article<\/em> could not be found./', $result);
|
$this->assertPattern('/<em>Article<\/em> could not be found./', $result);
|
||||||
$this->assertPattern('/(\/|\\\)article.php/', $result);
|
$this->assertPattern('/(\/|\\\)article.php/', $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* testing that having a code => 500 in the cakeError call makes an
|
||||||
|
* internal server error.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function testThatCode500Works() {
|
||||||
|
Configure::write('debug', 0);
|
||||||
|
ob_start();
|
||||||
|
$TestErrorHandler = new TestErrorHandler('missingTable', array(
|
||||||
|
'className' => 'Article',
|
||||||
|
'table' => 'articles',
|
||||||
|
'code' => 500
|
||||||
|
));
|
||||||
|
$result = ob_get_clean();
|
||||||
|
$this->assertPattern('/<h2>An Internal Error Has Occurred<\/h2>/', $result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1095,6 +1095,8 @@ class NumberTreeTest extends CakeTestCase {
|
||||||
array($modelClass => array( 'id' => 6, 'name' => '1.2.1', $parentField => 5, $leftField => 9, $rightField => 10)),
|
array($modelClass => array( 'id' => 6, 'name' => '1.2.1', $parentField => 5, $leftField => 9, $rightField => 10)),
|
||||||
array($modelClass => array('id' => 7, 'name' => '1.2.2', $parentField => 5, $leftField => 11, $rightField => 12)));
|
array($modelClass => array('id' => 7, 'name' => '1.2.2', $parentField => 5, $leftField => 11, $rightField => 12)));
|
||||||
$this->assertEqual($total, $expects);
|
$this->assertEqual($total, $expects);
|
||||||
|
|
||||||
|
$this->assertEqual(array(), $this->Tree->children(10000));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -249,6 +249,24 @@ class DboMysqlTest extends CakeTestCase {
|
||||||
$this->assertEqual($expected, $result);
|
$this->assertEqual($expected, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test that localized floats don't cause trouble.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function testLocalizedFloats() {
|
||||||
|
$restore = setlocale(LC_ALL, null);
|
||||||
|
setlocale(LC_ALL, 'de_DE');
|
||||||
|
|
||||||
|
$result = $this->db->value(3.141593, 'float');
|
||||||
|
$this->assertEqual((string)$result, '3.141593');
|
||||||
|
|
||||||
|
$result = $this->db->value(3.141593);
|
||||||
|
$this->assertEqual((string)$result, '3.141593');
|
||||||
|
|
||||||
|
setlocale(LC_ALL, $restore);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* testTinyintCasting method
|
* testTinyintCasting method
|
||||||
*
|
*
|
||||||
|
|
|
@ -330,8 +330,8 @@ class DboPostgresTest extends CakeTestCase {
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function testValueQuoting() {
|
function testValueQuoting() {
|
||||||
$this->assertIdentical($this->Dbo2->value(1.2, 'float'), "'1.2'");
|
$this->assertIdentical($this->db2->value(1.2, 'float'), "'1.200000'");
|
||||||
$this->assertEqual($this->Dbo2->value('1,2', 'float'), "'1,2'");
|
$this->assertEqual($this->db2->value('1,2', 'float'), "'1,2'");
|
||||||
|
|
||||||
$this->assertEqual($this->Dbo2->value('0', 'integer'), "'0'");
|
$this->assertEqual($this->Dbo2->value('0', 'integer'), "'0'");
|
||||||
$this->assertEqual($this->Dbo2->value('', 'integer'), 'NULL');
|
$this->assertEqual($this->Dbo2->value('', 'integer'), 'NULL');
|
||||||
|
@ -356,6 +356,24 @@ class DboPostgresTest extends CakeTestCase {
|
||||||
$this->assertEqual($this->Dbo2->value(array()), "NULL");
|
$this->assertEqual($this->Dbo2->value(array()), "NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test that localized floats don't cause trouble.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function testLocalizedFloats() {
|
||||||
|
$restore = setlocale(LC_ALL, null);
|
||||||
|
setlocale(LC_ALL, 'de_DE');
|
||||||
|
|
||||||
|
$result = $this->db->value(3.141593, 'float');
|
||||||
|
$this->assertEqual((string)$result, "'3.141593'");
|
||||||
|
|
||||||
|
$result = $this->db->value(3.14);
|
||||||
|
$this->assertEqual((string)$result, "'3.140000'");
|
||||||
|
|
||||||
|
setlocale(LC_ALL, $restore);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* test that date and time columns do not generate errors with null and nullish values.
|
* test that date and time columns do not generate errors with null and nullish values.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2549,11 +2549,11 @@ class DboSourceTest extends CakeTestCase {
|
||||||
$this->assertEqual($result, $expected);
|
$this->assertEqual($result, $expected);
|
||||||
|
|
||||||
$result = $this->testDb->conditions(array('score BETWEEN ? AND ?' => array(90.1, 95.7)));
|
$result = $this->testDb->conditions(array('score BETWEEN ? AND ?' => array(90.1, 95.7)));
|
||||||
$expected = " WHERE `score` BETWEEN 90.1 AND 95.7";
|
$expected = " WHERE `score` BETWEEN 90.100000 AND 95.700000";
|
||||||
$this->assertEqual($result, $expected);
|
$this->assertEqual($result, $expected);
|
||||||
|
|
||||||
$result = $this->testDb->conditions(array('Post.title' => 1.1));
|
$result = $this->testDb->conditions(array('Post.title' => 1.1));
|
||||||
$expected = " WHERE `Post`.`title` = 1.1";
|
$expected = " WHERE `Post`.`title` = 1.100000";
|
||||||
$this->assertEqual($result, $expected);
|
$this->assertEqual($result, $expected);
|
||||||
|
|
||||||
$result = $this->testDb->conditions(array('Post.title' => 1.1), true, true, new Post());
|
$result = $this->testDb->conditions(array('Post.title' => 1.1), true, true, new Post());
|
||||||
|
|
|
@ -164,11 +164,34 @@ class ModelValidationTest extends BaseModelTest {
|
||||||
$TestModel->invalidFields();
|
$TestModel->invalidFields();
|
||||||
$expected = array('name' => 'This field cannot be left blank');
|
$expected = array('name' => 'This field cannot be left blank');
|
||||||
$this->assertEqual($TestModel->validationErrors, $expected);
|
$this->assertEqual($TestModel->validationErrors, $expected);
|
||||||
$TestModel->validationErrors = array();
|
|
||||||
|
|
||||||
$this->assertEqual($TestModel->validate, $validate);
|
$this->assertEqual($TestModel->validate, $validate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that invalidFields() integrates well with save(). And that fieldList can be an empty type.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function testInvalidFieldsWhitelist() {
|
||||||
|
$TestModel =& new ValidationTest1();
|
||||||
|
$TestModel->validate = $validate = array(
|
||||||
|
'title' => array(
|
||||||
|
'rule' => 'customValidator',
|
||||||
|
'required' => true
|
||||||
|
),
|
||||||
|
'name' => array(
|
||||||
|
'rule' => 'alphaNumeric',
|
||||||
|
'required' => true
|
||||||
|
));
|
||||||
|
|
||||||
|
$TestModel->whitelist = array('name');
|
||||||
|
$TestModel->save(array('name' => '#$$#'));
|
||||||
|
|
||||||
|
$expected = array('name' => 'This field cannot be left blank');
|
||||||
|
$this->assertEqual($TestModel->validationErrors, $expected);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* testValidates method
|
* testValidates method
|
||||||
*
|
*
|
||||||
|
|
|
@ -3508,6 +3508,65 @@ class ModelWriteTest extends BaseModelTest {
|
||||||
$this->assertEqual($result[0]['Comment'][0]['comment'], 'Only new comment');
|
$this->assertEqual($result[0]['Comment'][0]['comment'], 'Only new comment');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test saveAll()'s return is correct when using atomic = false and validate = first.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function testSaveAllValidateFirstAtomicFalse() {
|
||||||
|
$Something =& new Something();
|
||||||
|
$invalidData = array(
|
||||||
|
array(
|
||||||
|
'title' => 'foo',
|
||||||
|
'body' => 'bar',
|
||||||
|
'published' => 'baz',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'body' => 3,
|
||||||
|
'published' =>'sd',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
$Something->create();
|
||||||
|
$Something->validate = array(
|
||||||
|
'title' => array(
|
||||||
|
'rule' => 'alphaNumeric',
|
||||||
|
'required' => true,
|
||||||
|
),
|
||||||
|
'body' => array(
|
||||||
|
'rule' => 'alphaNumeric',
|
||||||
|
'required' => true,
|
||||||
|
'allowEmpty' => true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
$result = $Something->saveAll($invalidData, array(
|
||||||
|
'atomic' => false,
|
||||||
|
'validate' => 'first',
|
||||||
|
));
|
||||||
|
$expected = array(true, false);
|
||||||
|
$this->assertEqual($result, $expected);
|
||||||
|
|
||||||
|
$Something =& new Something();
|
||||||
|
$validData = array(
|
||||||
|
array(
|
||||||
|
'title' => 'title value',
|
||||||
|
'body' => 'body value',
|
||||||
|
'published' => 'baz',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'title' => 'valid',
|
||||||
|
'body' => 'this body',
|
||||||
|
'published' =>'sd',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
$Something->create();
|
||||||
|
$result = $Something->saveAll($validData, array(
|
||||||
|
'atomic' => false,
|
||||||
|
'validate' => 'first',
|
||||||
|
));
|
||||||
|
$expected = array(true, true);
|
||||||
|
$this->assertEqual($result, $expected);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* testUpdateWithCalculation method
|
* testUpdateWithCalculation method
|
||||||
*
|
*
|
||||||
|
@ -3804,4 +3863,22 @@ class ModelWriteTest extends BaseModelTest {
|
||||||
$this->assertFalse($result);
|
$this->assertFalse($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test writing floats in german locale.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function testWriteFloatAsGerman() {
|
||||||
|
$restore = setlocale(LC_ALL, null);
|
||||||
|
setlocale(LC_ALL, 'de_DE');
|
||||||
|
|
||||||
|
$model = new DataTest();
|
||||||
|
$result = $model->save(array(
|
||||||
|
'count' => 1,
|
||||||
|
'float' => 3.14593
|
||||||
|
));
|
||||||
|
$this->assertTrue($result);
|
||||||
|
setlocale(LC_ALL, $restore);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,7 +228,7 @@ class HelperTest extends CakeTestCase {
|
||||||
* @access public
|
* @access public
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function testFormFieldNameParsing() {
|
function testSetEntity() {
|
||||||
// PHP4 reference hack
|
// PHP4 reference hack
|
||||||
ClassRegistry::removeObject('view');
|
ClassRegistry::removeObject('view');
|
||||||
ClassRegistry::addObject('view', $this->View);
|
ClassRegistry::addObject('view', $this->View);
|
||||||
|
@ -359,6 +359,17 @@ class HelperTest extends CakeTestCase {
|
||||||
$this->assertEqual($this->View->fieldSuffix, null);
|
$this->assertEqual($this->View->fieldSuffix, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test that 'view' doesn't break things.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function testSetEntityWithView() {
|
||||||
|
$this->assertNull($this->Helper->setEntity('Allow.view.group_id'));
|
||||||
|
$this->assertNull($this->Helper->setEntity('Allow.view'));
|
||||||
|
$this->assertNull($this->Helper->setEntity('View.view'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* test getting values from Helper
|
* test getting values from Helper
|
||||||
*
|
*
|
||||||
|
|
|
@ -433,6 +433,43 @@ class CacheHelperTest extends CakeTestCase {
|
||||||
$this->assertTrue(file_exists($filename));
|
$this->assertTrue(file_exists($filename));
|
||||||
@unlink($filename);
|
@unlink($filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test ControllerName contains AppName
|
||||||
|
*
|
||||||
|
* This test verifys view cache is created correctly when the app name is contained in part of the controller name.
|
||||||
|
* (webapp Name) base name is 'cache' controller is 'cacheTest' action is 'cache_name'
|
||||||
|
* apps url would look somehing like http://localhost/cache/cacheTest/cache_name
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
**/
|
||||||
|
function testCacheBaseNameControllerName() {
|
||||||
|
$this->Controller->cache_parsing();
|
||||||
|
$this->Controller->cacheAction = array(
|
||||||
|
'cache_name' => 21600
|
||||||
|
);
|
||||||
|
$this->Controller->params = array(
|
||||||
|
'controller' => 'cacheTest',
|
||||||
|
'action' => 'cache_name',
|
||||||
|
'url' => array(),
|
||||||
|
'pass' => array(),
|
||||||
|
'named' => array()
|
||||||
|
);
|
||||||
|
$this->Controller->here = '/cache/cacheTest/cache_name';
|
||||||
|
$this->Controller->action = 'cache_name';
|
||||||
|
$this->Controller->base = '/cache';
|
||||||
|
|
||||||
|
$View = new View($this->Controller);
|
||||||
|
$result = $View->render('index');
|
||||||
|
|
||||||
|
$this->assertNoPattern('/cake:nocache/', $result);
|
||||||
|
$this->assertNoPattern('/php echo/', $result);
|
||||||
|
|
||||||
|
$filename = CACHE . 'views' . DS . 'cache_cachetest_cache_name.php';
|
||||||
|
$this->assertTrue(file_exists($filename));
|
||||||
|
@unlink($filename);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* testCacheEmptySections method
|
* testCacheEmptySections method
|
||||||
*
|
*
|
||||||
|
|
|
@ -3447,7 +3447,10 @@ class FormHelperTest extends CakeTestCase {
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function testInputMultipleCheckboxes() {
|
function testInputMultipleCheckboxes() {
|
||||||
$result = $this->Form->input('Model.multi_field', array('options' => array('first', 'second', 'third'), 'multiple' => 'checkbox'));
|
$result = $this->Form->input('Model.multi_field', array(
|
||||||
|
'options' => array('first', 'second', 'third'),
|
||||||
|
'multiple' => 'checkbox'
|
||||||
|
));
|
||||||
$expected = array(
|
$expected = array(
|
||||||
array('div' => array('class' => 'input select')),
|
array('div' => array('class' => 'input select')),
|
||||||
array('label' => array('for' => 'ModelMultiField')),
|
array('label' => array('for' => 'ModelMultiField')),
|
||||||
|
@ -3476,7 +3479,10 @@ class FormHelperTest extends CakeTestCase {
|
||||||
);
|
);
|
||||||
$this->assertTags($result, $expected);
|
$this->assertTags($result, $expected);
|
||||||
|
|
||||||
$result = $this->Form->input('Model.multi_field', array('options' => array('a' => 'first', 'b' => 'second', 'c' => 'third'), 'multiple' => 'checkbox'));
|
$result = $this->Form->input('Model.multi_field', array(
|
||||||
|
'options' => array('a' => 'first', 'b' => 'second', 'c' => 'third'),
|
||||||
|
'multiple' => 'checkbox'
|
||||||
|
));
|
||||||
$expected = array(
|
$expected = array(
|
||||||
array('div' => array('class' => 'input select')),
|
array('div' => array('class' => 'input select')),
|
||||||
array('label' => array('for' => 'ModelMultiField')),
|
array('label' => array('for' => 'ModelMultiField')),
|
||||||
|
@ -3505,7 +3511,12 @@ class FormHelperTest extends CakeTestCase {
|
||||||
);
|
);
|
||||||
$this->assertTags($result, $expected);
|
$this->assertTags($result, $expected);
|
||||||
|
|
||||||
$result = $this->Form->input('Model.multi_field', array('options' => array('1' => 'first'), 'multiple' => 'checkbox', 'label' => false, 'div' => false));
|
$result = $this->Form->input('Model.multi_field', array(
|
||||||
|
'options' => array('1' => 'first'),
|
||||||
|
'multiple' => 'checkbox',
|
||||||
|
'label' => false,
|
||||||
|
'div' => false
|
||||||
|
));
|
||||||
$expected = array(
|
$expected = array(
|
||||||
'input' => array('type' => 'hidden', 'name' => 'data[Model][multi_field]', 'value' => '', 'id' => 'ModelMultiField'),
|
'input' => array('type' => 'hidden', 'name' => 'data[Model][multi_field]', 'value' => '', 'id' => 'ModelMultiField'),
|
||||||
array('div' => array('class' => 'checkbox')),
|
array('div' => array('class' => 'checkbox')),
|
||||||
|
@ -3517,7 +3528,12 @@ class FormHelperTest extends CakeTestCase {
|
||||||
);
|
);
|
||||||
$this->assertTags($result, $expected);
|
$this->assertTags($result, $expected);
|
||||||
|
|
||||||
$result = $this->Form->input('Model.multi_field', array('options' => array('2' => 'second'), 'multiple' => 'checkbox', 'label' => false, 'div' => false));
|
$result = $this->Form->input('Model.multi_field', array(
|
||||||
|
'options' => array('2' => 'second'),
|
||||||
|
'multiple' => 'checkbox',
|
||||||
|
'label' => false,
|
||||||
|
'div' => false
|
||||||
|
));
|
||||||
$expected = array(
|
$expected = array(
|
||||||
'input' => array('type' => 'hidden', 'name' => 'data[Model][multi_field]', 'value' => '', 'id' => 'ModelMultiField'),
|
'input' => array('type' => 'hidden', 'name' => 'data[Model][multi_field]', 'value' => '', 'id' => 'ModelMultiField'),
|
||||||
array('div' => array('class' => 'checkbox')),
|
array('div' => array('class' => 'checkbox')),
|
||||||
|
@ -3530,6 +3546,34 @@ class FormHelperTest extends CakeTestCase {
|
||||||
$this->assertTags($result, $expected);
|
$this->assertTags($result, $expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test that select() with multiple = checkbox works with overriding name attribute.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function testSelectCheckboxMultipleOverrideName() {
|
||||||
|
$result = $this->Form->input('category', array(
|
||||||
|
'type' => 'select',
|
||||||
|
'multiple' => 'checkbox',
|
||||||
|
'name' => 'data[fish]',
|
||||||
|
'options' => array('1', '2'),
|
||||||
|
'div' => false,
|
||||||
|
'label' => false,
|
||||||
|
));
|
||||||
|
$expected = array(
|
||||||
|
'input' => array('type' => 'hidden', 'name' => 'data[fish]', 'value' => '', 'id' => 'category'),
|
||||||
|
array('div' => array('class' => 'checkbox')),
|
||||||
|
array('input' => array('type' => 'checkbox', 'name' => 'data[fish][]', 'value' => '0', 'id' => 'Category0')),
|
||||||
|
array('label' => array('for' => 'Category0')), '1', '/label',
|
||||||
|
'/div',
|
||||||
|
array('div' => array('class' => 'checkbox')),
|
||||||
|
array('input' => array('type' => 'checkbox', 'name' => 'data[fish][]', 'value' => '1', 'id' => 'Category1')),
|
||||||
|
array('label' => array('for' => 'Category1')), '2', '/label',
|
||||||
|
'/div'
|
||||||
|
);
|
||||||
|
$this->assertTags($result, $expected);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* testCheckbox method
|
* testCheckbox method
|
||||||
*
|
*
|
||||||
|
|
|
@ -618,6 +618,34 @@ class HtmlHelperTest extends CakeTestCase {
|
||||||
$this->assertNull($result);
|
$this->assertNull($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test a script file in the webroot/theme dir.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function testScriptInTheme() {
|
||||||
|
if ($this->skipIf(!is_writable(WWW_ROOT . 'theme'), 'Cannot write to webroot/theme')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
App::import('Core', 'File');
|
||||||
|
|
||||||
|
$testfile = WWW_ROOT . 'theme' . DS . 'test_theme' . DS . 'js' . DS . '__test_js.js';
|
||||||
|
$file =& new File($testfile, true);
|
||||||
|
|
||||||
|
App::build(array(
|
||||||
|
'views' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS)
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->Html->webroot = '/';
|
||||||
|
$this->Html->theme = 'test_theme';
|
||||||
|
$result = $this->Html->script('__test_js.js');
|
||||||
|
$expected = array(
|
||||||
|
'script' => array('src' => '/theme/test_theme/js/__test_js.js', 'type' => 'text/javascript')
|
||||||
|
);
|
||||||
|
$this->assertTags($result, $expected);
|
||||||
|
App::build();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* test Script block generation
|
* test Script block generation
|
||||||
*
|
*
|
||||||
|
|
|
@ -402,5 +402,8 @@ class TextHelperTest extends CakeTestCase {
|
||||||
|
|
||||||
$result = $this->Text->toList(array( 'name1' => 'Dusty', 'name2' => 'Lucky'));
|
$result = $this->Text->toList(array( 'name1' => 'Dusty', 'name2' => 'Lucky'));
|
||||||
$this->assertEqual($result, 'Dusty and Lucky');
|
$this->assertEqual($result, 'Dusty and Lucky');
|
||||||
|
|
||||||
|
$result = $this->Text->toList(array( 'test_0' => 'banana', 'test_1' => 'apple', 'test_2' => 'lemon'));
|
||||||
|
$this->assertEqual($result, 'banana, apple and lemon');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue