From 396dca92c0c8e9f16c35665e5f4d58761905a3f3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Nov 2023 10:47:36 +0900 Subject: [PATCH 1/8] test: update tests to use SiteURI --- tests/system/API/ResponseTraitTest.php | 15 +-- tests/system/Cache/ResponseCacheTest.php | 4 +- tests/system/CommonFunctionsTest.php | 8 +- tests/system/ControllerTest.php | 4 +- tests/system/Filters/InvalidCharsTest.php | 4 +- .../HTTP/IncomingRequestDetectingTest.php | 3 +- tests/system/HTTP/IncomingRequestTest.php | 7 +- tests/system/Helpers/CookieHelperTest.php | 4 +- tests/system/Pager/PagerTest.php | 7 +- .../system/RESTful/ResourceControllerTest.php | 6 +- .../SecurityCSRFCookieRandomizeTokenTest.php | 5 +- .../SecurityCSRFSessionRandomizeTokenTest.php | 51 +++++------ .../Security/SecurityCSRFSessionTest.php | 43 ++++----- tests/system/Security/SecurityTest.php | 91 +++++-------------- tests/system/Validation/ValidationTest.php | 16 ++-- 15 files changed, 110 insertions(+), 158 deletions(-) diff --git a/tests/system/API/ResponseTraitTest.php b/tests/system/API/ResponseTraitTest.php index c867f1b4a94e..708235e9fbd9 100644 --- a/tests/system/API/ResponseTraitTest.php +++ b/tests/system/API/ResponseTraitTest.php @@ -15,7 +15,7 @@ use CodeIgniter\Format\FormatterInterface; use CodeIgniter\Format\JSONFormatter; use CodeIgniter\Format\XMLFormatter; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockIncomingRequest; @@ -42,7 +42,7 @@ protected function setUp(): void $this->formatter = new JSONFormatter(); } - protected function makeController(array $userConfig = [], string $uri = 'http://example.com', array $userHeaders = []) + protected function makeController(array $userConfig = [], string $routePath = '', array $userHeaders = []) { $config = new App(); @@ -73,7 +73,7 @@ protected function makeController(array $userConfig = [], string $uri = 'http:// Factories::injectMock('config', 'Cookie', $cookie); if ($this->request === null) { - $this->request = new MockIncomingRequest($config, new URI($uri), null, new UserAgent()); + $this->request = new MockIncomingRequest($config, new SiteURI($config, $routePath), null, new UserAgent()); $this->response = new MockResponse($config); } @@ -115,7 +115,7 @@ public function resetFormatter(): void public function testNoFormatterJSON(): void { $this->formatter = null; - $controller = $this->makeController([], 'http://codeigniter.com', ['Accept' => 'application/json']); + $controller = $this->makeController([], '', ['Accept' => 'application/json']); $this->invoke($controller, 'respondCreated', [['id' => 3], 'A Custom Reason']); @@ -133,7 +133,7 @@ public function testNoFormatterJSON(): void public function testNoFormatter(): void { $this->formatter = null; - $controller = $this->makeController([], 'http://codeigniter.com', ['Accept' => 'application/json']); + $controller = $this->makeController([], '', ['Accept' => 'application/json']); $this->invoke($controller, 'respondCreated', ['A Custom Reason']); @@ -484,8 +484,9 @@ private function tryValidContentType($mimeType, $contentType): void $original = $_SERVER; $_SERVER['CONTENT_TYPE'] = $mimeType; - $this->makeController([], 'http://codeigniter.com', ['Accept' => $mimeType]); + $this->makeController([], '', ['Accept' => $mimeType]); $this->assertSame($mimeType, $this->request->getHeaderLine('Accept'), 'Request header...'); + $this->response->setContentType($contentType); $this->assertSame($contentType, $this->response->getHeaderLine('Content-Type'), 'Response header pre-response...'); @@ -554,7 +555,7 @@ public function testFormatByRequestNegotiateIfFormatIsNotJsonOrXML(): void } Factories::injectMock('config', 'Cookie', $cookie); - $request = new MockIncomingRequest($config, new URI($config->baseURL), null, new UserAgent()); + $request = new MockIncomingRequest($config, new SiteURI($config), null, new UserAgent()); $response = new MockResponse($config); $controller = new class ($request, $response) { diff --git a/tests/system/Cache/ResponseCacheTest.php b/tests/system/Cache/ResponseCacheTest.php index 12eaeb1a2d23..b34cfce95c37 100644 --- a/tests/system/Cache/ResponseCacheTest.php +++ b/tests/system/Cache/ResponseCacheTest.php @@ -15,7 +15,7 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Response; use CodeIgniter\HTTP\ResponseInterface; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Test\CIUnitTestCase; use Config\App as AppConfig; @@ -53,7 +53,7 @@ private function createIncomingRequest( $appConfig ??= $this->appConfig; - $siteUri = new URI($appConfig->baseURL . $uri); + $siteUri = new SiteURI($appConfig, $uri); if ($query !== []) { $_GET = $_REQUEST = $query; $siteUri->setQueryArray($query); diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index b6702c5a7376..228a24e9a26f 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -18,7 +18,7 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\RedirectResponse; use CodeIgniter\HTTP\Response; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Router\RouteCollection; use CodeIgniter\Session\Handlers\FileHandler; @@ -411,7 +411,7 @@ public function testOldInput(): void $this->routes = $this->createRouteCollection(); Services::injectMock('routes', $this->routes); - $this->request = new MockIncomingRequest($this->config, new URI('http://example.com'), null, new UserAgent()); + $this->request = new MockIncomingRequest($this->config, new SiteURI($this->config), null, new UserAgent()); Services::injectMock('request', $this->request); // setup & ask for a redirect... @@ -446,7 +446,7 @@ public function testOldInputSerializeData(): void $this->routes = $this->createRouteCollection(); Services::injectMock('routes', $this->routes); - $this->request = new MockIncomingRequest($this->config, new URI('http://example.com'), null, new UserAgent()); + $this->request = new MockIncomingRequest($this->config, new SiteURI($this->config), null, new UserAgent()); Services::injectMock('request', $this->request); // setup & ask for a redirect... @@ -481,7 +481,7 @@ public function testOldInputArray(): void $this->routes = $this->createRouteCollection(); Services::injectMock('routes', $this->routes); - $this->request = new MockIncomingRequest($this->config, new URI('http://example.com'), null, new UserAgent()); + $this->request = new MockIncomingRequest($this->config, new SiteURI($this->config), null, new UserAgent()); Services::injectMock('request', $this->request); $locations = [ diff --git a/tests/system/ControllerTest.php b/tests/system/ControllerTest.php index 668cf9b1bc68..14756039c161 100644 --- a/tests/system/ControllerTest.php +++ b/tests/system/ControllerTest.php @@ -16,7 +16,7 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Request; use CodeIgniter\HTTP\Response; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Validation\Exceptions\ValidationException; @@ -58,7 +58,7 @@ protected function setUp(): void parent::setUp(); $this->config = new App(); - $this->request = new IncomingRequest($this->config, new URI('https://somwhere.com'), null, new UserAgent()); + $this->request = new IncomingRequest($this->config, new SiteURI($this->config), null, new UserAgent()); $this->response = new Response($this->config); $this->logger = Services::logger(); } diff --git a/tests/system/Filters/InvalidCharsTest.php b/tests/system/Filters/InvalidCharsTest.php index 6289ae755ce0..a7c40ebe8b20 100644 --- a/tests/system/Filters/InvalidCharsTest.php +++ b/tests/system/Filters/InvalidCharsTest.php @@ -13,7 +13,7 @@ use CodeIgniter\HTTP\CLIRequest; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Security\Exceptions\SecurityException; use CodeIgniter\Test\CIUnitTestCase; @@ -53,7 +53,7 @@ protected function tearDown(): void private function createRequest(): IncomingRequest { $config = new MockAppConfig(); - $uri = new URI(); + $uri = new SiteURI($config); $userAgent = new UserAgent(); $request = $this->getMockBuilder(IncomingRequest::class) ->setConstructorArgs([$config, $uri, null, $userAgent]) diff --git a/tests/system/HTTP/IncomingRequestDetectingTest.php b/tests/system/HTTP/IncomingRequestDetectingTest.php index 481821dd922b..9984e8d825b3 100644 --- a/tests/system/HTTP/IncomingRequestDetectingTest.php +++ b/tests/system/HTTP/IncomingRequestDetectingTest.php @@ -32,8 +32,7 @@ protected function setUp(): void $_POST = $_GET = $_SERVER = $_REQUEST = $_ENV = $_COOKIE = $_SESSION = []; // The URI object is not used in detectPath(). - $origin = 'http://www.example.com/index.php/woot?code=good#pos'; - $this->request = new IncomingRequest(new App(), new URI($origin), null, new UserAgent()); + $this->request = new IncomingRequest(new App(), new SiteURI(new App(), 'woot?code=good#pos'), null, new UserAgent()); } public function testPathDefault(): void diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 9f6114f4875e..f9000d90001f 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -223,7 +223,7 @@ public function testSetValidLocales() $config->defaultLocale = 'es'; $config->baseURL = 'http://example.com/'; - $request = new IncomingRequest($config, new URI(), null, new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), null, new UserAgent()); $request->setValidLocales(['ja']); $request->setLocale('ja'); @@ -901,7 +901,7 @@ public function testExtensionPHP($path, $detectPath): void $_SERVER['REQUEST_URI'] = $path; $_SERVER['SCRIPT_NAME'] = $path; - $request = new IncomingRequest($config, new URI($path), null, new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config, $path), null, new UserAgent()); $this->assertSame($detectPath, $request->detectPath()); } @@ -914,7 +914,8 @@ public function testGetPath(): void public function testSetPath(): void { - $request = new IncomingRequest(new App(), new URI(), null, new UserAgent()); + $config = new App(); + $request = new IncomingRequest($config, new SiteURI($config), null, new UserAgent()); $this->assertSame('', $request->getPath()); $request->setPath('foobar'); diff --git a/tests/system/Helpers/CookieHelperTest.php b/tests/system/Helpers/CookieHelperTest.php index 45796658fecc..73f05123ab88 100755 --- a/tests/system/Helpers/CookieHelperTest.php +++ b/tests/system/Helpers/CookieHelperTest.php @@ -15,7 +15,7 @@ use CodeIgniter\Cookie\Exceptions\CookieException; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Response; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockResponse; @@ -49,7 +49,7 @@ protected function setUp(): void Services::injectMock('response', new MockResponse(new App())); $this->response = Services::response(); - $this->request = new IncomingRequest(new App(), new URI(), null, new UserAgent()); + $this->request = new IncomingRequest(new App(), new SiteURI(new App()), null, new UserAgent()); Services::injectMock('request', $this->request); helper('cookie'); diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index 63ae20d3cd0c..f5059f082b53 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -13,6 +13,7 @@ use CodeIgniter\Config\Factories; use CodeIgniter\HTTP\IncomingRequest; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\URI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Pager\Exceptions\PagerException; @@ -53,7 +54,7 @@ private function createPager(string $requestUri): void $request = new IncomingRequest( $config, - new URI($config->baseURL . ltrim($requestUri, '/')), + new SiteURI($config, ltrim($requestUri, '/')), 'php://input', new UserAgent() ); @@ -70,7 +71,7 @@ public function testSetPathRemembersPath(): void $details = $this->pager->getDetails(); - $this->assertSame('foo/bar', $details['uri']->getPath()); + $this->assertSame('foo/bar', $details['uri']->getRoutePath()); } public function testGetDetailsRecognizesPageQueryVar(): void @@ -474,7 +475,7 @@ public function testBasedURI(): void $request = new IncomingRequest( $config, - new URI(), + new SiteURI($config, 'x/y'), 'php://input', new UserAgent() ); diff --git a/tests/system/RESTful/ResourceControllerTest.php b/tests/system/RESTful/ResourceControllerTest.php index bd52bd0d31a5..284754280929 100644 --- a/tests/system/RESTful/ResourceControllerTest.php +++ b/tests/system/RESTful/ResourceControllerTest.php @@ -17,7 +17,7 @@ use CodeIgniter\Format\XMLFormatter; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Response; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Model; use CodeIgniter\Router\RouteCollection; @@ -312,7 +312,7 @@ public function testJSONFormatOutput(): void $resource = new MockResourceController(); $config = new App(); - $uri = new URI(); + $uri = new SiteURI($config); $agent = new UserAgent(); $request = new IncomingRequest($config, $uri, '', $agent); @@ -340,7 +340,7 @@ public function testXMLFormatOutput(): void $resource = new MockResourceController(); $config = new App(); - $uri = new URI(); + $uri = new SiteURI($config); $agent = new UserAgent(); $request = new IncomingRequest($config, $uri, '', $agent); diff --git a/tests/system/Security/SecurityCSRFCookieRandomizeTokenTest.php b/tests/system/Security/SecurityCSRFCookieRandomizeTokenTest.php index b0c1ef8ec707..a5c014814035 100644 --- a/tests/system/Security/SecurityCSRFCookieRandomizeTokenTest.php +++ b/tests/system/Security/SecurityCSRFCookieRandomizeTokenTest.php @@ -14,7 +14,7 @@ use CodeIgniter\Config\Factories; use CodeIgniter\Cookie\Cookie; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockAppConfig; @@ -74,7 +74,8 @@ public function testCSRFVerifySetNewCookie(): void $_POST['foo'] = 'bar'; $_POST['csrf_test_name'] = $this->randomizedToken; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $config = new MockAppConfig(); + $request = new IncomingRequest($config, new SiteURI($config), null, new UserAgent()); $security = new Security($this->config); diff --git a/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php b/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php index 7c8af63040f4..e16093b76418 100644 --- a/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php +++ b/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php @@ -14,7 +14,7 @@ use CodeIgniter\Config\Factories; use CodeIgniter\Config\Services; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Security\Exceptions\SecurityException; use CodeIgniter\Session\Handlers\ArrayHandler; @@ -25,6 +25,7 @@ use CodeIgniter\Test\Mock\MockSecurity; use CodeIgniter\Test\Mock\MockSession; use CodeIgniter\Test\TestLogger; +use Config\App; use Config\Cookie; use Config\Logger as LoggerConfig; use Config\Security as SecurityConfig; @@ -136,13 +137,19 @@ public function testCSRFVerifyPostNoToken(): void $_SERVER['REQUEST_METHOD'] = 'POST'; unset($_POST['csrf_test_name']); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $security->verify($request); } + private function createIncomingRequest(?App $config = null): IncomingRequest + { + $config ??= new MockAppConfig(); + + return new IncomingRequest($config, new SiteURI($config), null, new UserAgent()); + } + public function testCSRFVerifyPostThrowsExceptionOnNoMatch(): void { $this->expectException(SecurityException::class); @@ -151,8 +158,7 @@ public function testCSRFVerifyPostThrowsExceptionOnNoMatch(): void $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $security->verify($request); @@ -166,8 +172,7 @@ public function testCSRFVerifyPostInvalidToken(): void $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['csrf_test_name'] = '!'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $security->verify($request); @@ -179,8 +184,7 @@ public function testCSRFVerifyPostReturnsSelfOnMatch(): void $_POST['foo'] = 'bar'; $_POST['csrf_test_name'] = $this->randomizedToken; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -192,9 +196,8 @@ public function testCSRFVerifyPOSTHeaderThrowsExceptionOnNoMatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b'); - $security = $this->createSecurity(); $this->expectException(SecurityException::class); @@ -208,9 +211,8 @@ public function testCSRFVerifyPOSTHeaderReturnsSelfOnMatch(): void $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['foo'] = 'bar'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', $this->randomizedToken); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -222,9 +224,8 @@ public function testCSRFVerifyPUTHeaderThrowsExceptionOnNoMatch(): void { $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b'); - $security = $this->createSecurity(); $this->expectException(SecurityException::class); @@ -237,9 +238,8 @@ public function testCSRFVerifyPUTHeaderReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', $this->randomizedToken); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -250,9 +250,8 @@ public function testCSRFVerifyPUTBodyReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setBody("csrf_test_name={$this->randomizedToken}&foo=bar"); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -266,9 +265,8 @@ public function testCSRFVerifyJsonThrowsExceptionOnNoMatch(): void $_SERVER['REQUEST_METHOD'] = 'POST'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005b"}'); - $security = $this->createSecurity(); $security->verify($request); @@ -278,9 +276,8 @@ public function testCSRFVerifyJsonReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setBody('{"csrf_test_name":"' . $this->randomizedToken . '","foo":"bar"}'); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -298,9 +295,8 @@ public function testRegenerateWithFalseSecurityRegenerateProperty(): void $config->regenerate = false; Factories::injectMock('config', 'Security', $config); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - - $security = new MockSecurity($this->config); + $request = $this->createIncomingRequest(); + $security = new MockSecurity($config); $oldHash = $security->getHash(); $security->verify($request); @@ -319,8 +315,7 @@ public function testRegenerateWithTrueSecurityRegenerateProperty(): void $config->regenerate = true; Factories::injectMock('config', 'Security', $config); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $oldHash = $security->getHash(); diff --git a/tests/system/Security/SecurityCSRFSessionTest.php b/tests/system/Security/SecurityCSRFSessionTest.php index 1d701520488c..cc5b56eae33a 100644 --- a/tests/system/Security/SecurityCSRFSessionTest.php +++ b/tests/system/Security/SecurityCSRFSessionTest.php @@ -14,7 +14,7 @@ use CodeIgniter\Config\Factories; use CodeIgniter\Config\Services; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Security\Exceptions\SecurityException; use CodeIgniter\Session\Handlers\ArrayHandler; @@ -24,6 +24,7 @@ use CodeIgniter\Test\Mock\MockAppConfig; use CodeIgniter\Test\Mock\MockSession; use CodeIgniter\Test\TestLogger; +use Config\App; use Config\Cookie; use Config\Logger as LoggerConfig; use Config\Security as SecurityConfig; @@ -125,21 +126,26 @@ public function testCSRFVerifyPostThrowsExceptionOnNoMatch(): void $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $security->verify($request); } + private function createIncomingRequest(?App $config = null): IncomingRequest + { + $config ??= new MockAppConfig(); + + return new IncomingRequest($config, new SiteURI($config), null, new UserAgent()); + } + public function testCSRFVerifyPostReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['foo'] = 'bar'; $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -151,9 +157,8 @@ public function testCSRFVerifyPOSTHeaderThrowsExceptionOnNoMatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b'); - $security = $this->createSecurity(); $this->expectException(SecurityException::class); @@ -165,9 +170,8 @@ public function testCSRFVerifyPOSTHeaderReturnsSelfOnMatch(): void $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['foo'] = 'bar'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -179,9 +183,8 @@ public function testCSRFVerifyPUTHeaderThrowsExceptionOnNoMatch(): void { $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b'); - $security = $this->createSecurity(); $this->expectException(SecurityException::class); @@ -192,9 +195,8 @@ public function testCSRFVerifyPUTHeaderReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -205,9 +207,8 @@ public function testCSRFVerifyPUTBodyReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setBody('csrf_test_name=8b9218a55906f9dcc1dc263dce7f005a&foo=bar'); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -220,9 +221,8 @@ public function testCSRFVerifyJsonThrowsExceptionOnNoMatch(): void $_SERVER['REQUEST_METHOD'] = 'POST'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005b"}'); - $security = $this->createSecurity(); $security->verify($request); @@ -232,9 +232,8 @@ public function testCSRFVerifyJsonReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a","foo":"bar"}'); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -251,8 +250,7 @@ public function testRegenerateWithFalseSecurityRegenerateProperty(): void $config->regenerate = false; Factories::injectMock('config', 'Security', $config); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $oldHash = $security->getHash(); @@ -271,8 +269,7 @@ public function testRegenerateWithTrueSecurityRegenerateProperty(): void $config->regenerate = true; Factories::injectMock('config', 'Security', $config); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $oldHash = $security->getHash(); diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index ae4953607662..f10c79e5fb7c 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -14,7 +14,7 @@ use CodeIgniter\Config\Factories; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Request; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Security\Exceptions\SecurityException; use CodeIgniter\Test\CIUnitTestCase; @@ -101,17 +101,24 @@ public function testCSRFVerifyPostThrowsExceptionOnNoMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $this->expectException(SecurityException::class); $security->verify($request); } + private function createIncomingRequest(): IncomingRequest + { + $config = new MockAppConfig(); + + return new IncomingRequest( + $config, + new SiteURI($config), + null, + new UserAgent() + ); + } + public function testCSRFVerifyPostReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; @@ -120,12 +127,7 @@ public function testCSRFVerifyPostReturnsSelfOnMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $this->assertInstanceOf(Security::class, $security->verify($request)); $this->assertLogged('info', 'CSRF token verified.'); @@ -139,12 +141,7 @@ public function testCSRFVerifyHeaderThrowsExceptionOnNoMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); @@ -159,12 +156,7 @@ public function testCSRFVerifyHeaderReturnsSelfOnMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); @@ -180,12 +172,7 @@ public function testCSRFVerifyJsonThrowsExceptionOnNoMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $request->setBody( '{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a"}' @@ -201,12 +188,7 @@ public function testCSRFVerifyJsonReturnsSelfOnMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $request->setBody( '{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a","foo":"bar"}' @@ -224,12 +206,7 @@ public function testCSRFVerifyPutBodyThrowsExceptionOnNoMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $request->setBody( 'csrf_test_name=8b9218a55906f9dcc1dc263dce7f005a' @@ -245,12 +222,7 @@ public function testCSRFVerifyPutBodyReturnsSelfOnMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $request->setBody( 'csrf_test_name=8b9218a55906f9dcc1dc263dce7f005a&foo=bar' @@ -282,12 +254,7 @@ public function testRegenerateWithFalseSecurityRegenerateProperty(): void Factories::injectMock('config', 'Security', $config); $security = new MockSecurity($config); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $oldHash = $security->getHash(); $security->verify($request); @@ -307,12 +274,7 @@ public function testRegenerateWithFalseSecurityRegeneratePropertyManually(): voi Factories::injectMock('config', 'Security', $config); $security = $this->createMockSecurity($config); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $oldHash = $security->getHash(); $security->verify($request); @@ -333,12 +295,7 @@ public function testRegenerateWithTrueSecurityRegenerateProperty(): void Factories::injectMock('config', 'Security', $config); $security = $this->createMockSecurity($config); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $oldHash = $security->getHash(); $security->verify($request); diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index 7cc6f99c40d5..fbc8f2ace5f6 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -12,7 +12,7 @@ namespace CodeIgniter\Validation; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Validation\Exceptions\ValidationException; @@ -748,7 +748,7 @@ public function testRawInput(): void $rawstring = 'username=admin001&role=administrator&usepass=0'; $config = new App(); $config->baseURL = 'http://example.com/'; - $request = new IncomingRequest($config, new URI(), $rawstring, new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), $rawstring, new UserAgent()); $rules = [ 'role' => 'required|min_length[5]', @@ -772,7 +772,7 @@ public function testJsonInput(): void $json = json_encode($data); $config = new App(); $config->baseURL = 'http://example.com/'; - $request = new IncomingRequest($config, new URI(), $json, new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), $json, new UserAgent()); $rules = [ 'role' => 'required|min_length[5]', @@ -809,7 +809,7 @@ public function testJsonInputObjectArray(): void $config = new App(); $config->baseURL = 'http://example.com/'; - $request = new IncomingRequest($config, new URI(), $json, new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), $json, new UserAgent()); $rules = [ 'p' => 'required|array_count[2]', @@ -995,7 +995,7 @@ public function testRulesForArrayField(array $body, array $rules, array $results $config = new App(); $config->baseURL = 'http://example.com/'; - $request = new IncomingRequest($config, new URI(), http_build_query($body), new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), http_build_query($body), new UserAgent()); $this->validation->setRules($rules); $this->validation->withRequest($request->withMethod('post'))->run($body); @@ -1074,7 +1074,7 @@ public function testRulesForSingleRuleWithAsteriskWillReturnNoError(): void ], ]; - $request = new IncomingRequest($config, new URI(), 'php://input', new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), 'php://input', new UserAgent()); $this->validation->setRules([ 'id_user.*' => 'numeric', @@ -1108,7 +1108,7 @@ public function testRulesForSingleRuleWithAsteriskWillReturnError(): void ], ]; - $request = new IncomingRequest($config, new URI(), 'php://input', new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), 'php://input', new UserAgent()); $this->validation->setRules([ 'id_user.*' => 'numeric', @@ -1144,7 +1144,7 @@ public function testRulesForSingleRuleWithSingleValue(): void 'id_user' => 'gh', ]; - $request = new IncomingRequest($config, new URI(), 'php://input', new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), 'php://input', new UserAgent()); $this->validation->setRules([ 'id_user' => 'numeric', From ee7020f2185de2a9ccfca915631643e6b41eebf4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Nov 2023 06:49:06 +0900 Subject: [PATCH 2/8] docs: add missing `get` in method name --- user_guide_src/source/incoming/routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 92daf06b7be6..3ba27117468f 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -763,7 +763,7 @@ when a controller is found that matches the URI, but no segment exists for the m ``index``. In this example, if the user were to visit **example.com/products**, and a ``Products`` controller existed, the -``Products::listAll()`` method would be executed: +``Products::getListAll()`` method would be executed: .. literalinclude:: routing/048.php From 0cdd2996588e3f0c5383d35ece4c5e55a3fb601e Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Nov 2023 07:05:13 +0900 Subject: [PATCH 3/8] docs: add about Controller returns string/Response --- user_guide_src/source/incoming/controllers.rst | 4 +++- user_guide_src/source/installation/upgrade_controllers.rst | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index bf5a747cb462..eda94fcf447a 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -11,7 +11,9 @@ Controllers are the heart of your application, as they determine how HTTP reques What is a Controller? ********************* -A Controller is simply a class file that handles a HTTP request. :doc:`URI Routing ` associates a URI with a controller. +A Controller is simply a class file that handles a HTTP request. +:doc:`URI Routing ` associates a URI with a controller. It returns a +view string or ``Response`` object. Every controller you create should extend ``BaseController`` class. This class provides several features that are available to all of your controllers. diff --git a/user_guide_src/source/installation/upgrade_controllers.rst b/user_guide_src/source/installation/upgrade_controllers.rst index cd5f17fd3d22..1a2dc9a9b4ce 100644 --- a/user_guide_src/source/installation/upgrade_controllers.rst +++ b/user_guide_src/source/installation/upgrade_controllers.rst @@ -20,6 +20,8 @@ What has been changed - CI4 provides :doc:`Request ` and :doc:`Responses ` objects for you to work with - more powerful than the CI3-way. - If you want a base controller (``MY_Controller`` in CI3), use **app/Controllers/BaseController.php**. +- Calling ``echo`` within Controllers, as in CI3, is still supported, but + it is recommended that a string or Response object be returned from Controllers. Upgrade Guide ============= From fbd0ebe7e6c82340ef4cb1ac0db74f8944a8cb2a Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Nov 2023 08:33:27 +0900 Subject: [PATCH 4/8] docs: change expressions --- user_guide_src/source/models/model.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 6a2700520fd0..d8cefa02c1cb 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -180,13 +180,13 @@ $createdField ^^^^^^^^^^^^^ Specifies which database field to use for data record create timestamp. -Leave it empty (``''``) to avoid updating it (even if ``$useTimestamps`` is enabled). +Set to an empty string (``''``) to avoid updating it (even if ``$useTimestamps`` is enabled). $updatedField ^^^^^^^^^^^^^ Specifies which database field should use for keep data record update timestamp. -Leave it empty (``''``) to avoid updating it (even ``$useTimestamps`` is enabled). +Set to an empty string (``''``) to avoid updating it (even ``$useTimestamps`` is enabled). $deletedField ^^^^^^^^^^^^^ From ac4430863401c15882b33fc7fa6625391ef85690 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Nov 2023 09:04:53 +0900 Subject: [PATCH 5/8] docs: change model event order Place batch methods after. --- user_guide_src/source/models/model.rst | 47 +++++++++++++++----------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index d8cefa02c1cb..e6b6ec448b16 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -244,18 +244,10 @@ $beforeInsert ^^^^^^^^^^^^^ $afterInsert ^^^^^^^^^^^^ -$beforeInsertBatch -^^^^^^^^^^^^^^^^^^ -$afterInsertBatch -^^^^^^^^^^^^^^^^^ $beforeUpdate ^^^^^^^^^^^^^ $afterUpdate ^^^^^^^^^^^^^ -$beforeUpdateBatch -^^^^^^^^^^^^^^^^^^ -$afterUpdateBatch -^^^^^^^^^^^^^^^^^ $beforeFind ^^^^^^^^^^^ $afterFind @@ -264,6 +256,14 @@ $beforeDelete ^^^^^^^^^^^^^ $afterDelete ^^^^^^^^^^^^ +$beforeInsertBatch +^^^^^^^^^^^^^^^^^^ +$afterInsertBatch +^^^^^^^^^^^^^^^^^ +$beforeUpdateBatch +^^^^^^^^^^^^^^^^^^ +$afterUpdateBatch +^^^^^^^^^^^^^^^^^ These arrays allow you to specify callback methods that will be run on the data at the time specified in the property name. @@ -718,10 +718,17 @@ Model Events ************ There are several points within the model's execution that you can specify multiple callback methods to run. -These methods can be used to normalize data, hash passwords, save related entities, and much more. The following -points in the model's execution can be affected, each through a class property: ``$beforeInsert``, ``$afterInsert``, -``$beforeInsertBatch``, ``$afterInsertBatch``, ``$beforeUpdate``, ``$afterUpdate``, ``$beforeUpdateBatch``, -``$afterUpdateBatch``, ``$afterFind``, and ``$afterDelete``. +These methods can be used to normalize data, hash passwords, save related entities, and much more. + +The following +points in the model's execution can be affected, each through a class property: + +- `$beforeInsert`_, `$afterInsert`_ +- `$beforeUpdate`_, `$afterUpdate`_ +- `$beforeFind`_, `$afterFind`_ +- `$beforeDelete`_, `$afterDelete`_ +- `$beforeInsertBatch`_, `$afterInsertBatch`_ +- `$beforeUpdateBatch`_, `$afterUpdateBatch`_ .. note:: ``$beforeInsertBatch``, ``$afterInsertBatch``, ``$beforeUpdateBatch`` and ``$afterUpdateBatch`` can be used since v4.3.0. @@ -769,20 +776,12 @@ beforeInsert **data** = the key/value pairs that are being inserted. If an afterInsert **id** = the primary key of the new row, or 0 on failure. **data** = the key/value pairs being inserted. **result** = the results of the insert() method used through the Query Builder. -beforeInsertBatch **data** = associative array of values that are being inserted. If an object or Entity class is passed to the - insertBatch method, it is first converted to an array. -afterInsertBatch **data** = the associative array of values being inserted. - **result** = the results of the insertbatch() method used through the Query Builder. beforeUpdate **id** = the array of primary keys of the rows being updated. **data** = the key/value pairs that are being updated. If an object or Entity class is passed to the update method, it is first converted to an array. afterUpdate **id** = the array of primary keys of the rows being updated. **data** = the key/value pairs being updated. **result** = the results of the update() method used through the Query Builder. -beforeUpdateBatch **data** = associative array of values that are being updated. If an object or Entity class is passed to the - updateBatch method, it is first converted to an array. -afterUpdateBatch **data** = the key/value pairs being updated. - **result** = the results of the updateBatch() method used through the Query Builder. beforeFind The name of the calling **method**, whether a **singleton** was requested, and these additional fields: - first() No additional fields - find() **id** = the primary key of the row being searched for. @@ -796,6 +795,14 @@ afterDelete **id** = primary key of row being deleted. **purge** = boolean whether soft-delete rows should be hard deleted. **result** = the result of the delete() call on the Query Builder. **data** = unused. +beforeInsertBatch **data** = associative array of values that are being inserted. If an object or Entity class is passed to the + insertBatch method, it is first converted to an array. +afterInsertBatch **data** = the associative array of values being inserted. + **result** = the results of the insertbatch() method used through the Query Builder. +beforeUpdateBatch **data** = associative array of values that are being updated. If an object or Entity class is passed to the + updateBatch method, it is first converted to an array. +afterUpdateBatch **data** = the key/value pairs being updated. + **result** = the results of the updateBatch() method used through the Query Builder. ================= ========================================================================================================= Modifying Find* Data From ab2d13de0e474cc214834130c20cb79295094cfc Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Nov 2023 09:15:05 +0900 Subject: [PATCH 6/8] docs: make property names links --- user_guide_src/source/models/model.rst | 52 +++++++++++++------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index e6b6ec448b16..a83ca4082130 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -111,12 +111,12 @@ is used with methods like ``find()`` to know what column to match the specified $useAutoIncrement ----------------- -Specifies if the table uses an auto-increment feature for ``$primaryKey``. If set to ``false`` +Specifies if the table uses an auto-increment feature for `$primaryKey`_. If set to ``false`` then you are responsible for providing primary key value for every record in the table. This feature may be handy when we want to implement 1:1 relation or use UUIDs for our model. The default value is ``true``. -.. note:: If you set ``$useAutoIncrement`` to ``false``, then make sure to set your primary +.. note:: If you set `$useAutoIncrement`_ to ``false``, then make sure to set your primary key in the database to ``unique``. This way you will make sure that all of Model's features will still work the same as before. @@ -142,8 +142,8 @@ part of a security trail. If true, the **find*()** methods will only return non- the ``withDeleted()`` method is called prior to calling the **find*()** method. This requires either a DATETIME or INTEGER field in the database as per the model's -``$dateFormat`` setting. The default field name is ``deleted_at`` however this name can be -configured to any name of your choice by using ``$deletedField`` property. +`$dateFormat`_ setting. The default field name is ``deleted_at`` however this name can be +configured to any name of your choice by using `$deletedField`_ property. .. important:: The ``deleted_at`` field must be nullable. @@ -155,7 +155,7 @@ This array should be updated with the field names that can be set during ``save( against just taking input from a form and throwing it all at the model, resulting in potential mass assignment vulnerabilities. -.. note:: The ``$primaryKey`` field should never be an allowed field. +.. note:: The `$primaryKey`_ field should never be an allowed field. Dates ----- @@ -164,29 +164,29 @@ $useTimestamps ^^^^^^^^^^^^^^ This boolean value determines whether the current date is automatically added to all inserts -and updates. If true, will set the current time in the format specified by ``$dateFormat``. This +and updates. If ``true``, will set the current time in the format specified by `$dateFormat`_. This requires that the table have columns named **created_at**, **updated_at** and **deleted_at** in the appropriate data type. $dateFormat ^^^^^^^^^^^ -This value works with ``$useTimestamps`` and ``$useSoftDeletes`` to ensure that the correct type of +This value works with `$useTimestamps`_ and `$useSoftDeletes`_ to ensure that the correct type of date value gets inserted into the database. By default, this creates DATETIME values, but -valid options are: ``'datetime'``, ``'date'``, or ``'int'`` (a PHP timestamp). Using **useSoftDeletes** or -**useTimestamps** with an invalid or missing **dateFormat** will cause an exception. +valid options are: ``'datetime'``, ``'date'``, or ``'int'`` (a PHP timestamp). Using `$useSoftDeletes`_ or +`$useTimestamps`_ with an invalid or missing `$dateFormat`_ will cause an exception. $createdField ^^^^^^^^^^^^^ Specifies which database field to use for data record create timestamp. -Set to an empty string (``''``) to avoid updating it (even if ``$useTimestamps`` is enabled). +Set to an empty string (``''``) to avoid updating it (even if `$useTimestamps`_ is enabled). $updatedField ^^^^^^^^^^^^^ Specifies which database field should use for keep data record update timestamp. -Set to an empty string (``''``) to avoid updating it (even ``$useTimestamps`` is enabled). +Set to an empty string (``''``) to avoid updating it (even `$useTimestamps`_ is enabled). $deletedField ^^^^^^^^^^^^^ @@ -284,7 +284,7 @@ Returns a single row where the primary key matches the value passed in as the fi .. literalinclude:: model/006.php -The value is returned in the format specified in ``$returnType``. +The value is returned in the format specified in `$returnType`_. You can specify more than one row to return by passing an array of primaryKey values instead of just one: @@ -329,7 +329,7 @@ Returns the first row in the result set. This is best used in combination with t withDeleted() ------------- -If ``$useSoftDeletes`` is true, then the **find*()** methods will not return any rows where ``deleted_at IS NOT NULL``. +If `$useSoftDeletes`_ is true, then the **find*()** methods will not return any rows where ``deleted_at IS NOT NULL``. To temporarily override this, you can use the ``withDeleted()`` method prior to calling the **find*()** method. .. literalinclude:: model/013.php @@ -351,7 +351,7 @@ insert() The first parameter is an associative array of data to create a new row of data in the database. If an object is passed instead of an array, it will attempt to convert it to an array. -The array's keys must match the name of the columns in the ``$table``, while the array's values are the values to save for that key. +The array's keys must match the name of the columns in the `$table`_, while the array's values are the values to save for that key. The optional second parameter is of type boolean, and if it is set to false, the method will return a boolean value, which indicates the success or failure of the query. @@ -376,15 +376,15 @@ You can enable the check again by calling ``allowEmptyInserts(false)``. update() -------- -Updates an existing record in the database. The first parameter is the ``$primaryKey`` of the record to update. +Updates an existing record in the database. The first parameter is the `$primaryKey`_ of the record to update. An associative array of data is passed into this method as the second parameter. The array's keys must match the name -of the columns in a ``$table``, while the array's values are the values to save for that key: +of the columns in a `$table`_, while the array's values are the values to save for that key: .. literalinclude:: model/016.php .. important:: Since v4.3.0, this method raises a ``DatabaseException`` if it generates an SQL statement without a WHERE clause. - In previous versions, if it is called without ``$primaryKey`` specified and + In previous versions, if it is called without `$primaryKey`_ specified and an SQL statement was generated without a WHERE clause, the query would still execute and all records in the table would be updated. @@ -440,7 +440,7 @@ Takes a primary key value as the first parameter and deletes the matching record .. literalinclude:: model/023.php -If the model's ``$useSoftDeletes`` value is true, this will update the row to set ``deleted_at`` to the current +If the model's `$useSoftDeletes`_ value is true, this will update the row to set ``deleted_at`` to the current date and time. You can force a permanent delete by setting the second parameter as true. An array of primary keys can be passed in as the first parameter to delete multiple records at once: @@ -481,13 +481,13 @@ prior to saving to the database with the ``insert()``, ``update()``, or ``save() Setting Validation Rules ------------------------ -The first step is to fill out the ``$validationRules`` class property with the fields and rules that should -be applied. If you have custom error message that you want to use, place them in the ``$validationMessages`` array: +The first step is to fill out the `$validationRules`_ class property with the fields and rules that should +be applied. If you have custom error message that you want to use, place them in the `$validationMessages`_ array: .. literalinclude:: model/027.php If you'd rather organize your rules and error messages within the Validation configuration file, you can do that -and simply set ``$validationRules`` to the name of the validation rule group you created: +and simply set `$validationRules`_ to the name of the validation rule group you created: .. literalinclude:: model/034.php @@ -614,7 +614,7 @@ Protecting Fields ================= To help protect against Mass Assignment Attacks, the Model class **requires** that you list all of the field names -that can be changed during inserts and updates in the ``$allowedFields`` class property. Any data provided +that can be changed during inserts and updates in the `$allowedFields`_ class property. Any data provided in addition to these will be removed prior to hitting the database. This is great for ensuring that timestamps, or primary keys do not get changed. @@ -629,7 +629,7 @@ Runtime Return Type Changes =========================== You can specify the format that data should be returned as when using the **find*()** methods as the class property, -``$returnType``. There may be times that you would like the data back in a different format, though. The Model +`$returnType`_. There may be times that you would like the data back in a different format, though. The Model provides methods that allow you to do just that. .. note:: These methods only change the return type for the next **find*()** method call. After that, @@ -674,7 +674,7 @@ You can get access to the **shared** instance of the Query Builder any time you .. literalinclude:: model/043.php -This builder is already set up with the model's ``$table``. +This builder is already set up with the model's `$table`_. .. note:: Once you get the Query Builder instance, you can call methods of the :doc:`Query Builder <../database/query_builder>`. @@ -748,13 +748,13 @@ must return the original $data array so other callbacks have the full informatio Specifying Callbacks To Run =========================== -You specify when to run the callbacks by adding the method name to the appropriate class property (``$beforeInsert``, ``$afterUpdate``, +You specify when to run the callbacks by adding the method name to the appropriate class property (`$beforeInsert`_, `$afterUpdate`_, etc). Multiple callbacks can be added to a single event and they will be processed one after the other. You can use the same callback in multiple events: .. literalinclude:: model/051.php -Additionally, each model may allow (default) or deny callbacks class-wide by setting its ``$allowCallbacks`` property: +Additionally, each model may allow (default) or deny callbacks class-wide by setting its `$allowCallbacks`_ property: .. literalinclude:: model/052.php From de0f67fc1ca86a8680d1599d261b335c183a7c26 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Nov 2023 09:16:27 +0900 Subject: [PATCH 7/8] docs: add references in page --- user_guide_src/source/models/model.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index a83ca4082130..5481265231e9 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -166,7 +166,7 @@ $useTimestamps This boolean value determines whether the current date is automatically added to all inserts and updates. If ``true``, will set the current time in the format specified by `$dateFormat`_. This requires that the table have columns named **created_at**, **updated_at** and **deleted_at** in the appropriate -data type. +data type. See also `$createdField`_, `$updatedField`_, and `$deletedField`_. $dateFormat ^^^^^^^^^^^ @@ -238,7 +238,7 @@ Callbacks $allowCallbacks ^^^^^^^^^^^^^^^ -Whether the callbacks defined below should be used. +Whether the callbacks defined below should be used. See :ref:`model-events`. $beforeInsert ^^^^^^^^^^^^^ @@ -266,7 +266,7 @@ $afterUpdateBatch ^^^^^^^^^^^^^^^^^ These arrays allow you to specify callback methods that will be run on the data at the -time specified in the property name. +time specified in the property name. See :ref:`model-events`. Working with Data ***************** @@ -714,6 +714,8 @@ and specify the model's method at the end of the method chaining. .. literalinclude:: model/046.php +.. _model-events: + Model Events ************ From aed2800f94d9914192dc136893e2b46548eb33a5 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 13 Nov 2023 17:08:06 +0700 Subject: [PATCH 8/8] [Rector] Fix deprecated dynamic pull phpDocInfoFactory from AbstractRector on UnderscoreToCamelCaseVariableNameRector --- utils/Rector/UnderscoreToCamelCaseVariableNameRector.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php b/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php index 3cadde86d3f7..4af0be534e61 100644 --- a/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php +++ b/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php @@ -21,6 +21,7 @@ use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Function_; use PhpParser\Node\Stmt\Namespace_; +use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\Core\Php\ReservedKeywordAnalyzer; use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace; use Rector\Core\Rector\AbstractRector; @@ -39,12 +40,15 @@ final class UnderscoreToCamelCaseVariableNameRector extends AbstractRector private const PARAM_NAME_REGEX = '#(?@param\s.*\s+\$)(?%s)#ms'; private ReservedKeywordAnalyzer $reservedKeywordAnalyzer; + private PhpDocInfoFactory $phpDocInfoFactory; private bool $hasChanged = false; public function __construct( - ReservedKeywordAnalyzer $reservedKeywordAnalyzer + ReservedKeywordAnalyzer $reservedKeywordAnalyzer, + PhpDocInfoFactory $phpDocInfoFactory ) { $this->reservedKeywordAnalyzer = $reservedKeywordAnalyzer; + $this->phpDocInfoFactory = $phpDocInfoFactory; } public function getRuleDefinition(): RuleDefinition