From 937642b1e82d414376f5fbcec37c6291d121cd05 Mon Sep 17 00:00:00 2001 From: michalsn Date: Fri, 8 May 2020 12:19:49 +0200 Subject: [PATCH 1/2] Improved getSegment() method --- system/HTTP/URI.php | 19 ++++++++---- tests/system/HTTP/URITest.php | 39 +++++++++++++++++++++++++ user_guide_src/source/libraries/uri.rst | 12 ++++++++ 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/system/HTTP/URI.php b/system/HTTP/URI.php index 09aa3cdc2eeb..5903ddf2791f 100644 --- a/system/HTTP/URI.php +++ b/system/HTTP/URI.php @@ -469,12 +469,14 @@ public function getSegments(): array /** * Returns the value of a specific segment of the URI path. * - * @param integer $number + * @param integer $number Segment number + * @param string|null $default Default value when segment is empty (equal to '') + * @param boolean $silent Throw an exception or not * - * @return string The value of the segment. If no segment is found, - * throws InvalidArgumentError + * @return string|null The value of the segment. If no segment is found, + * throws InvalidArgumentError */ - public function getSegment(int $number): string + public function getSegment(int $number, ?string $default = '', bool $silent = false): ?string { // The segment should treat the array as 1-based for the user // but we still have to deal with a zero-based array. @@ -482,10 +484,17 @@ public function getSegment(int $number): string if ($number > count($this->segments)) { + if ($silent) + { + return $default; + } + throw HTTPException::forURISegmentOutOfRange($number); } - return $this->segments[$number] ?? ''; + return (isset($this->segments[$number]) && $this->segments[$number] !== '') + ? $this->segments[$number] + : $default; } /** diff --git a/tests/system/HTTP/URITest.php b/tests/system/HTTP/URITest.php index 54b58a911f63..273ff7ca0e20 100644 --- a/tests/system/HTTP/URITest.php +++ b/tests/system/HTTP/URITest.php @@ -65,6 +65,45 @@ public function testSegmentOutOfRange() //-------------------------------------------------------------------- + public function testSegmentOutOfRangeWithDefaultValue() + { + $this->expectException(HTTPException::class); + $url = 'http://abc.com/a123/b/c'; + $uri = new URI($url); + $uri->getSegment(22, 'something'); + } + + //-------------------------------------------------------------------- + + public function testSegmentsWithDefaultValue() + { + $uri = new URI('http://hostname/path/to'); + + $this->assertEquals(['path', 'to'], $uri->getSegments()); + $this->assertEquals('path', $uri->getSegment(1)); + $this->assertEquals('to', $uri->getSegment(2, 'different')); + $this->assertEquals('script', $uri->getSegment(3, 'script')); + $this->assertEquals('', $uri->getSegment(3)); + + $this->assertEquals(2, $uri->getTotalSegments()); + $this->assertEquals(['path', 'to'], $uri->getSegments()); + } + + //-------------------------------------------------------------------- + + public function testSegmentOutOfRangeSilent() + { + $uri = new URI('http://hostname/path/to/script'); + + $this->assertEquals('', $uri->getSegment(22, '', true)); + $this->assertEquals('something', $uri->getSegment(33, 'something', true)); + + $this->assertEquals(3, $uri->getTotalSegments()); + $this->assertEquals(['path', 'to', 'script'], $uri->getSegments()); + } + + //-------------------------------------------------------------------- + public function testCanCastAsString() { $url = 'http://username:password@hostname:9090/path?arg=value#anchor'; diff --git a/user_guide_src/source/libraries/uri.rst b/user_guide_src/source/libraries/uri.rst index 47ddd98201bb..a69054ed7166 100644 --- a/user_guide_src/source/libraries/uri.rst +++ b/user_guide_src/source/libraries/uri.rst @@ -234,6 +234,18 @@ what the values of the segments are. The segments start at 1 being the furthest echo $request->uri->getSegment(2); } +By default, if we want to get a segment number that is not available, the exception ``HTTPException::forURISegmentOutOfRange`` +will be thrown. Therefore, additional parameters for the ``getSegment()`` method are available to allow more convenient work. +These parameters allow you to return the default value for a segment, even if it's not defined. In a code example below 'foo' +is now default value if a given segment is not available and the last parameter ``true`` prevents the exception to be thrown. +In some situations, you may find it very handy. +:: + + // URI = http://example.com/users/15/profile + + // Prints 'foo' + echo $request->uri->getSegment(5, 'foo', true); + You can get a count of the total segments:: $total = $request->uri->getTotalSegments(); // 3 From 1c3a9d6b23ee5ff3980e03f0f779f1a64ac74859 Mon Sep 17 00:00:00 2001 From: michalsn Date: Fri, 8 May 2020 22:50:46 +0200 Subject: [PATCH 2/2] Code cleanup --- system/HTTP/URI.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/system/HTTP/URI.php b/system/HTTP/URI.php index 5903ddf2791f..42b36eca088b 100644 --- a/system/HTTP/URI.php +++ b/system/HTTP/URI.php @@ -482,19 +482,12 @@ public function getSegment(int $number, ?string $default = '', bool $silent = fa // but we still have to deal with a zero-based array. $number -= 1; - if ($number > count($this->segments)) + if (! $silent && $number > count($this->segments)) { - if ($silent) - { - return $default; - } - throw HTTPException::forURISegmentOutOfRange($number); } - return (isset($this->segments[$number]) && $this->segments[$number] !== '') - ? $this->segments[$number] - : $default; + return $this->segments[$number] ?? $default; } /**