diff --git a/src/Controller/Component/AuthComponent.php b/src/Controller/Component/AuthComponent.php index 5fea7a06a41..c8360a8621d 100644 --- a/src/Controller/Component/AuthComponent.php +++ b/src/Controller/Component/AuthComponent.php @@ -383,7 +383,7 @@ protected function _unauthenticated(Controller $controller) if ($auth === false) { throw new Exception('At least one authenticate object must be available.'); } - $result = $auth->unauthenticated($this->request, $response); + $result = $auth->unauthenticated($controller->request, $response); if ($result !== null) { return $result; } @@ -535,7 +535,7 @@ public function isAuthorized($user = null, ServerRequest $request = null) $user = $this->user(); } if (empty($request)) { - $request = $this->request; + $request = $this->getController()->getRequest(); } if (empty($this->_authorizeObjects)) { $this->constructAuthorize(); @@ -749,7 +749,7 @@ protected function _getUser() $this->constructAuthenticate(); } foreach ($this->_authenticateObjects as $auth) { - $result = $auth->getUser($this->request); + $result = $auth->getUser($this->getController()->getRequest()); if (!empty($result) && is_array($result)) { $this->_authenticationProvider = $auth; $event = $this->dispatchEvent('Auth.afterIdentify', [$result, $auth]); @@ -785,7 +785,7 @@ protected function _getUser() */ public function redirectUrl($url = null) { - $redirectUrl = $this->request->getQuery(static::QUERY_STRING_REDIRECT); + $redirectUrl = $this->getController()->getRequest()->getQuery(static::QUERY_STRING_REDIRECT); if ($redirectUrl && (substr($redirectUrl, 0, 1) !== '/' || substr($redirectUrl, 0, 2) === '//')) { $redirectUrl = null; } @@ -825,7 +825,7 @@ public function identify() $this->constructAuthenticate(); } foreach ($this->_authenticateObjects as $auth) { - $result = $auth->authenticate($this->request, $this->response); + $result = $auth->authenticate($this->getController()->getRequest(), $this->response); if (!empty($result)) { $this->_authenticationProvider = $auth; $event = $this->dispatchEvent('Auth.afterIdentify', [$result, $auth]); @@ -911,7 +911,9 @@ public function storage(StorageInterface $storage = null) if (!class_exists($className)) { throw new Exception(sprintf('Auth storage adapter "%s" was not found.', $class)); } - $this->_storage = new $className($this->request, $this->response, $config); + $request = $this->getController()->getRequest(); + $response = $this->getController()->getResponse(); + $this->_storage = new $className($request, $response, $config); return $this->_storage; } diff --git a/src/Controller/Component/PaginatorComponent.php b/src/Controller/Component/PaginatorComponent.php index eaa28d0730f..4b5a4311e31 100644 --- a/src/Controller/Component/PaginatorComponent.php +++ b/src/Controller/Component/PaginatorComponent.php @@ -266,12 +266,11 @@ public function getPaginator() */ protected function _setPagingParams() { - $request = $this->_registry->getController()->request; + $controller = $this->getController(); + $request = $controller->getRequest(); + $paging = $this->_paginator->getPagingParams() + (array)$request->getParam('paging'); - $request->addParams([ - 'paging' => $this->_paginator->getPagingParams() - + (array)$request->getParam('paging') - ]); + $controller->setRequest($request->withParam('paging', $paging)); } /** diff --git a/tests/TestCase/Auth/BasicAuthenticateTest.php b/tests/TestCase/Auth/BasicAuthenticateTest.php index 4f09cc23dda..f55a8afcdbb 100644 --- a/tests/TestCase/Auth/BasicAuthenticateTest.php +++ b/tests/TestCase/Auth/BasicAuthenticateTest.php @@ -129,9 +129,8 @@ public function testAuthenticateInjection() 'environment' => [ 'PHP_AUTH_USER' => '> 1', 'PHP_AUTH_PW' => "' OR 1 = 1" - ] + ], ]); - $request->addParams(['pass' => []]); $this->assertFalse($this->auth->getUser($request)); $this->assertFalse($this->auth->authenticate($request, $this->response)); @@ -172,7 +171,6 @@ public function testAuthenticateUsernameZero() public function testAuthenticateChallenge() { $request = new ServerRequest('posts/index'); - $request->addParams(['pass' => []]); try { $this->auth->unauthenticated($request, $this->response); @@ -199,7 +197,6 @@ public function testAuthenticateSuccess() 'PHP_AUTH_PW' => 'password' ] ]); - $request->addParams(['pass' => []]); $result = $this->auth->authenticate($request, $this->response); $expected = [ @@ -228,7 +225,6 @@ public function testAuthenticateFailReChallenge() 'PHP_AUTH_PW' => 'password' ] ]); - $request->addParams(['pass' => []]); $this->auth->unauthenticated($request, $this->response); } diff --git a/tests/TestCase/Auth/DigestAuthenticateTest.php b/tests/TestCase/Auth/DigestAuthenticateTest.php index eac0b347967..62977993045 100644 --- a/tests/TestCase/Auth/DigestAuthenticateTest.php +++ b/tests/TestCase/Auth/DigestAuthenticateTest.php @@ -113,8 +113,7 @@ public function testAuthenticateWrongUsername() { $this->expectException(\Cake\Http\Exception\UnauthorizedException::class); $this->expectExceptionCode(401); - $request = new ServerRequest('posts/index'); - $request->addParams(['pass' => []]); + $request = new ServerRequest(['url' => 'posts/index']); $data = [ 'username' => 'incorrect_user', @@ -142,7 +141,6 @@ public function testAuthenticateChallenge() 'url' => 'posts/index', 'environment' => ['REQUEST_METHOD' => 'GET'] ]); - $request->addParams(['pass' => []]); try { $this->auth->unauthenticated($request, $this->response); @@ -169,7 +167,6 @@ public function testAuthenticateChallengeIncludesStaleAttributeOnStaleNonce() 'url' => 'posts/index', 'environment' => ['REQUEST_METHOD' => 'GET'] ]); - $request->addParams(['pass' => []]); $data = [ 'uri' => '/dir/index.html', 'nonce' => $this->generateNonce(null, 5, strtotime('-10 minutes')), @@ -201,7 +198,6 @@ public function testAuthenticateFailsOnStaleNonce() 'url' => 'posts/index', 'environment' => ['REQUEST_METHOD' => 'GET'] ]); - $request->addParams(['pass' => []]); $data = [ 'uri' => '/dir/index.html', @@ -227,7 +223,6 @@ public function testAuthenticateValidUsernamePasswordNoNonce() 'url' => 'posts/index', 'environment' => ['REQUEST_METHOD' => 'GET'] ]); - $request->addParams(['pass' => []]); $data = [ 'username' => 'mariano', @@ -255,7 +250,6 @@ public function testAuthenticateSuccess() 'url' => 'posts/index', 'environment' => ['REQUEST_METHOD' => 'GET'] ]); - $request->addParams(['pass' => []]); $data = [ 'uri' => '/dir/index.html', @@ -291,7 +285,6 @@ public function testAuthenticateSuccessHiddenPasswordField() 'url' => 'posts/index', 'environment' => ['REQUEST_METHOD' => 'GET'] ]); - $request->addParams(['pass' => []]); $data = [ 'uri' => '/dir/index.html', @@ -325,7 +318,6 @@ public function testAuthenticateSuccessSimulatedRequestMethod() 'post' => ['_method' => 'PUT'], 'environment' => ['REQUEST_METHOD' => 'GET'] ]); - $request->addParams(['pass' => []]); $data = [ 'username' => 'mariano', @@ -362,7 +354,6 @@ public function testAuthenticateFailReChallenge() 'url' => 'posts/index', 'environment' => ['REQUEST_METHOD' => 'GET'] ]); - $request->addParams(['pass' => []]); $data = [ 'username' => 'invalid', diff --git a/tests/TestCase/Controller/Component/AuthComponentTest.php b/tests/TestCase/Controller/Component/AuthComponentTest.php index a4e10d4e07a..5de18f4e201 100644 --- a/tests/TestCase/Controller/Component/AuthComponentTest.php +++ b/tests/TestCase/Controller/Component/AuthComponentTest.php @@ -85,6 +85,7 @@ public function setUp() $Users = TableRegistry::get('AuthUsers'); $Users->updateAll(['password' => password_hash('cake', PASSWORD_BCRYPT)], []); + $this->request = $request; } /** @@ -129,7 +130,7 @@ public function testIdentify() $this->Auth->setAuthenticateObject(0, $AuthLoginFormAuthenticate); - $this->Auth->request->data = [ + $this->Controller->request->data = [ 'AuthUsers' => [ 'username' => 'mark', 'password' => Security::hash('cake', null, true) @@ -143,7 +144,7 @@ public function testIdentify() $AuthLoginFormAuthenticate->expects($this->once()) ->method('authenticate') - ->with($this->Auth->request) + ->with($this->Controller->request) ->will($this->returnValue($user)); $result = $this->Auth->identify(); @@ -170,7 +171,7 @@ public function testIdentifyArrayAccess() $this->Auth->setAuthenticateObject(0, $AuthLoginFormAuthenticate); - $this->Auth->request->data = [ + $this->Controller->request->data = [ 'AuthUsers' => [ 'username' => 'mark', 'password' => Security::hash('cake', null, true) @@ -184,7 +185,7 @@ public function testIdentifyArrayAccess() $AuthLoginFormAuthenticate->expects($this->once()) ->method('authenticate') - ->with($this->Auth->request) + ->with($this->Controller->request) ->will($this->returnValue($user)); $result = $this->Auth->identify(); @@ -206,7 +207,7 @@ public function testAuthorizeFalse() $this->Controller->Auth->storage()->write($user); $this->Controller->Auth->setConfig('userModel', 'Users'); $this->Controller->Auth->setConfig('authorize', false); - $this->Controller->request->addParams(['controller' => 'AuthTest', 'action' => 'add']); + $this->Controller->request = $this->request->withAttribute('params', ['controller' => 'AuthTest', 'action' => 'add']); $result = $this->Controller->Auth->startup($event); $this->assertNull($result); @@ -216,7 +217,7 @@ public function testAuthorizeFalse() $this->assertInstanceOf('Cake\Http\Response', $result); $this->assertTrue($this->Auth->session->check('Flash.flash')); - $this->Controller->request->addParams(['controller' => 'AuthTest', 'action' => 'camelCase']); + $this->Controller->request = $this->request->withAttribute('params', ['controller' => 'AuthTest', 'action' => 'camelCase']); $result = $this->Controller->Auth->startup($event); $this->assertInstanceOf('Cake\Http\Response', $result); } @@ -256,7 +257,7 @@ public function testIsAuthorizedDelegation() $this->Auth->setAuthorizeObject(0, $AuthMockOneAuthorize); $this->Auth->setAuthorizeObject(1, $AuthMockTwoAuthorize); $this->Auth->setAuthorizeObject(2, $AuthMockThreeAuthorize); - $request = $this->Auth->request; + $request = $this->Controller->request; $AuthMockOneAuthorize->expects($this->once()) ->method('authorize') @@ -288,7 +289,7 @@ public function testIsAuthorizedWithArrayObject() ->getMock(); $this->Auth->setAuthorizeObject(0, $AuthMockOneAuthorize); - $request = $this->Auth->request; + $request = $this->Controller->request; $user = new \ArrayObject(['User']); @@ -496,14 +497,18 @@ public function testDenyWithCamelCaseMethods() $this->Controller->Auth->deny(['add', 'camelCase']); $url = '/auth_test/camelCase'; - $this->Controller->request->addParams(['controller' => 'AuthTest', 'action' => 'camelCase']); - $this->Controller->request->query['url'] = Router::normalize($url); + $this->Controller->request = $this->request->withAttribute( + 'params', + ['controller' => 'AuthTest', 'action' => 'camelCase'] + )->withQueryParams(['url' => Router::normalize($url)]); $this->assertInstanceOf('Cake\Http\Response', $this->Controller->Auth->startup($event)); $url = '/auth_test/CamelCase'; - $this->Controller->request->addParams(['controller' => 'AuthTest', 'action' => 'camelCase']); - $this->Controller->request->query['url'] = Router::normalize($url); + $this->Controller->request = $this->request->withAttribute( + 'params', + ['controller' => 'AuthTest', 'action' => 'camelCase'] + )->withQueryParams(['url' => Router::normalize($url)]); $this->assertInstanceOf('Cake\Http\Response', $this->Controller->Auth->startup($event)); } @@ -517,8 +522,9 @@ public function testAllowedActionsWithCamelCaseMethods() { $event = new Event('Controller.startup', $this->Controller); $url = '/auth_test/camelCase'; - $this->Controller->request->addParams(['controller' => 'AuthTest', 'action' => 'camelCase']); - $this->Controller->request->query['url'] = Router::normalize($url); + $this->Controller->request = $this->request + ->withAttribute('params', ['controller' => 'AuthTest', 'action' => 'camelCase']) + ->withRequestTarget($url); $this->Controller->Auth->loginAction = ['controller' => 'AuthTest', 'action' => 'login']; $this->Controller->Auth->userModel = 'AuthUsers'; $this->Controller->Auth->allow(); @@ -526,8 +532,9 @@ public function testAllowedActionsWithCamelCaseMethods() $this->assertNull($result, 'startup() should return null, as action is allowed. %s'); $url = '/auth_test/camelCase'; - $this->Controller->request->addParams(['controller' => 'AuthTest', 'action' => 'camelCase']); - $this->Controller->request->query['url'] = Router::normalize($url); + $this->Controller->request = $this->request + ->withAttribute('params', ['controller' => 'AuthTest', 'action' => 'camelCase']) + ->withRequestTarget($url); $this->Controller->Auth->loginAction = ['controller' => 'AuthTest', 'action' => 'login']; $this->Controller->Auth->userModel = 'AuthUsers'; $this->Controller->Auth->allowedActions = ['delete', 'camelCase', 'add']; @@ -538,8 +545,9 @@ public function testAllowedActionsWithCamelCaseMethods() $this->assertInstanceOf('Cake\Http\Response', $this->Controller->Auth->startup($event)); $url = '/auth_test/delete'; - $this->Controller->request->addParams(['controller' => 'AuthTest', 'action' => 'delete']); - $this->Controller->request->query['url'] = Router::normalize($url); + $this->Controller->request = $this->request + ->withAttribute('params', ['controller' => 'AuthTest', 'action' => 'delete']) + ->withRequestTarget($url); $this->Controller->Auth->loginAction = ['controller' => 'AuthTest', 'action' => 'login']; $this->Controller->Auth->userModel = 'AuthUsers'; @@ -556,8 +564,8 @@ public function testAllowedActionsWithCamelCaseMethods() public function testAllowedActionsSetWithAllowMethod() { $url = '/auth_test/action_name'; - $this->Controller->request->addParams(['controller' => 'AuthTest', 'action' => 'action_name']); - $this->Controller->request->query['url'] = Router::normalize($url); + $this->Controller->request = $this->request + ->withAttribute('params', ['controller' => 'AuthTest', 'action' => 'action_name']); $this->Controller->Auth->allow(['action_name', 'anotherAction']); $this->assertEquals(['action_name', 'anotherAction'], $this->Controller->Auth->allowedActions); } @@ -574,7 +582,7 @@ public function testLoginRedirect() 'AuthUsers' => ['id' => '1', 'username' => 'nate'] ]); - $this->Auth->request = $this->Controller->request = new ServerRequest([ + $this->Controller->request = $this->Controller->request = new ServerRequest([ 'params' => ['controller' => 'Users', 'action' => 'login'], 'url' => '/users/login', 'environment' => ['HTTP_REFERER' => false], @@ -597,7 +605,7 @@ public function testLoginRedirect() 'Auth', ['AuthUsers' => ['id' => '1', 'username' => 'nate']] ); - $this->Auth->request = $this->Controller->request = new ServerRequest([ + $this->Controller->request = $this->Controller->request = new ServerRequest([ 'params' => ['controller' => 'Posts', 'action' => 'view', 'pass' => [1]], 'url' => '/posts/view/1', 'environment' => ['HTTP_REFERER' => false, 'REQUEST_METHOD' => 'GET'], @@ -622,7 +630,7 @@ public function testLoginRedirect() // Auth.redirect gets set when accessing a protected action without being authenticated $this->Auth->session->delete('Auth'); - $this->Auth->request = $this->Controller->request = new ServerRequest([ + $this->Controller->request = $this->Controller->request = new ServerRequest([ 'params' => ['controller' => 'Posts', 'action' => 'view', 'pass' => [1]], 'url' => '/posts/view/1', 'environment' => ['HTTP_REFERER' => false, 'REQUEST_METHOD' => 'GET'], @@ -646,7 +654,7 @@ public function testLoginRedirect() public function testLoginRedirectPost() { $this->Auth->session->delete('Auth'); - $this->Auth->request = new ServerRequest([ + $this->Controller->request = new ServerRequest([ 'environment' => [ 'HTTP_REFERER' => Router::url('/foo/bar', true), 'REQUEST_METHOD' => 'POST' @@ -673,7 +681,7 @@ public function testLoginRedirectPost() public function testLoginRedirectPostNoReferer() { $this->Auth->session->delete('Auth'); - $this->Auth->request = new ServerRequest([ + $this->Controller->request = new ServerRequest([ 'environment' => ['REQUEST_METHOD' => 'POST'], 'params' => ['controller' => 'Posts', 'action' => 'view', 'pass' => [1]], 'url' => '/posts/view/1?print=true&refer=menu', @@ -696,7 +704,7 @@ public function testLoginRedirectQueryString() { // QueryString parameters are preserved when redirecting with redirect key $this->Auth->session->delete('Auth'); - $this->Auth->request = new ServerRequest([ + $this->Controller->request = new ServerRequest([ 'environment' => ['REQUEST_METHOD' => 'GET'], 'params' => ['controller' => 'Posts', 'action' => 'view', 'pass' => [29]], 'url' => '/posts/view/29?print=true&refer=menu', @@ -722,7 +730,7 @@ public function testLoginRedirectQueryString() public function testLoginRedirectQueryStringWithComplexLoginActionUrl() { $this->Auth->session->delete('Auth'); - $this->Auth->request = new ServerRequest([ + $this->Controller->request = new ServerRequest([ 'environment' => ['REQUEST_METHOD' => 'GET'], 'params' => ['controller' => 'Posts', 'action' => 'view', 'pass' => [29]], 'url' => '/posts/view/29?print=true&refer=menu', @@ -832,7 +840,7 @@ public function testNoLoginRedirectForAuthenticatedUser() public function testDefaultToLoginRedirect() { $url = '/party/on'; - $this->Auth->request = $request = new ServerRequest([ + $this->Controller->request = $request = new ServerRequest([ 'url' => $url, 'environment' => [ 'HTTP_REFERER' => false, @@ -882,11 +890,11 @@ public function testRedirectToUnauthorizedRedirect() ->setMethods(['set']) ->setConstructorArgs([$this->Controller->components()]) ->getMock(); - $this->Auth->request = $request = new ServerRequest([ + $request = new ServerRequest([ 'url' => $url, - 'session' => $this->Auth->session + 'session' => $this->Auth->session, + 'params' => ['controller' => 'Party', 'action' => 'on'] ]); - $this->Auth->request->addParams(['controller' => 'Party', 'action' => 'on']); $this->Auth->setConfig('authorize', ['Controller']); $this->Auth->setUser(['username' => 'admad', 'password' => 'cake']); @@ -894,19 +902,19 @@ public function testRedirectToUnauthorizedRedirect() $this->Auth->setConfig('unauthorizedRedirect', $expected); $response = new Response(); - $Controller = $this->getMockBuilder('Cake\Controller\Controller') + $controller = $this->getMockBuilder('Cake\Controller\Controller') ->setMethods(['on', 'redirect']) ->setConstructorArgs([$request, $response]) ->getMock(); - $Controller->expects($this->once()) + $controller->expects($this->once()) ->method('redirect') ->with($this->equalTo($expected)); $this->Auth->Flash->expects($this->once()) ->method('set'); - $event = new Event('Controller.startup', $Controller); + $event = new Event('Controller.startup', $controller); $this->Auth->startup($event); } @@ -923,11 +931,11 @@ public function testRedirectToUnauthorizedRedirectLoginAction() ->setMethods(['set']) ->setConstructorArgs([$this->Controller->components()]) ->getMock(); - $this->Auth->request = $request = new ServerRequest([ + $request = new ServerRequest([ 'url' => $url, - 'session' => $this->Auth->session + 'session' => $this->Auth->session, + 'params' => ['controller' => 'Party', 'action' => 'on'] ]); - $this->Auth->request->addParams(['controller' => 'Party', 'action' => 'on']); $this->Auth->setConfig('authorize', ['Controller']); $this->Auth->setUser(['username' => 'admad', 'password' => 'cake']); @@ -935,17 +943,17 @@ public function testRedirectToUnauthorizedRedirectLoginAction() $this->Auth->setConfig('loginAction', '/users/login'); $response = new Response(); - $Controller = $this->getMockBuilder('Cake\Controller\Controller') + $controller = $this->getMockBuilder('Cake\Controller\Controller') ->setMethods(['on', 'redirect']) ->setConstructorArgs([$request, $response]) ->getMock(); // Uses referrer instead of loginAction. - $Controller->expects($this->once()) + $controller->expects($this->once()) ->method('redirect') ->with($this->equalTo('/')); - $event = new Event('Controller.startup', $Controller); + $event = new Event('Controller.startup', $controller); $this->Auth->startup($event); } @@ -961,28 +969,30 @@ public function testRedirectToUnauthorizedRedirectSuppressedAuthError() $this->Auth->session = $this->getMockBuilder(Session::class) ->setMethods(['flash']) ->getMock(); - $this->Auth->request = $Request = new ServerRequest($url); - $this->Auth->request->addParams(['controller' => 'Party', 'action' => 'on']); + $request = new ServerRequest([ + 'url' => $url, + 'params' => ['controller' => 'Party', 'action' => 'on'] + ]); $this->Auth->setConfig('authorize', ['Controller']); $this->Auth->setUser(['username' => 'admad', 'password' => 'cake']); $expected = ['controller' => 'no_can_do', 'action' => 'jack']; $this->Auth->setConfig('unauthorizedRedirect', $expected); $this->Auth->setConfig('authError', false); - $Response = new Response(); - $Controller = $this->getMockBuilder('Cake\Controller\Controller') + $response = new Response(); + $controller = $this->getMockBuilder('Cake\Controller\Controller') ->setMethods(['on', 'redirect']) - ->setConstructorArgs([$Request, $Response]) + ->setConstructorArgs([$request, $response]) ->getMock(); - $Controller->expects($this->once()) + $controller->expects($this->once()) ->method('redirect') ->with($this->equalTo($expected)); $this->Auth->session->expects($this->never()) ->method('flash'); - $event = new Event('Controller.startup', $Controller); + $event = new Event('Controller.startup', $controller); $this->Auth->startup($event); } @@ -995,15 +1005,15 @@ public function testRedirectToUnauthorizedRedirectSuppressedAuthError() public function testForbiddenException() { $this->expectException(\Cake\Http\Exception\ForbiddenException::class); - $url = '/party/on'; - $this->Auth->request = $request = new ServerRequest($url); - $this->Auth->request->addParams(['controller' => 'Party', 'action' => 'on']); $this->Auth->setConfig([ 'authorize' => ['Controller'], 'unauthorizedRedirect' => false ]); $this->Auth->setUser(['username' => 'baker', 'password' => 'cake']); + $request = $this->request + ->withAttribute('params', ['controller' => 'Party', 'action' => 'on']) + ->withRequestTarget('/party/on'); $response = new Response(); $Controller = $this->getMockBuilder('Cake\Controller\Controller') ->setMethods(['on', 'redirect']) @@ -1029,8 +1039,10 @@ public function testNoRedirectOnLoginAction() $controller->methods = ['login']; $url = '/AuthTest/login'; - $this->Auth->request = $controller->request = new ServerRequest($url); - $this->Auth->request->addParams(['controller' => 'AuthTest', 'action' => 'login']); + $this->Controller->request = $this->request + ->withAttribute('params', ['controller' => 'AuthTest', 'action' => 'login']) + ->withRequestTarget($url); + $this->Auth->setConfig([ 'loginAction', ['controller' => 'AuthTest', 'action' => 'login'], 'authorize', ['Controller'] @@ -1053,7 +1065,10 @@ public function testNoRedirectOn404() { $event = new Event('Controller.startup', $this->Controller); $this->Auth->session->delete('Auth'); - $this->Auth->request->addParams(['controller' => 'AuthTest', 'action' => 'something_totally_wrong']); + $this->Controller->request = $this->request->withAttribute( + 'params', + ['controller' => 'AuthTest', 'action' => 'something_totally_wrong'] + ); $result = $this->Auth->startup($event); $this->assertNull($result, 'Auth redirected a missing action %s'); } @@ -1074,7 +1089,7 @@ public function testAdminRoute() Router::scope('/', function ($routes) { $routes->fallbacks(InflectedRoute::class); }); - $this->Auth->request = new ServerRequest([ + $this->Controller->request = new ServerRequest([ 'environment' => [ 'REQUEST_METHOD' => 'GET', ], @@ -1088,7 +1103,7 @@ public function testAdminRoute() 'session' => $this->Auth->session ]); - Router::setRequestInfo($this->Auth->request); + Router::setRequestInfo($this->Controller->request); $this->Auth->setConfig('loginAction', [ 'prefix' => 'admin', @@ -1208,7 +1223,7 @@ public function testLoginActionRedirect() public function testStatelessAuthWorksWithUser() { $event = new Event('Controller.startup', $this->Controller); - $this->Auth->request = new ServerRequest([ + $this->Controller->request = new ServerRequest([ 'environment' => [ 'REQUEST_METHOD' => 'POST', 'PHP_AUTH_USER' => 'mariano', @@ -1320,7 +1335,7 @@ public function testAfterIdentifyForStatelessAuthentication() { $event = new Event('Controller.startup', $this->Controller); $url = '/auth_test/add'; - $this->Auth->request = $this->Auth->request + $this->Controller->request = $this->Controller->request ->withParam('controller', 'AuthTest') ->withParam('action', 'add') ->withEnv('PHP_AUTH_USER', 'mariano') @@ -1352,7 +1367,7 @@ public function testSetUser() { $storage = $this->getMockBuilder('Cake\Auth\Storage\SessionStorage') ->setMethods(['write']) - ->setConstructorArgs([$this->Auth->request, $this->Auth->response]) + ->setConstructorArgs([$this->Controller->request, $this->Auth->response]) ->getMock(); $this->Auth->storage($storage); @@ -1446,7 +1461,7 @@ public function testRedirectSet() public function testRedirectQueryStringRead() { $this->Auth->setConfig('loginAction', ['controller' => 'users', 'action' => 'login']); - $this->Auth->request->query = ['redirect' => '/users/custom']; + $this->Controller->request->query = ['redirect' => '/users/custom']; $result = $this->Auth->redirectUrl(); $this->assertEquals('/users/custom', $result); @@ -1459,12 +1474,12 @@ public function testRedirectQueryStringRead() */ public function testRedirectQueryStringReadDuplicateBase() { - $this->Auth->request->webroot = '/waves/'; - $this->Auth->request->base = '/waves'; + $this->Controller->request->webroot = '/waves/'; + $this->Controller->request->base = '/waves'; - $this->Auth->request->query = ['redirect' => '/waves/add']; + $this->Controller->request->query = ['redirect' => '/waves/add']; - Router::setRequestInfo($this->Auth->request); + Router::setRequestInfo($this->Controller->request); $result = $this->Auth->redirectUrl(); $this->assertEquals('/waves/add', $result); @@ -1482,7 +1497,7 @@ public function testRedirectQueryStringReadEqualToLoginAction() 'loginAction' => ['controller' => 'users', 'action' => 'login'], 'loginRedirect' => ['controller' => 'users', 'action' => 'home'] ]); - $this->Auth->request->query = ['redirect' => '/users/login']; + $this->Controller->request->query = ['redirect' => '/users/login']; $result = $this->Auth->redirectUrl(); $this->assertEquals('/users/home', $result); @@ -1500,12 +1515,12 @@ public function testRedirectQueryStringInvalid() 'loginAction' => ['controller' => 'users', 'action' => 'login'], 'loginRedirect' => ['controller' => 'users', 'action' => 'home'] ]); - $this->Auth->request->query = ['redirect' => 'http://some.domain.example/users/login']; + $this->Controller->request->query = ['redirect' => 'http://some.domain.example/users/login']; $result = $this->Auth->redirectUrl(); $this->assertEquals('/users/home', $result); - $this->Auth->request->query = ['redirect' => '//some.domain.example/users/login']; + $this->Controller->request->query = ['redirect' => '//some.domain.example/users/login']; $result = $this->Auth->redirectUrl(); $this->assertEquals('/users/home', $result); @@ -1528,11 +1543,11 @@ public function testRedirectUrlWithBaseSet() ]); $url = '/users/login'; - $this->Auth->request = $this->Controller->request = new ServerRequest($url); - $this->Auth->request->addParams(['controller' => 'Users', 'action' => 'login']); - $this->Auth->request->url = Router::normalize($url); - - Router::setRequestInfo($this->Auth->request); + $this->Controller->request = $this->Controller->request = new ServerRequest([ + 'url' => $url, + 'params' => ['plugin' => null, 'controller' => 'Users', 'action' => 'login'] + ]); + Router::setRequestInfo($this->Controller->request); $this->Auth->setConfig('loginAction', ['controller' => 'users', 'action' => 'login']); $this->Auth->setConfig('loginRedirect', ['controller' => 'users', 'action' => 'home']); diff --git a/tests/TestCase/Controller/Component/PaginatorComponentTest.php b/tests/TestCase/Controller/Component/PaginatorComponentTest.php index 2d67b8f92fc..3d6126962f7 100644 --- a/tests/TestCase/Controller/Component/PaginatorComponentTest.php +++ b/tests/TestCase/Controller/Component/PaginatorComponentTest.php @@ -80,10 +80,9 @@ public function setUp() static::setAppNamespace(); - $this->request = new ServerRequest('controller_posts/index'); - $this->request->params['pass'] = []; - $controller = new Controller($this->request); - $this->registry = new ComponentRegistry($controller); + $request = new ServerRequest(['url' => 'controller_posts/index']); + $this->controller = new Controller($request); + $this->registry = new ComponentRegistry($this->controller); $this->Paginator = new PaginatorComponent($this->registry, []); $this->Post = $this->getMockRepository(); @@ -151,10 +150,10 @@ public function testPageParamCasting() ->method('find') ->will($this->returnValue($query)); - $this->request->query = ['page' => '1 " onclick="alert(\'xss\');">']; + $this->controller->request = $this->controller->request->withQueryParams(['page' => '1 " onclick="alert(\'xss\');">']); $settings = ['limit' => 1, 'maxLimit' => 10]; $this->Paginator->paginate($this->Post, $settings); - $this->assertSame(1, $this->request->params['paging']['Posts']['page'], 'XSS exploit opened'); + $this->assertSame(1, $this->controller->request->getParam('paging.Posts.page'), 'XSS exploit opened'); } /** @@ -165,7 +164,7 @@ public function testPageParamCasting() */ public function testPaginateExtraParams() { - $this->request->query = ['page' => '-1']; + $this->controller->request = $this->controller->request->withQueryParams(['page' => '-1']); $settings = [ 'PaginatorPosts' => [ 'contain' => ['PaginatorAuthor'], @@ -245,7 +244,7 @@ public function testPaginateCustomFinder() ->will($this->returnValue($query)); $this->Paginator->paginate($table, $settings); - $this->assertEquals('popular', $this->request->params['paging']['PaginatorPosts']['finder']); + $this->assertEquals('popular', $this->controller->request->getParam('paging.PaginatorPosts.finder')); } /** @@ -338,8 +337,8 @@ public function testDefaultPaginateParamsIntoRequest() ]); $this->Paginator->paginate($table, $settings); - $this->assertEquals('PaginatorPosts.id', $this->request->params['paging']['PaginatorPosts']['sortDefault']); - $this->assertEquals('DESC', $this->request->params['paging']['PaginatorPosts']['directionDefault']); + $this->assertEquals('PaginatorPosts.id', $this->controller->request->getParam('paging.PaginatorPosts.sortDefault')); + $this->assertEquals('DESC', $this->controller->request->getParam('paging.PaginatorPosts.directionDefault')); } /** @@ -375,14 +374,14 @@ public function testMergeOptionsModelSpecific() */ public function testMergeOptionsCustomScope() { - $this->request->query = [ + $this->controller->request = $this->controller->request->withQueryParams([ 'page' => 10, 'limit' => 10, 'scope' => [ 'page' => 2, 'limit' => 5, ] - ]; + ]); $settings = [ 'page' => 1, @@ -444,10 +443,10 @@ public function testMergeOptionsCustomScope() */ public function testMergeOptionsCustomFindKey() { - $this->request->query = [ + $this->controller->request = $this->controller->request->withQueryParams([ 'page' => 10, 'limit' => 10 - ]; + ]); $settings = [ 'page' => 1, 'limit' => 20, @@ -472,10 +471,10 @@ public function testMergeOptionsCustomFindKey() */ public function testMergeOptionsQueryString() { - $this->request->query = [ + $this->controller->request = $this->controller->request->withQueryParams([ 'page' => 99, 'limit' => 75 - ]; + ]); $settings = [ 'page' => 1, 'limit' => 20, @@ -493,14 +492,14 @@ public function testMergeOptionsQueryString() */ public function testMergeOptionsDefaultWhiteList() { - $this->request->query = [ + $this->controller->request = $this->controller->request->withQueryParams([ 'page' => 10, 'limit' => 10, 'fields' => ['bad.stuff'], 'recursive' => 1000, 'conditions' => ['bad.stuff'], 'contain' => ['bad'] - ]; + ]); $settings = [ 'page' => 1, 'limit' => 20, @@ -518,14 +517,14 @@ public function testMergeOptionsDefaultWhiteList() */ public function testMergeOptionsExtraWhitelist() { - $this->request->query = [ + $this->controller->request = $this->controller->request->withQueryParams([ 'page' => 10, 'limit' => 10, 'fields' => ['bad.stuff'], 'recursive' => 1000, 'conditions' => ['bad.stuff'], 'contain' => ['bad'] - ]; + ]); $settings = [ 'page' => 1, 'limit' => 20, @@ -646,14 +645,14 @@ public function testValidateSortInvalid() 'scope' => null, ]); - $this->request->query = [ + $this->controller->request = $this->controller->request->withQueryParams([ 'page' => 1, 'sort' => 'id', 'direction' => 'herp' - ]; + ]); $this->Paginator->paginate($table); - $this->assertEquals('PaginatorPosts.id', $this->request->params['paging']['PaginatorPosts']['sort']); - $this->assertEquals('asc', $this->request->params['paging']['PaginatorPosts']['direction']); + $this->assertEquals('PaginatorPosts.id', $this->controller->request->getParam('paging.PaginatorPosts.sort')); + $this->assertEquals('asc', $this->controller->request->getParam('paging.PaginatorPosts.direction')); } /** @@ -693,17 +692,17 @@ public function testEmptyPaginationResult() $this->assertSame( 0, - $this->request->params['paging']['PaginatorPosts']['count'], + $this->controller->request->getParam('paging.PaginatorPosts.count'), 'Count should be 0' ); $this->assertSame( 1, - $this->request->params['paging']['PaginatorPosts']['page'], + $this->controller->request->getParam('paging.PaginatorPosts.page'), 'Page number should not be 0' ); $this->assertSame( 1, - $this->request->params['paging']['PaginatorPosts']['pageCount'], + $this->controller->request->getParam('paging.PaginatorPosts.pageCount'), 'Page count number should not be 0' ); } @@ -716,7 +715,7 @@ public function testEmptyPaginationResult() public function testOutOfRangePageNumberGetsClamped() { $this->loadFixtures('Posts'); - $this->request->query['page'] = 3000; + $this->controller->request = $this->controller->request->withQueryParams(['page' => 3000]); $table = TableRegistry::get('PaginatorPosts'); @@ -728,7 +727,7 @@ public function testOutOfRangePageNumberGetsClamped() $this->assertEquals( 1, - $this->request->params['paging']['PaginatorPosts']['page'], + $this->controller->request->getParam('paging.PaginatorPosts.page'), 'Page number should not be 0' ); @@ -744,8 +743,10 @@ public function testOutOfRangePageNumberGetsClamped() public function testOutOfRangePageNumberStillProvidesPageCount() { $this->loadFixtures('Posts'); - $this->request->query['limit'] = 1; - $this->request->query['page'] = 4; + $this->controller->request = $this->controller->request->withQueryParams([ + 'limit' => 1, + 'page' => '4', + ]); $table = TableRegistry::get('PaginatorPosts'); @@ -757,7 +758,7 @@ public function testOutOfRangePageNumberStillProvidesPageCount() $this->assertEquals( 3, - $this->request->params['paging']['PaginatorPosts']['pageCount'], + $this->controller->request->getParam('paging.PaginatorPosts.pageCount'), 'Page count number should not be 0' ); @@ -774,9 +775,9 @@ public function testOutOfVeryBigPageNumberGetsClamped() { $this->expectException(\Cake\Http\Exception\NotFoundException::class); $this->loadFixtures('Posts'); - $this->request->query = [ + $this->controller->request = $this->controller->request->withQueryParams([ 'page' => '3000000000000000000000000', - ]; + ]); $table = TableRegistry::get('PaginatorPosts'); $this->Paginator->paginate($table); @@ -1084,19 +1085,19 @@ public function testPaginateMaxLimit() $settings = [ 'maxLimit' => 100, ]; - $this->request->query = [ + $this->controller->request = $this->controller->request->withQueryParams([ 'limit' => '1000' - ]; + ]); $this->Paginator->paginate($table, $settings); - $this->assertEquals(100, $this->request->params['paging']['PaginatorPosts']['limit']); - $this->assertEquals(100, $this->request->params['paging']['PaginatorPosts']['perPage']); + $this->assertEquals(100, $this->controller->request->getParam('paging.PaginatorPosts.limit')); + $this->assertEquals(100, $this->controller->request->getParam('paging.PaginatorPosts.perPage')); - $this->request->query = [ + $this->controller->request = $this->controller->request->withQueryParams([ 'limit' => '10' - ]; + ]); $this->Paginator->paginate($table, $settings); - $this->assertEquals(10, $this->request->params['paging']['PaginatorPosts']['limit']); - $this->assertEquals(10, $this->request->params['paging']['PaginatorPosts']['perPage']); + $this->assertEquals(10, $this->controller->request->getParam('paging.PaginatorPosts.limit')); + $this->assertEquals(10, $this->controller->request->getParam('paging.PaginatorPosts.perPage')); } /** @@ -1125,7 +1126,7 @@ public function testPaginateCustomFind() $this->assertCount(4, $result, '4 rows should come back'); $this->assertEquals(['First Post', 'Second Post', 'Third Post', 'Fourth Post'], $titleExtractor($result)); - $result = $this->request->params['paging']['PaginatorPosts']; + $result = $this->controller->request->getParam('paging.PaginatorPosts'); $this->assertEquals(4, $result['current']); $this->assertEquals(4, $result['count']); @@ -1134,7 +1135,7 @@ public function testPaginateCustomFind() $this->assertCount(3, $result, '3 rows should come back'); $this->assertEquals(['First Post', 'Second Post', 'Third Post'], $titleExtractor($result)); - $result = $this->request->params['paging']['PaginatorPosts']; + $result = $this->controller->request->getParam('paging.PaginatorPosts'); $this->assertEquals(3, $result['current']); $this->assertEquals(3, $result['count']); @@ -1143,7 +1144,7 @@ public function testPaginateCustomFind() $this->assertCount(1, $result, '1 rows should come back'); $this->assertEquals(['Third Post'], $titleExtractor($result)); - $result = $this->request->params['paging']['PaginatorPosts']; + $result = $this->controller->request->getParam('paging.PaginatorPosts'); $this->assertEquals(1, $result['current']); $this->assertEquals(3, $result['count']); $this->assertEquals(2, $result['pageCount']); @@ -1153,7 +1154,7 @@ public function testPaginateCustomFind() $this->assertCount(2, $result, '2 rows should come back'); $this->assertEquals(['First Post', 'Second Post'], $titleExtractor($result)); - $result = $this->request->params['paging']['PaginatorPosts']; + $result = $this->controller->request->getParam('paging.PaginatorPosts'); $this->assertEquals(2, $result['current']); $this->assertEquals(3, $result['count']); $this->assertEquals(2, $result['pageCount']); @@ -1189,7 +1190,7 @@ public function testPaginateCustomFindFieldsArray() ]; $this->assertEquals($expected, $result); - $result = $this->request->params['paging']['PaginatorPosts']; + $result = $this->controller->request->getParam('paging.PaginatorPosts'); $this->assertEquals(2, $result['current']); $this->assertEquals(3, $result['count']); $this->assertEquals(2, $result['pageCount']); @@ -1235,7 +1236,7 @@ public function testPaginateCustomFindCount() */ public function testPaginateQuery() { - $this->request->query = ['page' => '-1']; + $this->controller->request = $this->controller->request->withQueryParams(['page' => '-1']); $settings = [ 'PaginatorPosts' => [ 'contain' => ['PaginatorAuthor'], @@ -1293,7 +1294,7 @@ public function testPaginateQueryWithBindValue() */ public function testPaginateQueryWithLimit() { - $this->request->query = ['page' => '-1']; + $this->controller->request->query = ['page' => '-1']; $settings = [ 'PaginatorPosts' => [ 'contain' => ['PaginatorAuthor'], diff --git a/tests/TestCase/Controller/Component/SecurityComponentTest.php b/tests/TestCase/Controller/Component/SecurityComponentTest.php index 5e93543e116..e74ffcde831 100644 --- a/tests/TestCase/Controller/Component/SecurityComponentTest.php +++ b/tests/TestCase/Controller/Component/SecurityComponentTest.php @@ -215,11 +215,11 @@ public function testBlackholeWithBrokenCallback() $this->expectException(\Cake\Http\Exception\BadRequestException::class); $request = new ServerRequest([ 'url' => 'posts/index', - 'session' => $this->Security->session - ]); - $request->addParams([ - 'controller' => 'posts', - 'action' => 'index' + 'session' => $this->Security->session, + 'params' => [ + 'controller' => 'posts', + 'action' => 'index' + ] ]); $Controller = new \TestApp\Controller\SomePagesController($request); $event = new Event('Controller.startup', $Controller); @@ -240,10 +240,10 @@ public function testBlackholeWithBrokenCallback() */ public function testExceptionWhenActionIsBlackholeCallback() { - $this->Controller->request->addParams([ - 'controller' => 'posts', - 'action' => 'fail' - ]); + $this->Controller->request = $this->Controller->request + ->withParam('controller', 'posts') + ->withParam('action', 'fail'); + $event = new Event('Controller.startup', $this->Controller); $this->assertFalse($this->Controller->failed); $this->Controller->Security->startup($event); diff --git a/tests/TestCase/Controller/ControllerTest.php b/tests/TestCase/Controller/ControllerTest.php index 991ee1fc2ae..089e607ff4c 100644 --- a/tests/TestCase/Controller/ControllerTest.php +++ b/tests/TestCase/Controller/ControllerTest.php @@ -812,8 +812,10 @@ public function testInvokeActionMissingAction() { $this->expectException(\Cake\Controller\Exception\MissingActionException::class); $this->expectExceptionMessage('Action TestController::missing() could not be found, or is not accessible.'); - $url = new ServerRequest('test/missing'); - $url->addParams(['controller' => 'Test', 'action' => 'missing']); + $url = new ServerRequest([ + 'url' => 'test/missing', + 'params' => ['controller' => 'Test', 'action' => 'missing'] + ]); $response = $this->getMockBuilder('Cake\Http\Response')->getMock(); $Controller = new TestController($url, $response); @@ -829,8 +831,10 @@ public function testInvokeActionPrivate() { $this->expectException(\Cake\Controller\Exception\MissingActionException::class); $this->expectExceptionMessage('Action TestController::private_m() could not be found, or is not accessible.'); - $url = new ServerRequest('test/private_m/'); - $url->addParams(['controller' => 'Test', 'action' => 'private_m']); + $url = new ServerRequest([ + 'url' => 'test/private_m/', + 'params' => ['controller' => 'Test', 'action' => 'private_m'] + ]); $response = $this->getMockBuilder('Cake\Http\Response')->getMock(); $Controller = new TestController($url, $response); @@ -846,8 +850,10 @@ public function testInvokeActionProtected() { $this->expectException(\Cake\Controller\Exception\MissingActionException::class); $this->expectExceptionMessage('Action TestController::protected_m() could not be found, or is not accessible.'); - $url = new ServerRequest('test/protected_m/'); - $url->addParams(['controller' => 'Test', 'action' => 'protected_m']); + $url = new ServerRequest([ + 'url' => 'test/protected_m/', + 'params' => ['controller' => 'Test', 'action' => 'protected_m'] + ]); $response = $this->getMockBuilder('Cake\Http\Response')->getMock(); $Controller = new TestController($url, $response); @@ -863,8 +869,10 @@ public function testInvokeActionBaseMethods() { $this->expectException(\Cake\Controller\Exception\MissingActionException::class); $this->expectExceptionMessage('Action TestController::redirect() could not be found, or is not accessible.'); - $url = new ServerRequest('test/redirect/'); - $url->addParams(['controller' => 'Test', 'action' => 'redirect']); + $url = new ServerRequest([ + 'url' => 'test/redirect/', + 'params' => ['controller' => 'Test', 'action' => 'redirect'] + ]); $response = $this->getMockBuilder('Cake\Http\Response')->getMock(); $Controller = new TestController($url, $response); @@ -878,11 +886,13 @@ public function testInvokeActionBaseMethods() */ public function testInvokeActionReturnValue() { - $url = new ServerRequest('test/returner/'); - $url->addParams([ - 'controller' => 'Test', - 'action' => 'returner', - 'pass' => [] + $url = new ServerRequest([ + 'url' => 'test/returner/', + 'params' => [ + 'controller' => 'Test', + 'action' => 'returner', + 'pass' => [] + ] ]); $response = $this->getMockBuilder('Cake\Http\Response')->getMock(); @@ -898,11 +908,13 @@ public function testInvokeActionReturnValue() */ public function testInvokeActionWithPassedParams() { - $url = new ServerRequest('test/index/1/2'); - $url->addParams([ - 'controller' => 'Test', - 'action' => 'index', - 'pass' => ['param1' => '1', 'param2' => '2'] + $url = new ServerRequest([ + 'url' => 'test/index/1/2', + 'params' => [ + 'controller' => 'Test', + 'action' => 'index', + 'pass' => ['param1' => '1', 'param2' => '2'] + ] ]); $response = $this->getMockBuilder('Cake\Http\Response')->getMock(); @@ -921,9 +933,9 @@ public function testInvokeActionWithPassedParams() */ public function testViewPathConventions() { - $request = new ServerRequest('admin/posts'); - $request->addParams([ - 'prefix' => 'admin' + $request = new ServerRequest([ + 'url' => 'admin/posts', + 'params' => ['prefix' => 'admin'] ]); $response = $this->getMockBuilder('Cake\Http\Response')->getMock(); $Controller = new \TestApp\Controller\Admin\PostsController($request, $response); @@ -933,9 +945,7 @@ public function testViewPathConventions() $Controller->render(); $this->assertEquals('Admin' . DS . 'Posts', $Controller->viewBuilder()->templatePath()); - $request->addParams([ - 'prefix' => 'admin/super' - ]); + $request = $request->withParam('prefix', 'admin/super'); $response = $this->getMockBuilder('Cake\Http\Response')->getMock(); $Controller = new \TestApp\Controller\Admin\PostsController($request, $response); $Controller->getEventManager()->on('Controller.beforeRender', function (Event $e) { @@ -944,9 +954,11 @@ public function testViewPathConventions() $Controller->render(); $this->assertEquals('Admin' . DS . 'Super' . DS . 'Posts', $Controller->viewBuilder()->templatePath()); - $request = new ServerRequest('pages/home'); - $request->addParams([ - 'prefix' => false + $request = new ServerRequest([ + 'url' => 'pages/home', + 'params' => [ + 'prefix' => false + ] ]); $Controller = new \TestApp\Controller\PagesController($request, $response); $Controller->getEventManager()->on('Controller.beforeRender', function (Event $e) { diff --git a/tests/TestCase/View/Helper/PaginatorHelperTest.php b/tests/TestCase/View/Helper/PaginatorHelperTest.php index f56e605833f..8c23c5a22b4 100644 --- a/tests/TestCase/View/Helper/PaginatorHelperTest.php +++ b/tests/TestCase/View/Helper/PaginatorHelperTest.php @@ -54,19 +54,21 @@ public function setUp() Configure::write('Config.language', 'eng'); $this->View = new View(); $this->Paginator = new PaginatorHelper($this->View); - $this->Paginator->request = new ServerRequest(); - $this->Paginator->request->addParams([ - 'paging' => [ - 'Article' => [ - 'page' => 1, - 'current' => 9, - 'count' => 62, - 'prevPage' => false, - 'nextPage' => true, - 'pageCount' => 7, - 'sort' => null, - 'direction' => null, - 'limit' => null, + $this->Paginator->request = new ServerRequest([ + 'url' => '/', + 'params' => [ + 'paging' => [ + 'Article' => [ + 'page' => 1, + 'current' => 9, + 'count' => 62, + 'prevPage' => false, + 'nextPage' => true, + 'pageCount' => 7, + 'sort' => null, + 'direction' => null, + 'limit' => null, + ] ] ] ]);