diff --git a/system/Helpers/number_helper.php b/system/Helpers/number_helper.php index a0d0496452c3..bf577ed293f6 100644 --- a/system/Helpers/number_helper.php +++ b/system/Helpers/number_helper.php @@ -84,8 +84,9 @@ function number_to_amount($num, int $precision = 0, ?string $locale = null) // Strip any formatting & ensure numeric input try { // @phpstan-ignore-next-line - $num = 0 + str_replace(',', '', $num); + $num = 0 + str_replace(',', '', (string) $num); } catch (ErrorException) { + // Catch "Warning: A non-numeric value encountered" return false; } diff --git a/tests/system/Helpers/NumberHelperTest.php b/tests/system/Helpers/NumberHelperTest.php index 9b3afa61992f..7e5fe2a358c4 100644 --- a/tests/system/Helpers/NumberHelperTest.php +++ b/tests/system/Helpers/NumberHelperTest.php @@ -38,6 +38,11 @@ public function testRomanNumber(): void $this->assertSame('X', number_to_roman(10)); } + public function testRomanNumberString(): void + { + $this->assertSame('XCVI', number_to_roman('96')); + } + public function testRomanNumberRange(): void { $this->assertNull(number_to_roman(-1)); @@ -70,6 +75,11 @@ public function testNumberToSize(): void $this->assertSame('456 Bytes', number_to_size(456, 1, 'en_US')); } + public function testNumberToSizeString(): void + { + $this->assertSame('456 Bytes', number_to_size('456', 1, 'en_US')); + } + public function testKbFormat(): void { $this->assertSame('4.5 KB', number_to_size(4567, 1, 'en_US')); @@ -109,6 +119,11 @@ public function testThousands(): void $this->assertSame('1,000 thousand', number_to_amount('999999', 0, 'en_US')); } + public function testThousandsInt(): void + { + $this->assertSame('123 thousand', number_to_amount(123000, 0, 'en_US')); + } + public function testMillions(): void { $this->assertSame('123.4 million', number_to_amount('123,400,000', 1, 'en_US')); diff --git a/user_guide_src/source/concepts/services.rst b/user_guide_src/source/concepts/services.rst index a3dc9fabb74d..92eec136e1c8 100644 --- a/user_guide_src/source/concepts/services.rst +++ b/user_guide_src/source/concepts/services.rst @@ -37,7 +37,7 @@ come in handy. Instead of creating the instance ourself, we let a central class create an instance of the class for us. This class is kept very simple. It only contains a method for each class that we want to use as a service. The method typically returns a **shared instance** of that class, passing any dependencies -it might have into it. Then, we would replace our timer creation code with code that calls this new class: +it might have into it. Then, we would replace our timer creation code with code that calls this global function or Services class: .. literalinclude:: services/002.php @@ -55,7 +55,7 @@ As many CodeIgniter classes are provided as services, you can get them like the .. literalinclude:: services/013.php -The ``$typography`` is an instance of the Typography class, and if you call ``\Config\Services::typography()`` again, you will get the exactly same instance. +The ``$timer`` is an instance of the Timer class, and if you call ``service('timer')`` again, you will get the exactly same instance. The Services typically return a **shared instance** of the class. The following code creates a ``CURLRequest`` instance at the first call. And the second call returns the exactly same instance. @@ -66,7 +66,7 @@ Therefore, the parameter ``$options2`` for the ``$client2`` does not work. It is Getting a New Instance ====================== -If you want to get a new instance of the Typography class, you need to pass ``false`` to the argument ``$getShared``: +If you want to get a new instance of the Timer class, you need to pass ``false`` to the argument ``$getShared``: .. literalinclude:: services/014.php @@ -85,6 +85,8 @@ always return the same instance: .. literalinclude:: services/003.php +.. note:: Since v4.5.0, when you don't pass parameters to the service, the global function ``service()`` is recommended due to performance improvements. + If the creation method requires additional parameters, they can be passed after the service name: .. literalinclude:: services/004.php diff --git a/user_guide_src/source/concepts/services/002.php b/user_guide_src/source/concepts/services/002.php index cb292ecaeb42..cedf5d19ed65 100644 --- a/user_guide_src/source/concepts/services/002.php +++ b/user_guide_src/source/concepts/services/002.php @@ -1,3 +1,6 @@ 'http://example.com/api/v1/', 'timeout' => 3, ]; -$client1 = \Config\Services::curlrequest($options1); +$client1 = service('curlrequest', $options1); $options2 = [ 'baseURI' => 'http://another.example.com/api/v2/', 'timeout' => 10, ]; -$client2 = \Config\Services::curlrequest($options2); +$client2 = service('curlrequest', $options2); // $options2 does not work. // $client2 is the exactly same instance as $client1. diff --git a/user_guide_src/source/extending/basecontroller/003.php b/user_guide_src/source/extending/basecontroller/003.php index 2f6fcb9d08cb..b7bcab22545d 100644 --- a/user_guide_src/source/extending/basecontroller/003.php +++ b/user_guide_src/source/extending/basecontroller/003.php @@ -18,6 +18,6 @@ public function initController(/* ... */) // Do Not Edit This Line parent::initController($request, $response, $logger); - $this->session = \Config\Services::session(); + $this->session = service('session'); } } diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst index 61b92a99df92..d0a23758e348 100644 --- a/user_guide_src/source/general/common_functions.rst +++ b/user_guide_src/source/general/common_functions.rst @@ -372,7 +372,7 @@ Miscellaneous Functions :returns: The shared Request object. :rtype: IncomingRequest|CLIRequest - This function is a wrapper for ``Services::request()``. + This function is a wrapper for ``Services::request()`` and ``service('request')``. .. php:function:: response() @@ -381,7 +381,7 @@ Miscellaneous Functions :returns: The shared Response object. :rtype: Response - This function is a wrapper for ``Services::response()``. + This function is a wrapper for ``Services::response()`` and ``service('response')``. .. php:function:: route_to($method[, ...$params]) diff --git a/user_guide_src/source/general/errors/018.php b/user_guide_src/source/general/errors/018.php index 3cba09951d8b..9546e4a606ae 100644 --- a/user_guide_src/source/general/errors/018.php +++ b/user_guide_src/source/general/errors/018.php @@ -1,6 +1,6 @@ redirect('https://example.com/path') ->setHeader('Some', 'header') ->setCookie('and', 'cookie'); diff --git a/user_guide_src/source/helpers/form_helper.rst b/user_guide_src/source/helpers/form_helper.rst index 68c7090408df..9a2d9f026abb 100644 --- a/user_guide_src/source/helpers/form_helper.rst +++ b/user_guide_src/source/helpers/form_helper.rst @@ -28,7 +28,7 @@ Escaping Field Values ********************* You may need to use HTML and characters such as quotes within your form -elements. In order to do that safely, you'll need to use +elements. In order to do that safely, you'll need to use the :doc:`common function <../general/common_functions>` :php:func:`esc()`. @@ -64,8 +64,8 @@ The following functions are available: Creates an opening form tag with a site URL **built from your** ``Config\App::$baseURL``. It will optionally let you add form attributes and hidden input fields, and - will always add the `accept-charset` attribute based on the charset value in your - config file. + will always add the `accept-charset` attribute based on the ``$charset`` property in your + **app/Config/App.php** config file. The main benefit of using this tag rather than hard coding your own HTML is that it permits your site to be more portable in the event your URLs ever change. @@ -103,16 +103,21 @@ The following functions are available: