Merge branch 'develop' into 4.6

This commit is contained in:
John Paul E. Balandan, CPA 2024-12-02 00:20:53 +08:00
commit 9fba8c7a49
No known key found for this signature in database
GPG Key ID: 697D84680E3738DA
9 changed files with 119 additions and 228 deletions

View File

@ -12133,12 +12133,6 @@ $ignoreErrors[] = [
'count' => 1,
'path' => __DIR__ . '/tests/system/Commands/Translation/LocalizationFinderTest.php',
];
$ignoreErrors[] = [
// identifier: missingType.return
'message' => '#^Method CodeIgniter\\\\Commands\\\\Utilities\\\\ConfigCheckTest\\:\\:getBuffer\\(\\) has no return type specified\\.$#',
'count' => 1,
'path' => __DIR__ . '/tests/system/Commands/Utilities/ConfigCheckTest.php',
];
$ignoreErrors[] = [
// identifier: missingType.return
'message' => '#^Method CodeIgniter\\\\Commands\\\\Utilities\\\\NamespacesTest\\:\\:getBuffer\\(\\) has no return type specified\\.$#',

View File

@ -211,7 +211,7 @@ class Services extends BaseService
return new CURLRequest(
$config,
new URI($options['base_uri'] ?? null),
new URI($options['baseURI'] ?? null),
$response,
$options
);

View File

@ -150,8 +150,9 @@ class Connection extends BaseConnection
*/
public function reconnect()
{
if (pg_ping($this->connID) === false) {
$this->connID = false;
if ($this->connID === false || pg_ping($this->connID) === false) {
$this->close();
$this->initialize();
}
}

View File

@ -356,9 +356,9 @@ class ContentSecurityPolicy
}
/**
* Adds a new base_uri value. Can be either a URI class or a simple string.
* Adds a new baseURI value. Can be either a URI class or a simple string.
*
* base_uri restricts the URLs that can appear in a page's <base> element.
* baseURI restricts the URLs that can appear in a page's <base> element.
*
* @see http://www.w3.org/TR/CSP/#directive-base-uri
*

View File

@ -13,9 +13,12 @@ declare(strict_types=1);
namespace CodeIgniter\Commands\Utilities;
use Closure;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\StreamFilterTrait;
use Config\App;
use Kint\Kint;
use Kint\Renderer\CliRenderer;
use PHPUnit\Framework\Attributes\Group;
/**
@ -26,6 +29,26 @@ final class ConfigCheckTest extends CIUnitTestCase
{
use StreamFilterTrait;
public static function setUpBeforeClass(): void
{
App::$override = false;
putenv('NO_COLOR=1');
CliRenderer::$cli_colors = false;
parent::setUpBeforeClass();
}
public static function tearDownAfterClass(): void
{
App::$override = true;
putenv('NO_COLOR');
CliRenderer::$cli_colors = true;
parent::tearDownAfterClass();
}
protected function setUp(): void
{
$this->resetServices();
@ -38,188 +61,71 @@ final class ConfigCheckTest extends CIUnitTestCase
parent::tearDown();
}
protected function getBuffer()
{
return $this->getStreamFilterBuffer();
}
public function testCommandConfigCheckNoArg(): void
public function testCommandConfigCheckWithNoArgumentPassed(): void
{
command('config:check');
$this->assertStringContainsString(
'You must specify a Config classname.',
$this->getBuffer()
$this->assertSame(
<<<'EOF'
You must specify a Config classname.
Usage: config:check <classname>
Example: config:check App
config:check 'CodeIgniter\Shield\Config\Auth'
EOF,
str_replace("\n\n", "\n", $this->getStreamFilterBuffer())
);
}
public function testCommandConfigCheckApp(): void
{
command('config:check App');
$this->assertStringContainsString(App::class, $this->getBuffer());
$this->assertStringContainsString("public 'baseURL", $this->getBuffer());
}
public function testCommandConfigCheckNonexistentClass(): void
{
command('config:check Nonexistent');
$this->assertStringContainsString(
'No such Config class: Nonexistent',
$this->getBuffer()
$this->assertSame(
"No such Config class: Nonexistent\n",
$this->getStreamFilterBuffer()
);
}
public function testGetKintD(): void
public function testConfigCheckWithKintEnabledUsesKintD(): void
{
$command = new ConfigCheck(service('logger'), service('commands'));
$getKintD = $this->getPrivateMethodInvoker($command, 'getKintD');
/** @var Closure(object): string $command */
$command = $this->getPrivateMethodInvoker(
new ConfigCheck(service('logger'), service('commands')),
'getKintD'
);
$output = $getKintD(new App());
command('config:check App');
$output = preg_replace(
$this->assertSame(
$command(config('App')) . "\n",
preg_replace('/\s+Config Caching: \S+/', '', $this->getStreamFilterBuffer())
);
}
public function testConfigCheckWithKintDisabledUsesVarDump(): void
{
/** @var Closure(object): string $command */
$command = $this->getPrivateMethodInvoker(
new ConfigCheck(service('logger'), service('commands')),
'getVarDump'
);
$clean = static fn (string $input): string => trim(preg_replace(
'/(\033\[[0-9;]+m)|(\035\[[0-9;]+m)/u',
'',
$output
);
$input
));
$this->assertStringContainsString(
'Config\App#',
$output
);
$this->assertStringContainsString(
<<<'EOL'
(
public 'baseURL' -> string (19) "http://example.com/"
public 'allowedHostnames' -> array (0) []
public 'indexPage' -> string (9) "index.php"
public 'uriProtocol' -> string (11) "REQUEST_URI"
public 'permittedURIChars' -> string (14) "a-z 0-9~%.:_\-"
public 'defaultLocale' -> string (2) "en"
public 'negotiateLocale' -> boolean false
public 'supportedLocales' -> array (1) [
0 => string (2) "en"
]
public 'appTimezone' -> string (3) "UTC"
public 'charset' -> string (5) "UTF-8"
public 'forceGlobalSecureRequests' -> boolean false
public 'proxyIPs' -> array (0) []
public 'CSPEnabled' -> boolean false
EOL,
$output
);
}
try {
Kint::$enabled_mode = false;
command('config:check App');
public function testGetVarDump(): void
{
$command = new ConfigCheck(service('logger'), service('commands'));
$getVarDump = $this->getPrivateMethodInvoker($command, 'getVarDump');
$output = $getVarDump(new App());
if (
ini_get('xdebug.mode')
&& in_array(
'develop',
explode(',', ini_get('xdebug.mode')),
true
)
) {
// Xdebug force adds colors on xdebug.cli_color=2
$output = preg_replace(
'/(\033\[[0-9;]+m)|(\035\[[0-9;]+m)/u',
'',
$output
);
// Xdebug overloads var_dump().
$this->assertStringContainsString(
'class Config\App#',
$output
);
$this->assertStringContainsString(
<<<'EOL'
{
public string $baseURL =>
string(19) "http://example.com/"
public array $allowedHostnames =>
array(0) {
}
public string $indexPage =>
string(9) "index.php"
public string $uriProtocol =>
string(11) "REQUEST_URI"
public string $permittedURIChars =>
string(14) "a-z 0-9~%.:_\-"
public string $defaultLocale =>
string(2) "en"
public bool $negotiateLocale =>
bool(false)
public array $supportedLocales =>
array(1) {
[0] =>
string(2) "en"
}
public string $appTimezone =>
string(3) "UTC"
public string $charset =>
string(5) "UTF-8"
public bool $forceGlobalSecureRequests =>
bool(false)
public array $proxyIPs =>
array(0) {
}
public bool $CSPEnabled =>
bool(false)
}
EOL,
$output
);
} else {
// PHP's var_dump().
$this->assertStringContainsString(
'object(Config\App)#',
$output
);
$this->assertStringContainsString(
<<<'EOL'
{
["baseURL"]=>
string(19) "http://example.com/"
["allowedHostnames"]=>
array(0) {
}
["indexPage"]=>
string(9) "index.php"
["uriProtocol"]=>
string(11) "REQUEST_URI"
["permittedURIChars"]=>
string(14) "a-z 0-9~%.:_\-"
["defaultLocale"]=>
string(2) "en"
["negotiateLocale"]=>
bool(false)
["supportedLocales"]=>
array(1) {
[0]=>
string(2) "en"
}
["appTimezone"]=>
string(3) "UTC"
["charset"]=>
string(5) "UTF-8"
["forceGlobalSecureRequests"]=>
bool(false)
["proxyIPs"]=>
array(0) {
}
["CSPEnabled"]=>
bool(false)
}
EOL,
$output
$this->assertSame(
$clean($command(config('App'))),
$clean(preg_replace('/\s+Config Caching: \S+/', '', $this->getStreamFilterBuffer()))
);
} finally {
Kint::$enabled_mode = true;
}
}
}

View File

@ -30,7 +30,7 @@ final class CURLRequestShareOptionsTest extends CURLRequestTest
{
protected function getRequest(array $options = []): MockCURLRequest
{
$uri = isset($options['base_uri']) ? new URI($options['base_uri']) : new URI();
$uri = isset($options['baseURI']) ? new URI($options['baseURI']) : new URI();
$app = new App();
$config = new ConfigCURLRequest();
@ -43,7 +43,7 @@ final class CURLRequestShareOptionsTest extends CURLRequestTest
public function testHeaderContentLengthNotSharedBetweenRequests(): void
{
$options = [
'base_uri' => 'http://www.foo.com/api/v1/',
'baseURI' => 'http://www.foo.com/api/v1/',
];
$request = $this->getRequest($options);
@ -61,8 +61,8 @@ final class CURLRequestShareOptionsTest extends CURLRequestTest
public function testBodyIsResetOnSecondRequest(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'delay' => 100,
'baseURI' => 'http://www.foo.com/api/v1/',
'delay' => 100,
]);
$request->setBody('name=George');
$request->setOutput('Hi there');

View File

@ -47,7 +47,7 @@ class CURLRequestTest extends CIUnitTestCase
*/
protected function getRequest(array $options = []): MockCURLRequest
{
$uri = isset($options['base_uri']) ? new URI($options['base_uri']) : new URI();
$uri = isset($options['baseURI']) ? new URI($options['baseURI']) : new URI();
$app = new App();
$config = new ConfigCURLRequest();
@ -64,7 +64,7 @@ class CURLRequestTest extends CIUnitTestCase
{
config('App')->baseURL = 'http://example.com/fruit/';
$request = $this->getRequest(['base_uri' => 'http://example.com/v1/']);
$request = $this->getRequest(['baseURI' => 'http://example.com/v1/']);
$method = $this->getPrivateMethodInvoker($request, 'prepareURL');
@ -76,7 +76,7 @@ class CURLRequestTest extends CIUnitTestCase
*/
public function testGetRemembersBaseURI(): void
{
$request = $this->getRequest(['base_uri' => 'http://www.foo.com/api/v1/']);
$request = $this->getRequest(['baseURI' => 'http://www.foo.com/api/v1/']);
$request->get('products');
@ -90,7 +90,7 @@ class CURLRequestTest extends CIUnitTestCase
*/
public function testGetRemembersBaseURIWithHelperMethod(): void
{
$request = Services::curlrequest(['base_uri' => 'http://www.foo.com/api/v1/']);
$request = Services::curlrequest(['baseURI' => 'http://www.foo.com/api/v1/']);
$uri = $this->getPrivateProperty($request, 'baseURI');
$this->assertSame('www.foo.com', $uri->getHost());
@ -157,28 +157,17 @@ class CURLRequestTest extends CIUnitTestCase
public function testOptionsBaseURIOption(): void
{
$options = ['base_uri' => 'http://www.foo.com/api/v1/'];
$options = ['baseURI' => 'http://www.foo.com/api/v1/'];
$request = $this->getRequest($options);
$this->assertSame('http://www.foo.com/api/v1/', $request->getBaseURI()->__toString());
}
public function testOptionsBaseURIOverride(): void
{
$options = [
'base_uri' => 'http://www.foo.com/api/v1/',
'baseURI' => 'http://bogus/com',
];
$request = $this->getRequest($options);
$this->assertSame('http://bogus/com', $request->getBaseURI()->__toString());
}
public function testOptionsHeaders(): void
{
$options = [
'base_uri' => 'http://www.foo.com/api/v1/',
'headers' => ['fruit' => 'apple'],
'baseURI' => 'http://www.foo.com/api/v1/',
'headers' => ['fruit' => 'apple'],
];
$request = $this->getRequest();
$this->assertNull($request->header('fruit'));
@ -195,8 +184,8 @@ class CURLRequestTest extends CIUnitTestCase
$_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip, deflate, br';
$options = [
'base_uri' => 'http://www.foo.com/api/v1/',
'headers' => [
'baseURI' => 'http://www.foo.com/api/v1/',
'headers' => [
'Host' => 'www.foo.com',
'Accept-Encoding' => '',
],
@ -233,7 +222,7 @@ class CURLRequestTest extends CIUnitTestCase
public function testHeaderContentLengthNotSharedBetweenRequests(): void
{
$options = [
'base_uri' => 'http://www.foo.com/api/v1/',
'baseURI' => 'http://www.foo.com/api/v1/',
];
$request = $this->getRequest($options);
@ -253,7 +242,7 @@ class CURLRequestTest extends CIUnitTestCase
$_SERVER['HTTP_CONTENT_LENGTH'] = '10';
$options = [
'base_uri' => 'http://www.foo.com/api/v1/',
'baseURI' => 'http://www.foo.com/api/v1/',
];
$request = $this->getRequest($options);
$request->post('example', [
@ -730,8 +719,8 @@ Transfer-Encoding: chunked\x0d\x0a\x0d\x0a<title>Update success! config</title>"
public function testSendWithQuery(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'query' => [
'baseURI' => 'http://www.foo.com/api/v1/',
'query' => [
'name' => 'Henry',
'd.t' => 'value',
],
@ -747,8 +736,8 @@ Transfer-Encoding: chunked\x0d\x0a\x0d\x0a<title>Update success! config</title>"
public function testSendWithDelay(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'delay' => 100,
'baseURI' => 'http://www.foo.com/api/v1/',
'delay' => 100,
]);
$request->get('products');
@ -760,8 +749,8 @@ Transfer-Encoding: chunked\x0d\x0a\x0d\x0a<title>Update success! config</title>"
public function testSendContinued(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'delay' => 100,
'baseURI' => 'http://www.foo.com/api/v1/',
'delay' => 100,
]);
$request->setOutput("HTTP/1.1 100 Continue\x0d\x0a\x0d\x0aHi there");
@ -775,8 +764,8 @@ Transfer-Encoding: chunked\x0d\x0a\x0d\x0a<title>Update success! config</title>"
public function testSendContinuedWithManyHeaders(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'delay' => 100,
'baseURI' => 'http://www.foo.com/api/v1/',
'delay' => 100,
]);
$output = "HTTP/1.1 100 Continue
@ -819,8 +808,8 @@ Transfer-Encoding: chunked\x0d\x0a\x0d\x0a<title>Update success! config</title>"
public function testSendProxied(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'delay' => 100,
'baseURI' => 'http://www.foo.com/api/v1/',
'delay' => 100,
]);
$output = "HTTP/1.1 200 Connection established
@ -834,8 +823,8 @@ Proxy-Agent: Fortinet-Proxy/1.0\x0d\x0a\x0d\x0aHTTP/1.1 200 OK\x0d\x0a\x0d\x0aHi
public function testSendProxiedWithHTTP10(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'delay' => 100,
'baseURI' => 'http://www.foo.com/api/v1/',
'delay' => 100,
]);
$output = "HTTP/1.0 200 Connection established
@ -852,7 +841,7 @@ Proxy-Agent: Fortinet-Proxy/1.0\x0d\x0a\x0d\x0aHTTP/1.1 200 OK\x0d\x0a\x0d\x0aHi
public function testResponseHeadersWithMultipleRequests(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'baseURI' => 'http://www.foo.com/api/v1/',
]);
$output = "HTTP/2.0 200 OK
@ -905,7 +894,7 @@ Transfer-Encoding: chunked\x0d\x0a\x0d\x0a<title>Hello2</title>";
public function testResponseHeadersWithMultipleSetCookies(): void
{
$request = $this->getRequest([
'base_uri' => 'https://github.com/',
'baseURI' => 'https://github.com/',
]);
$output = "HTTP/2 200
@ -937,8 +926,8 @@ accept-ranges: bytes\x0d\x0a\x0d\x0a";
public function testSplitResponse(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'delay' => 100,
'baseURI' => 'http://www.foo.com/api/v1/',
'delay' => 100,
]);
$request->setOutput("Accept: text/html\x0d\x0a\x0d\x0aHi there");
@ -949,8 +938,8 @@ accept-ranges: bytes\x0d\x0a\x0d\x0a";
public function testApplyBody(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'delay' => 100,
'baseURI' => 'http://www.foo.com/api/v1/',
'delay' => 100,
]);
$request->setBody('name=George');
@ -964,8 +953,8 @@ accept-ranges: bytes\x0d\x0a\x0d\x0a";
public function testApplyBodyByOptions(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'delay' => 100,
'baseURI' => 'http://www.foo.com/api/v1/',
'delay' => 100,
]);
$request->setOutput('Hi there');
@ -980,8 +969,8 @@ accept-ranges: bytes\x0d\x0a\x0d\x0a";
public function testBodyIsResetOnSecondRequest(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'delay' => 100,
'baseURI' => 'http://www.foo.com/api/v1/',
'delay' => 100,
]);
$request->setBody('name=George');
$request->setOutput('Hi there');
@ -995,8 +984,8 @@ accept-ranges: bytes\x0d\x0a\x0d\x0a";
public function testResponseHeaders(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'delay' => 100,
'baseURI' => 'http://www.foo.com/api/v1/',
'delay' => 100,
]);
$request->setOutput("HTTP/2.0 234 Ohoh\x0d\x0aAccept: text/html\x0d\x0a\x0d\x0aHi there");
@ -1009,8 +998,8 @@ accept-ranges: bytes\x0d\x0a\x0d\x0a";
public function testResponseHeadersShortProtocol(): void
{
$request = $this->getRequest([
'base_uri' => 'http://www.foo.com/api/v1/',
'delay' => 100,
'baseURI' => 'http://www.foo.com/api/v1/',
'delay' => 100,
]);
$request->setOutput("HTTP/2 235 Ohoh\x0d\x0aAccept: text/html\x0d\x0a\x0d\x0aHi there shortie");

View File

@ -41,6 +41,7 @@ Bugs Fixed
- **Validation:** Fixed a bug where complex language strings were not properly handled.
- **CURLRequest:** Added support for handling proxy responses using HTTP versions other than 1.1.
- **Database:** Fixed a bug that caused ``Postgre\Connection::reconnect()`` method to throw an error when the connection had not yet been established.
See the repo's
`CHANGELOG.md <https://github.com/codeigniter4/CodeIgniter4/blob/develop/CHANGELOG.md>`_

View File

@ -149,7 +149,7 @@ the previous section. Specify the segment number to use as the fifth parameter t
Please note: ``$segment`` value cannot be greater than the number of URI segments plus 1.
If you in need to show many pagers on one page then additional parameter which will define a group could be helpful:
If you need to show many pagers on one page then the additional parameter which will define a group could be helpful:
.. literalinclude:: pagination/007.php
@ -224,7 +224,7 @@ usefulness. It is easiest to demonstrate creating a new view by showing you the
setSurroundCount()
------------------
In the first line, the ``setSurroundCount()`` method specifies than we want to show two links to either side of
In the first line, the ``setSurroundCount()`` method specifies that we want to show two links to either side of
the current page link. The only parameter that it accepts is the number of links to show.
.. note:: You must call this method first to generate correct pagination links.
@ -274,7 +274,7 @@ In the code presented for the standard pagination structure, the methods `getPre
If you want to use the pagination structure where prev and next will be links to the previous and next pages based on the current page, just replace the `getPrevious() & getNext()`_ methods with `getPreviousPage() & getNextPage()`_, and the methods `hasPrevious() & hasNext()`_ by `hasPreviousPage() & hasNextPage()`_ respectively.
See following an example with these changes:
See the following example with these changes:
.. literalinclude:: pagination/014.php
@ -325,7 +325,7 @@ links to be displayed. For example, if the set of links to be displayed is somet
3 | 4 | 5 | 6 | 7
``getFirstPageNumber()`` will return 3 while ``getLastPageNumber()`` will return 7.
``getFirstPageNumber()`` will return 3 while ``getLastPageNumber()`` will return 7.
.. note:: To obtain the page numbers of the first and last pages in the entire
result set, you can use the following approach: The first page number is always 1, and `getPageCount()`_ can be used to