diff --git a/system/HTTP/URI.php b/system/HTTP/URI.php index 09aa3cdc2eeb..42b36eca088b 100644 --- a/system/HTTP/URI.php +++ b/system/HTTP/URI.php @@ -469,23 +469,25 @@ 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. $number -= 1; - if ($number > count($this->segments)) + if (! $silent && $number > count($this->segments)) { throw HTTPException::forURISegmentOutOfRange($number); } - return $this->segments[$number] ?? ''; + return $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