From 339c3a916940d0ffebe3006178cc87b739428f8c Mon Sep 17 00:00:00 2001 From: Mark Story Date: Mon, 25 Jun 2018 22:05:18 -0400 Subject: [PATCH 01/13] Restrict phpstan to 0.9.x The new version of phpstan while great results in a bunch of errors/warnings we need to address. This gets us back to a passing build on master. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a25192117b6..1cf20cadf01 100644 --- a/.travis.yml +++ b/.travis.yml @@ -72,7 +72,7 @@ script: - if [[ $DEFAULT = 1 && $TRAVIS_PHP_VERSION != 7.0 ]]; then vendor/bin/phpunit; fi - if [[ $PHPCS = 1 ]]; then composer cs-check; fi - - if [[ $PHPSTAN = 1 ]]; then composer require --dev phpstan/phpstan:^0.9 && vendor/bin/phpstan analyse -c phpstan.neon -l 2 src; fi + - if [[ $PHPSTAN = 1 ]]; then composer require --dev "phpstan/phpstan:0.9.*" && vendor/bin/phpstan analyse -c phpstan.neon -l 2 src; fi after_success: - if [[ $DEFAULT = 1 && $TRAVIS_PHP_VERSION = 7.0 ]]; then bash <(curl -s https://codecov.io/bash); fi From 427929566577189007a9e2b61f03477a8ce85207 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Mon, 25 Jun 2018 22:29:01 -0400 Subject: [PATCH 02/13] Ignore invalid expires attributes in cookies. Refs #12269 --- src/Http/Cookie/CookieCollection.php | 15 ++++++++----- .../Http/Cookie/CookieCollectionTest.php | 21 +++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/Http/Cookie/CookieCollection.php b/src/Http/Cookie/CookieCollection.php index 0186fb94377..f168f1930d1 100644 --- a/src/Http/Cookie/CookieCollection.php +++ b/src/Http/Cookie/CookieCollection.php @@ -17,6 +17,7 @@ use Countable; use DateTimeImmutable; use DateTimeZone; +use Exception; use InvalidArgumentException; use IteratorAggregate; use Psr\Http\Message\RequestInterface; @@ -369,11 +370,15 @@ protected static function parseSetCookieHeader($values) $cookie[$key] = $value; } } - $expires = null; - if ($cookie['max-age'] !== null) { - $expires = new DateTimeImmutable('@' . (time() + $cookie['max-age'])); - } elseif ($cookie['expires']) { - $expires = new DateTimeImmutable('@' . strtotime($cookie['expires'])); + try { + $expires = null; + if ($cookie['max-age'] !== null) { + $expires = new DateTimeImmutable('@' . (time() + $cookie['max-age'])); + } elseif ($cookie['expires']) { + $expires = new DateTimeImmutable('@' . strtotime($cookie['expires'])); + } + } catch (Exception $e) { + $expires = null; } $cookies[] = new Cookie( diff --git a/tests/TestCase/Http/Cookie/CookieCollectionTest.php b/tests/TestCase/Http/Cookie/CookieCollectionTest.php index cb8e715d3ba..46451741763 100644 --- a/tests/TestCase/Http/Cookie/CookieCollectionTest.php +++ b/tests/TestCase/Http/Cookie/CookieCollectionTest.php @@ -305,6 +305,27 @@ public function testAddFromResponseRemoveExpired() $this->assertFalse($new->has('expired'), 'Should drop expired cookies'); } + /** + * Test adding cookies from a response with bad expires values + * + * @return void + */ + public function testAddFromResponseInvalidExpires() + { + $collection = new CookieCollection(); + $request = new ServerRequest([ + 'url' => '/app' + ]); + $response = (new Response()) + ->withAddedHeader('Set-Cookie', 'test=value') + ->withAddedHeader('Set-Cookie', 'expired=no; Expires=1w; Path=/; HttpOnly; Secure;'); + $new = $collection->addFromResponse($response, $request); + $this->assertTrue($new->has('test')); + $this->assertTrue($new->has('expired')); + $expired = $new->get('expired'); + $this->assertNull($expired->getExpiry()); + } + /** * Test adding cookies from responses updates cookie values. * From 55ee598f2984a8d60c932300ca3de797cf0f9d81 Mon Sep 17 00:00:00 2001 From: Albert Scherman Date: Tue, 26 Jun 2018 18:07:46 +0200 Subject: [PATCH 03/13] Fixed issue #12295 - https://github.com/cakephp/cakephp/issues/12295 --- src/Routing/Route/RedirectRoute.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Routing/Route/RedirectRoute.php b/src/Routing/Route/RedirectRoute.php index 170c56f206c..e4ccc3d16dd 100644 --- a/src/Routing/Route/RedirectRoute.php +++ b/src/Routing/Route/RedirectRoute.php @@ -88,7 +88,7 @@ public function parse($url, $method = '') } } } - $redirect = Router::reverse($redirect); + $redirect = Router::reverseToArray($redirect); } $status = 301; if (isset($this->options['status']) && ($this->options['status'] >= 300 && $this->options['status'] < 400)) { From f8fb7b61caae901d812a1eefd0555a83924ae076 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Tue, 26 Jun 2018 20:59:45 -0400 Subject: [PATCH 04/13] Clarify configuration options for CsrfProtectionMiddleware Refs #12294 --- src/Http/Middleware/CsrfProtectionMiddleware.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Http/Middleware/CsrfProtectionMiddleware.php b/src/Http/Middleware/CsrfProtectionMiddleware.php index 1257ca41a6c..8e0b155907a 100644 --- a/src/Http/Middleware/CsrfProtectionMiddleware.php +++ b/src/Http/Middleware/CsrfProtectionMiddleware.php @@ -40,11 +40,12 @@ class CsrfProtectionMiddleware /** * Default config for the CSRF handling. * - * - `cookieName` = The name of the cookie to send. - * - `expiry` = How long the CSRF token should last. Defaults to browser session. - * - `secure` = Whether or not the cookie will be set with the Secure flag. Defaults to false. - * - `httpOnly` = Whether or not the cookie will be set with the HttpOnly flag. Defaults to false. - * - `field` = The form field to check. Changing this will also require configuring + * - `cookieName` The name of the cookie to send. + * - `expiry` A strotime compatible value of how long the CSRF token should last. + * Defaults to browser session. + * - `secure` Whether or not the cookie will be set with the Secure flag. Defaults to false. + * - `httpOnly` Whether or not the cookie will be set with the HttpOnly flag. Defaults to false. + * - `field` The form field to check. Changing this will also require configuring * FormHelper. * * @var array From 703b4860b7f3b827e609bb59c16ff79860e1eb99 Mon Sep 17 00:00:00 2001 From: mark_story Date: Wed, 27 Jun 2018 12:31:06 -0400 Subject: [PATCH 05/13] Load cakephp-plugins when searching paths. In test suites the plugins key is cleared, while the runtime loaded plugins are not for compatibility reasons. This requires us to re-load the configuration file to restore path information. Refs #12288 --- src/Core/PluginCollection.php | 2 ++ tests/TestCase/Core/PluginCollectionTest.php | 22 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/Core/PluginCollection.php b/src/Core/PluginCollection.php index a1ce7058c3b..9dfff93c548 100644 --- a/src/Core/PluginCollection.php +++ b/src/Core/PluginCollection.php @@ -109,6 +109,8 @@ protected function loadConfig() */ public function findPath($name) { + $this->loadConfig(); + $path = Configure::read('plugins.' . $name); if ($path) { return $path; diff --git a/tests/TestCase/Core/PluginCollectionTest.php b/tests/TestCase/Core/PluginCollectionTest.php index dede7e389e7..ae778ea1785 100644 --- a/tests/TestCase/Core/PluginCollectionTest.php +++ b/tests/TestCase/Core/PluginCollectionTest.php @@ -148,6 +148,28 @@ public function testFindPathNoConfigureData() $this->assertEquals(TEST_APP . 'Plugin' . DS . 'TestPlugin' . DS, $path); } + public function testFindPathLoadsConfigureData() + { + $configPath = ROOT . DS . 'cakephp-plugins.php'; + $this->skipIf(file_exists($configPath), 'cakephp-plugins.php exists, skipping overwrite'); + $file = << [ + 'TestPlugin' => '/config/path' + ] +]; +PHP; + file_put_contents($configPath, $file); + + Configure::delete('plugins'); + $plugins = new PluginCollection(); + $path = $plugins->findPath('TestPlugin'); + unlink($configPath); + + $this->assertEquals('/config/path', $path); + } + public function testFindPathConfigureData() { Configure::write('plugins', ['TestPlugin' => '/some/path']); From 6c0d8dfa1f294f5da88c306f2ae464b9ac66d559 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Wed, 27 Jun 2018 21:35:52 -0400 Subject: [PATCH 06/13] Handle data attachments without warnings. Don't attempt to detect mimetypes on 'data' attachments. Refs #12297 --- src/Mailer/Email.php | 2 +- tests/TestCase/Mailer/EmailTest.php | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/Mailer/Email.php b/src/Mailer/Email.php index c1c92ef6cb5..87c16dcae74 100644 --- a/src/Mailer/Email.php +++ b/src/Mailer/Email.php @@ -1833,7 +1833,7 @@ public function setAttachments($attachments) $name = basename($fileInfo['file']); } } - if (!isset($fileInfo['mimetype']) && function_exists('mime_content_type')) { + if (!isset($fileInfo['mimetype']) && isset($fileInfo['file']) && function_exists('mime_content_type')) { $fileInfo['mimetype'] = mime_content_type($fileInfo['file']); } if (!isset($fileInfo['mimetype'])) { diff --git a/tests/TestCase/Mailer/EmailTest.php b/tests/TestCase/Mailer/EmailTest.php index 909006b5870..fc58560576b 100644 --- a/tests/TestCase/Mailer/EmailTest.php +++ b/tests/TestCase/Mailer/EmailTest.php @@ -857,7 +857,7 @@ public function testViewVars() * * @return void */ - public function testAttachments() + public function testSetAttachments() { $this->Email->setAttachments(CAKE . 'basics.php'); $expected = [ @@ -891,6 +891,26 @@ public function testAttachments() $this->Email->setAttachments([['nofile' => CAKE . 'basics.php', 'mimetype' => 'text/plain']]); } + /** + * Test send() with no template and data string attachment and no mimetype + * + * @return void + */ + public function testSetAttachmentDataNoMimetype() + { + $this->Email->setAttachments(['cake.icon.gif' => [ + 'data' => 'test', + ]]); + $result = $this->Email->getAttachments(); + $expected = [ + 'cake.icon.gif' => [ + 'data' => base64_encode('test') . "\r\n", + 'mimetype' => 'application/octet-stream' + ], + ]; + $this->assertSame($expected, $this->Email->getAttachments()); + } + /** * testTransport method * @@ -1317,7 +1337,6 @@ public function testSendNoTemplateWithAttachments() * * @return void */ - public function testSendNoTemplateWithDataStringAttachment() { $this->Email->setTransport('debug'); From acc11336a3292d64f36c43a581c1a04c0d9ccf1f Mon Sep 17 00:00:00 2001 From: Mark Story Date: Wed, 27 Jun 2018 21:54:33 -0400 Subject: [PATCH 07/13] Add a test for #12295 --- .../Routing/Route/RedirectRouteTest.php | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/TestCase/Routing/Route/RedirectRouteTest.php b/tests/TestCase/Routing/Route/RedirectRouteTest.php index 731cf119d2b..41716eed447 100644 --- a/tests/TestCase/Routing/Route/RedirectRouteTest.php +++ b/tests/TestCase/Routing/Route/RedirectRouteTest.php @@ -14,6 +14,7 @@ */ namespace Cake\Test\TestCase\Routing\Route; +use Cake\Http\ServerRequest; use Cake\Routing\Router; use Cake\Routing\Route\RedirectRoute; use Cake\TestSuite\TestCase; @@ -145,6 +146,26 @@ public function testParsePersist() $route->parse('/posts/2'); } + /** + * test redirecting with persist and a base directory + * + * @return void + */ + public function testParsePersistBaseDirectory() + { + $request = new ServerRequest([ + 'base' => '/basedir', + 'url' => '/posts/2' + ]); + Router::pushRequest($request); + + $this->expectException(\Cake\Routing\Exception\RedirectException::class); + $this->expectExceptionMessage('http://localhost/basedir/posts/view/2'); + $this->expectExceptionCode(301); + $route = new RedirectRoute('/posts/*', ['controller' => 'posts', 'action' => 'view'], ['persist' => true]); + $route->parse('/posts/2'); + } + /** * test redirecting with persist and string target URLs * From b991c2c70f68c8f8be8b609c98c0ff950a00f234 Mon Sep 17 00:00:00 2001 From: "vladimir.reznichenko" Date: Thu, 28 Jun 2018 13:20:00 +0200 Subject: [PATCH 08/13] Php Inspections (EA Ultimate): minor code tweaks --- src/Controller/Component/PaginatorComponent.php | 2 +- src/Core/functions.php | 6 ++---- src/Filesystem/File.php | 6 ++---- src/Http/ServerRequest.php | 4 ++-- src/ORM/Marshaller.php | 2 +- src/TestSuite/IntegrationTestCase.php | 2 +- src/Validation/Validation.php | 6 ++---- src/View/View.php | 2 +- 8 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/Controller/Component/PaginatorComponent.php b/src/Controller/Component/PaginatorComponent.php index 9ba5782665f..e44a36bc5a2 100644 --- a/src/Controller/Component/PaginatorComponent.php +++ b/src/Controller/Component/PaginatorComponent.php @@ -329,7 +329,7 @@ public function getConfig($key = null, $default = null) */ public function configShallow($key, $value = null) { - $this->_paginator->configShallow($key, $value = null); + $this->_paginator->configShallow($key, null); return $this; } diff --git a/src/Core/functions.php b/src/Core/functions.php index 0fbd2069ada..b2ccfd7c7da 100644 --- a/src/Core/functions.php +++ b/src/Core/functions.php @@ -207,10 +207,8 @@ function env($key, $default = null) return (strpos((string)env('SCRIPT_URI'), 'https://') === 0); } - if ($key === 'SCRIPT_NAME') { - if (env('CGI_MODE') && isset($_ENV['SCRIPT_URL'])) { - $key = 'SCRIPT_URL'; - } + if ($key === 'SCRIPT_NAME' && env('CGI_MODE') && isset($_ENV['SCRIPT_URL'])) { + $key = 'SCRIPT_URL'; } $val = null; diff --git a/src/Filesystem/File.php b/src/Filesystem/File.php index e0ebe95f7ba..e0ed1a44c92 100644 --- a/src/Filesystem/File.php +++ b/src/Filesystem/File.php @@ -109,10 +109,8 @@ public function create() { $dir = $this->Folder->pwd(); - if (is_dir($dir) && is_writable($dir) && !$this->exists()) { - if (touch($this->path)) { - return true; - } + if (is_dir($dir) && is_writable($dir) && !$this->exists() && touch($this->path)) { + return true; } return false; diff --git a/src/Http/ServerRequest.php b/src/Http/ServerRequest.php index 481ce967944..d2057227ebd 100644 --- a/src/Http/ServerRequest.php +++ b/src/Http/ServerRequest.php @@ -1107,8 +1107,8 @@ public function getHeaders() $name = $key; } if ($name !== null) { - $name = strtr(strtolower($name), '_', ' '); - $name = strtr(ucwords($name), ' ', '-'); + $name = str_replace('_', ' ', strtolower($name)); + $name = str_replace(' ', '-', ucwords($name)); $headers[$name] = (array)$value; } } diff --git a/src/ORM/Marshaller.php b/src/ORM/Marshaller.php index 45ae6136c24..7eb25518777 100644 --- a/src/ORM/Marshaller.php +++ b/src/ORM/Marshaller.php @@ -569,7 +569,7 @@ public function merge(EntityInterface $entity, array $data, array $options = []) $errors = $this->_validate($data + $keys, $options, $isNew); $options['isMerge'] = true; $propertyMap = $this->_buildPropertyMap($data, $options); - $properties = $marshalledAssocs = []; + $properties = []; foreach ($data as $key => $value) { if (!empty($errors[$key])) { if ($entity instanceof InvalidPropertyInterface) { diff --git a/src/TestSuite/IntegrationTestCase.php b/src/TestSuite/IntegrationTestCase.php index 975a00d14b7..f19f7a670c0 100644 --- a/src/TestSuite/IntegrationTestCase.php +++ b/src/TestSuite/IntegrationTestCase.php @@ -678,7 +678,7 @@ protected function _castToString($data) } if (is_array($value)) { - $looksLikeFile = isset($value['error']) && isset($value['tmp_name']) && isset($value['size']); + $looksLikeFile = isset($value['error'], $value['tmp_name'], $value['size']); if ($looksLikeFile) { continue; } diff --git a/src/Validation/Validation.php b/src/Validation/Validation.php index be47e5eb187..7a14c031281 100644 --- a/src/Validation/Validation.php +++ b/src/Validation/Validation.php @@ -208,10 +208,8 @@ public static function cc($check, $type = 'fast', $deep = false, $regex = null) return false; } - if ($regex !== null) { - if (static::_check($check, $regex)) { - return !$deep || static::luhn($check); - } + if ($regex !== null && static::_check($check, $regex)) { + return !$deep || static::luhn($check); } $cards = [ 'all' => [ diff --git a/src/View/View.php b/src/View/View.php index 4d93dff027f..0ea1c8d6dc8 100644 --- a/src/View/View.php +++ b/src/View/View.php @@ -1293,7 +1293,7 @@ protected function _getViewFileName($name = null) if (strlen($this->subDir)) { $subDir = $this->subDir . DIRECTORY_SEPARATOR; // Check if templatePath already terminates with subDir - if ($templatePath != $subDir && substr($templatePath, -(strlen($subDir))) == $subDir) { + if ($templatePath != $subDir && substr($templatePath, -strlen($subDir)) == $subDir) { $subDir = ''; } } From c09b9c293d7660b94f444ec99fa610f910ddaf16 Mon Sep 17 00:00:00 2001 From: "vladimir.reznichenko" Date: Thu, 28 Jun 2018 14:49:38 +0200 Subject: [PATCH 09/13] Php Inspections (EA Ultimate): simplified a touched code fragment --- src/Http/ServerRequest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Http/ServerRequest.php b/src/Http/ServerRequest.php index d2057227ebd..e2bc7044394 100644 --- a/src/Http/ServerRequest.php +++ b/src/Http/ServerRequest.php @@ -1107,8 +1107,7 @@ public function getHeaders() $name = $key; } if ($name !== null) { - $name = str_replace('_', ' ', strtolower($name)); - $name = str_replace(' ', '-', ucwords($name)); + $name = ucwords(str_replace(['_', ' '], [' ', '-'], $name)); $headers[$name] = (array)$value; } } From 5e622b2bfbb7c263a58c056a6f0dc66afeed216c Mon Sep 17 00:00:00 2001 From: "vladimir.reznichenko" Date: Thu, 28 Jun 2018 14:59:22 +0200 Subject: [PATCH 10/13] Php Inspections (EA Ultimate): restore original semantics --- src/Http/ServerRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Http/ServerRequest.php b/src/Http/ServerRequest.php index e2bc7044394..bf90b6d7155 100644 --- a/src/Http/ServerRequest.php +++ b/src/Http/ServerRequest.php @@ -1107,7 +1107,7 @@ public function getHeaders() $name = $key; } if ($name !== null) { - $name = ucwords(str_replace(['_', ' '], [' ', '-'], $name)); + $name = ucwords(strtolower(str_replace(['_', ' '], [' ', '-'], $name))); $headers[$name] = (array)$value; } } From 656ce4055c16c66034c50c5a589b689f57e1a450 Mon Sep 17 00:00:00 2001 From: "vladimir.reznichenko" Date: Thu, 28 Jun 2018 15:01:25 +0200 Subject: [PATCH 11/13] Php Inspections (EA Ultimate): partial revert --- src/Http/ServerRequest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Http/ServerRequest.php b/src/Http/ServerRequest.php index bf90b6d7155..d2057227ebd 100644 --- a/src/Http/ServerRequest.php +++ b/src/Http/ServerRequest.php @@ -1107,7 +1107,8 @@ public function getHeaders() $name = $key; } if ($name !== null) { - $name = ucwords(strtolower(str_replace(['_', ' '], [' ', '-'], $name))); + $name = str_replace('_', ' ', strtolower($name)); + $name = str_replace(' ', '-', ucwords($name)); $headers[$name] = (array)$value; } } From 0dc1d7a799b272ae4df016bb8764a5470343b9d5 Mon Sep 17 00:00:00 2001 From: chinpei215 Date: Thu, 28 Jun 2018 23:16:12 +0900 Subject: [PATCH 12/13] MultiCheckboxWidget should use checkboxWrapper, not radioWrapper. --- src/View/Widget/MultiCheckboxWidget.php | 2 +- .../View/Widget/MultiCheckboxWidgetTest.php | 71 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/View/Widget/MultiCheckboxWidget.php b/src/View/Widget/MultiCheckboxWidget.php index 46affc2dae4..18ba16d1899 100644 --- a/src/View/Widget/MultiCheckboxWidget.php +++ b/src/View/Widget/MultiCheckboxWidget.php @@ -191,7 +191,7 @@ protected function _renderInput($checkbox, $context) ) ]); - if ($checkbox['label'] === false && strpos($this->_templates->get('radioWrapper'), '{{input}}') === false) { + if ($checkbox['label'] === false && strpos($this->_templates->get('checkboxWrapper'), '{{input}}') === false) { $label = $input; } else { $labelAttrs = [ diff --git a/tests/TestCase/View/Widget/MultiCheckboxWidgetTest.php b/tests/TestCase/View/Widget/MultiCheckboxWidgetTest.php index 77ce89f193d..e411d1fa699 100644 --- a/tests/TestCase/View/Widget/MultiCheckboxWidgetTest.php +++ b/tests/TestCase/View/Widget/MultiCheckboxWidgetTest.php @@ -369,6 +369,77 @@ public function testRenderTemplateVars() $this->assertHtml($expected, $result); } + /** + * Test label = false with checkboxWrapper option. + * + * @return void + */ + public function testNoLabelWithCheckboxWrapperOption() + { + $data = [ + 'label' => false, + 'name' => 'test', + 'options' => [ + 1 => 'A', + 2 => 'B', + ], + ]; + + $label = new LabelWidget($this->templates); + $input = new MultiCheckboxWidget($this->templates, $label); + $result = $input->render($data, $this->context); + $expected = [ + ['div' => ['class' => 'checkbox']], + ['input' => [ + 'type' => 'checkbox', + 'name' => 'test[]', + 'value' => 1, + 'id' => 'test-1', + ]], + ['label' => ['for' => 'test-1']], + 'A', + '/label', + '/div', + ['div' => ['class' => 'checkbox']], + ['input' => [ + 'type' => 'checkbox', + 'name' => 'test[]', + 'value' => '2', + 'id' => 'test-2', + ]], + ['label' => ['for' => 'test-2']], + 'B', + '/label', + '/div', + ]; + $this->assertHtml($expected, $result); + + $templates = [ + 'checkboxWrapper' => '
{{label}}
', + ]; + $this->templates->add($templates); + $result = $input->render($data, $this->context); + $expected = [ + ['div' => ['class' => 'checkbox']], + ['input' => [ + 'type' => 'checkbox', + 'name' => 'test[]', + 'value' => 1, + 'id' => 'test-1', + ]], + '/div', + ['div' => ['class' => 'checkbox']], + ['input' => [ + 'type' => 'checkbox', + 'name' => 'test[]', + 'value' => '2', + 'id' => 'test-2', + ]], + '/div', + ]; + $this->assertHtml($expected, $result); + } + /** * Test render with groupings. * From bdd5170fd6c0ee573c75bef929f261535671903b Mon Sep 17 00:00:00 2001 From: Dmitriy Romanov Date: Thu, 28 Jun 2018 18:08:28 +0300 Subject: [PATCH 13/13] Corrected annotation for Debugger::exportVar() method. --- src/Error/Debugger.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Error/Debugger.php b/src/Error/Debugger.php index 8819476eefb..dd49fc5ea26 100644 --- a/src/Error/Debugger.php +++ b/src/Error/Debugger.php @@ -486,7 +486,7 @@ protected static function _highlight($str) * This is done to protect database credentials, which could be accidentally * shown in an error message if CakePHP is deployed in development mode. * - * @param string $var Variable to convert. + * @param mixed $var Variable to convert. * @param int $depth The depth to output to. Defaults to 3. * @return string Variable as a formatted string */