Merge branch 'MDL-87625-main' of https://github.com/andrewnicols/moodle
This commit is contained in:
@@ -45,5 +45,26 @@ class hook_callbacks {
|
||||
route_loader_interface::class,
|
||||
\DI\get(route_loader::class),
|
||||
);
|
||||
|
||||
// Until Moodle 6.0 we will allow the router to be unconfigured for backwards compatibility.
|
||||
// To support legacy shims like /course/tags.php we need a custom route resolver which tries both.
|
||||
// The following definition can be removed in Moodle 6.0.
|
||||
// - \Slim\Interfaces\RouteResolverInterface
|
||||
// - \Slim\Interfaces\RouteCollectorInterface
|
||||
// - \Psr\Http\Message\ResponseFactoryInterface
|
||||
// Along with the route_resolver class itself.
|
||||
// TODO MDL-87637 Remove in Moodle 6.0.
|
||||
$hook->add_definition(
|
||||
\Slim\Interfaces\RouteResolverInterface::class,
|
||||
\DI\get(route_resolver::class),
|
||||
);
|
||||
$hook->add_definition(
|
||||
\Slim\Interfaces\RouteCollectorInterface::class,
|
||||
\DI\get(\Slim\Routing\RouteCollector::class),
|
||||
);
|
||||
$hook->add_definition(
|
||||
\Psr\Http\Message\ResponseFactoryInterface::class,
|
||||
\DI\factory([\Slim\Factory\AppFactory::class, 'determineResponseFactory']),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core\router;
|
||||
|
||||
use Slim\Routing\RouteResolver;
|
||||
use Slim\Routing\RoutingResults;
|
||||
|
||||
/**
|
||||
* Route Resolver that supports routing via r.php.
|
||||
*
|
||||
* Note: This is a temporary shim to support legacy shims until Moodle 6.0.
|
||||
* After that, this class and its references can be removed.
|
||||
* See MDL-87625 for more details.
|
||||
* This class and it's DI definitions will be removed in Moodle 6.0.
|
||||
*
|
||||
* @package core
|
||||
* @copyright Andrew Lyons <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class route_resolver extends RouteResolver {
|
||||
#[\Override]
|
||||
public function computeRoutingResults(string $uri, string $method): RoutingResults {
|
||||
$originalresult = parent::computeRoutingResults($uri, $method);
|
||||
if ($originalresult->getRouteStatus() === RoutingResults::FOUND) {
|
||||
return $originalresult;
|
||||
}
|
||||
|
||||
// In some situations, like hardcoded shims, the request will look like /course/tags.php.
|
||||
// When the router is not correctly configured (that ism it still has /r.php in the basepath),
|
||||
// we need to adjust the URI to include /r.php so that the routing can work.
|
||||
// The basepath includes the wwwroot and /r.php. We need to remove the /r.php from that to leave just the wwwroot.
|
||||
// Then we can replae that with the basepath including /r.php.
|
||||
$basepath = \core\di::get(\core\router::class)->basepath;
|
||||
|
||||
if (str_ends_with($basepath, '/r.php')) {
|
||||
if (str_starts_with($uri, $basepath)) {
|
||||
// The router is in legacy mode and the requested URI already includes /r.php.
|
||||
return $originalresult;
|
||||
} else {
|
||||
// The router is in legacy mode but the requested URI does not include /r.php, so add it.
|
||||
$updateduri = $basepath . substr($uri, strlen($basepath) - strlen('/r.php'));
|
||||
}
|
||||
} else {
|
||||
$suffixedbasepath = $basepath . '/r.php';
|
||||
if (str_starts_with($uri, $suffixedbasepath)) {
|
||||
// The router is correctly configured but the requested URI includes /r.php, so remove it.
|
||||
$updateduri = $basepath . substr($uri, strlen($suffixedbasepath));
|
||||
} else {
|
||||
// The router is correctly configured and the requested URI does not include /r.php.
|
||||
return $originalresult;
|
||||
}
|
||||
}
|
||||
|
||||
// Try again with the updated URI.
|
||||
$result = parent::computeRoutingResults($updateduri, $method);
|
||||
|
||||
if ($result->getRouteStatus() === RoutingResults::FOUND) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Still not found, return the original result.
|
||||
return $originalresult;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core\router;
|
||||
|
||||
/**
|
||||
* Tests for the route resolver that supports routing with and without the r.php prefix.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @copyright Andrew Lyons <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
#[\PHPUnit\Framework\Attributes\CoversClass(route_resolver::class)]
|
||||
final class route_resolver_test extends \core\tests\router\route_testcase {
|
||||
/**
|
||||
* Ensure that the computation of routing results can add or remove /r.php as needed.
|
||||
*/
|
||||
#[\PHPUnit\Framework\Attributes\DataProvider('compute_routing_results_provider')]
|
||||
public function test_compute_routing_results(
|
||||
string $basepath,
|
||||
string $path,
|
||||
string $requestedpath,
|
||||
int $expectedresult,
|
||||
): void {
|
||||
$this->add_route_to_route_loader(
|
||||
self::class,
|
||||
'method_under_test',
|
||||
'',
|
||||
);
|
||||
|
||||
$router = $this->get_router($basepath);
|
||||
$result = $router->get_app()->getRouteResolver()->computeRoutingResults(
|
||||
$requestedpath,
|
||||
'GET',
|
||||
);
|
||||
|
||||
$this->assertEquals($expectedresult, $result->getRouteStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* A test route handler.
|
||||
*/
|
||||
#[\core\router\route(path: '/method_under_test')]
|
||||
public function method_under_test(): void {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for the routing provider.
|
||||
*
|
||||
* @return \Generator<string, array<int|string>, mixed, void>
|
||||
*/
|
||||
public static function compute_routing_results_provider(): \Generator {
|
||||
$prefixes = ['/moodle', ''];
|
||||
|
||||
foreach ($prefixes as $prefix) {
|
||||
yield "Router in legacy mode, request without r.php, wwwroot is '{$prefix}'" => [
|
||||
"{$prefix}/r.php",
|
||||
'/method_under_test',
|
||||
"{$prefix}/method_under_test",
|
||||
\Slim\Routing\RoutingResults::FOUND,
|
||||
];
|
||||
|
||||
yield "Router in legacy mode, request with r.php, wwwroot is '{$prefix}'" => [
|
||||
"{$prefix}/r.php",
|
||||
'/method_under_test',
|
||||
"{$prefix}/r.php/method_under_test",
|
||||
\Slim\Routing\RoutingResults::FOUND,
|
||||
];
|
||||
|
||||
yield "Router in normal mode, request without r.php, wwwroot is '{$prefix}'" => [
|
||||
"{$prefix}",
|
||||
'/method_under_test',
|
||||
"{$prefix}/method_under_test",
|
||||
\Slim\Routing\RoutingResults::FOUND,
|
||||
];
|
||||
|
||||
yield "Router in normal mode, request with r.php, wwwroot is '{$prefix}'" => [
|
||||
"{$prefix}",
|
||||
'/method_under_test',
|
||||
"{$prefix}/r.php/method_under_test",
|
||||
\Slim\Routing\RoutingResults::FOUND,
|
||||
];
|
||||
|
||||
yield "Router in legacy mode, request unrelated path, wwwroot is '{$prefix}'" => [
|
||||
"{$prefix}/r.php",
|
||||
'/method_under_test',
|
||||
"{$prefix}/otherpath",
|
||||
\Slim\Routing\RoutingResults::NOT_FOUND,
|
||||
];
|
||||
|
||||
yield "Router in normal mode, request unrelated path, wwwroot is '{$prefix}'" => [
|
||||
"{$prefix}",
|
||||
'/method_under_test',
|
||||
"{$prefix}/otherpath",
|
||||
\Slim\Routing\RoutingResults::NOT_FOUND,
|
||||
];
|
||||
|
||||
yield "Router in legacy mode, request root path, wwwroot is '{$prefix}'" => [
|
||||
"{$prefix}/r.php",
|
||||
'/method_under_test',
|
||||
"{$prefix}/",
|
||||
\Slim\Routing\RoutingResults::NOT_FOUND,
|
||||
];
|
||||
|
||||
yield "Router in normal mode, request root path, wwwroot is '{$prefix}'" => [
|
||||
"{$prefix}",
|
||||
'/method_under_test',
|
||||
"{$prefix}/",
|
||||
\Slim\Routing\RoutingResults::NOT_FOUND,
|
||||
];
|
||||
|
||||
yield "Router in legacy mode, request r.php only, wwwroot is '{$prefix}'" => [
|
||||
"{$prefix}/r.php",
|
||||
'/method_under_test',
|
||||
"{$prefix}/r.php",
|
||||
\Slim\Routing\RoutingResults::NOT_FOUND,
|
||||
];
|
||||
|
||||
yield "Router in normal mode, request r.php only, wwwroot is '{$prefix}'" => [
|
||||
"{$prefix}",
|
||||
'/method_under_test',
|
||||
"{$prefix}/r.php",
|
||||
\Slim\Routing\RoutingResults::NOT_FOUND,
|
||||
];
|
||||
|
||||
yield "Router in legacy mode, request empty path, wwwroot is '{$prefix}'" => [
|
||||
"{$prefix}/r.php",
|
||||
'/method_under_test',
|
||||
"{$prefix}",
|
||||
\Slim\Routing\RoutingResults::NOT_FOUND,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user