diff --git a/.upgradenotes/MDL-87671-2026020509381268.yml b/.upgradenotes/MDL-87671-2026020509381268.yml new file mode 100644 index 00000000000..efbaf8b18ae --- /dev/null +++ b/.upgradenotes/MDL-87671-2026020509381268.yml @@ -0,0 +1,5 @@ +issueNumber: MDL-87671 +notes: + core: + - message: A new path_section parameter type for routing has been created + type: improved diff --git a/public/lib/classes/router/parameters/path_section.php b/public/lib/classes/router/parameters/path_section.php new file mode 100644 index 00000000000..30d6e2bcc84 --- /dev/null +++ b/public/lib/classes/router/parameters/path_section.php @@ -0,0 +1,98 @@ +. + +namespace core\router\parameters; + +use core\exception\not_found_exception; +use core\param; +use core\router\schema\example; +use core\router\schema\parameters\mapped_property_parameter; +use core\router\schema\referenced_object; +use Psr\Http\Message\ServerRequestInterface; + +/** + * A parameter representing a section in the path. + * + * @package core + * @copyright 2026 Amaia Anabitarte + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class path_section extends \core\router\schema\parameters\path_parameter implements + mapped_property_parameter, + referenced_object +{ + /** + * Create a new path_section parameter. + * + * @param string $name The name of the parameter to use for the section identifier + * @param mixed ...$extra Additional arguments + */ + public function __construct( + string $name = 'section', + ...$extra, + ) { + $extra['name'] = $name; + $extra['type'] = param::RAW; + $extra['description'] = <<get_section_for_value($value); + return $request + ->withAttribute($this->name, $section) + ->withAttribute("coursecontext", \context_course::instance($section->course)); + } + + /** + * Get the section object for the given identifier. + * + * @param string $value A section id + * @return object + * @throws not_found_exception If the section cannot be found + */ + protected function get_section_for_value(string $value): mixed { + global $DB; + + $data = false; + + if (is_numeric($value)) { + $data = $DB->get_record('course_sections', [ + 'id' => $value, + ]); + } + if ($data) { + return $data; + } + + throw new not_found_exception('course_sections', $value); + } +} diff --git a/public/lib/tests/router/parameters/path_section_test.php b/public/lib/tests/router/parameters/path_section_test.php new file mode 100644 index 00000000000..eb989a839a8 --- /dev/null +++ b/public/lib/tests/router/parameters/path_section_test.php @@ -0,0 +1,68 @@ +. + +namespace core\router\parameters; + +use core\exception\not_found_exception; +use core\tests\router\route_testcase; +use GuzzleHttp\Psr7\ServerRequest; +use stdClass; + +/** + * Tests for the Section Path parameter. + * + * @package core + * @copyright Amaia Anabitarte + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @covers \core\router\parameters\path_section + */ +final class path_section_test extends route_testcase { + public function test_section_id(): void { + $this->resetAfterTest(); + + $course = $this->getDataGenerator()->create_course(); + $modinfo = get_fast_modinfo($course); + $section = $modinfo->get_section_info(1); + $context = \context_course::instance($course->id); + + $param = new path_section(); + $request = new ServerRequest('GET', '/course/sections/' . $section->id . '/restricted'); + $newrequest = $param->add_attributes_for_parameter_value($request, $section->id); + + $this->assertInstanceOf(stdClass::class, $newrequest->getAttribute('section')); + $this->assertInstanceOf(\core\context\course::class, $newrequest->getAttribute('coursecontext')); + + $this->assertEquals($section->id, $newrequest->getAttribute('section')->id); + $this->assertEquals($context->id, $newrequest->getAttribute('coursecontext')->id); + } + + /** + * Tests for when a section was not found. + */ + public function test_section_not_found(): void { + $this->resetAfterTest(); + + $param = new path_section(); + + $course = $this->getDataGenerator()->create_course(); + $sectionid = 9999; + + $request = new ServerRequest('GET', '/course/sections/' . $sectionid . '/restricted'); + + $this->expectException(not_found_exception::class); + $param->add_attributes_for_parameter_value($request, $sectionid); + } +}