blitz-php /
framework
| 1 | <?php |
||||
| 2 | |||||
| 3 | /** |
||||
| 4 | * This file is part of Blitz PHP framework. |
||||
| 5 | * |
||||
| 6 | * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]> |
||||
| 7 | * |
||||
| 8 | * For the full copyright and license information, please view |
||||
| 9 | * the LICENSE file that was distributed with this source code. |
||||
| 10 | */ |
||||
| 11 | |||||
| 12 | namespace BlitzPHP\Router; |
||||
| 13 | |||||
| 14 | use BlitzPHP\Contracts\Router\AutoRouterInterface; |
||||
| 15 | use BlitzPHP\Exceptions\MethodNotFoundException; |
||||
| 16 | use BlitzPHP\Exceptions\PageNotFoundException; |
||||
| 17 | use BlitzPHP\Utilities\Helpers; |
||||
| 18 | use BlitzPHP\Utilities\String\Text; |
||||
| 19 | use ReflectionClass; |
||||
| 20 | use ReflectionException; |
||||
| 21 | |||||
| 22 | /** |
||||
| 23 | * Routeur sécurisé pour le routage automatique |
||||
| 24 | * |
||||
| 25 | * @credit <a href="http://www.codeigniter.com">CodeIgniter 4.4 - CodeIgniter\Router\AutoRouterImproved</a> |
||||
| 26 | */ |
||||
| 27 | final class AutoRouter implements AutoRouterInterface |
||||
| 28 | { |
||||
| 29 | /** |
||||
| 30 | * Sous-répertoire contenant la classe contrôleur demandée. |
||||
| 31 | * Principalement utilisé par 'autoRoute'. |
||||
| 32 | */ |
||||
| 33 | private ?string $directory = null; |
||||
| 34 | |||||
| 35 | /** |
||||
| 36 | * Le nom de la classe du contrôleur. |
||||
| 37 | */ |
||||
| 38 | private string $controller; |
||||
| 39 | |||||
| 40 | /** |
||||
| 41 | * Nom de la méthode à utiliser. |
||||
| 42 | */ |
||||
| 43 | private string $method; |
||||
| 44 | |||||
| 45 | /** |
||||
| 46 | * Tableau de paramètres de la méthode du contrôleur. |
||||
| 47 | * |
||||
| 48 | * @var list<string> |
||||
|
0 ignored issues
–
show
|
|||||
| 49 | */ |
||||
| 50 | private array $params = []; |
||||
| 51 | |||||
| 52 | /** |
||||
| 53 | * Indique si on doit traduire les tirets de l'URL pour les controleurs/methodes en CamelCase. |
||||
| 54 | * E.g., blog-controller -> BlogController |
||||
| 55 | */ |
||||
| 56 | private readonly bool $translateUriToCamelCase; |
||||
| 57 | |||||
| 58 | /** |
||||
| 59 | * Namespace des controleurs |
||||
| 60 | */ |
||||
| 61 | private string $namespace; |
||||
| 62 | |||||
| 63 | /** |
||||
| 64 | * Segments de l'URI |
||||
| 65 | * |
||||
| 66 | * @var list<string> |
||||
| 67 | */ |
||||
| 68 | private array $segments = []; |
||||
| 69 | |||||
| 70 | /** |
||||
| 71 | * Position du contrôleur dans les segments URI. |
||||
| 72 | * Null pour le contrôleur par défaut. |
||||
| 73 | */ |
||||
| 74 | private ?int $controllerPos = null; |
||||
| 75 | |||||
| 76 | /** |
||||
| 77 | * Position de la méthode dans les segments URI. |
||||
| 78 | * Null pour la méthode par défaut. |
||||
| 79 | */ |
||||
| 80 | private ?int $methodPos = null; |
||||
| 81 | |||||
| 82 | /** |
||||
| 83 | * Position du premier Paramètre dans les segments URI. |
||||
| 84 | * Null pour les paramètres non definis. |
||||
| 85 | */ |
||||
| 86 | private ?int $paramPos = null; |
||||
| 87 | |||||
| 88 | /** |
||||
| 89 | * Carte des segments URI et des namespace. |
||||
| 90 | * |
||||
| 91 | * La clé est le premier segment URI. La valeur est le namespace du contrôleur. |
||||
| 92 | * Ex., |
||||
| 93 | * [ |
||||
| 94 | * 'blog' => 'Acme\Blog\Controllers', |
||||
| 95 | * ] |
||||
| 96 | * |
||||
| 97 | * @var array [ uri_segment => namespace ] |
||||
| 98 | */ |
||||
| 99 | private array $moduleRoutes; |
||||
| 100 | |||||
| 101 | /** |
||||
| 102 | * URI courant |
||||
| 103 | */ |
||||
| 104 | private ?string $uri = null; |
||||
| 105 | |||||
| 106 | /** |
||||
| 107 | * Constructeur |
||||
| 108 | * |
||||
| 109 | * @param list<class-string> $protectedControllers Liste des contrôleurs enregistrés pour le verbe CLI qui ne doivent pas être accessibles sur le Web. |
||||
| 110 | * @param string $namespace Espace de noms par défaut pour les contrôleurs. |
||||
| 111 | * @param string $defaultController Nom du controleur par defaut. |
||||
| 112 | * @param string $defaultMethod Nom de la methode par defaut. |
||||
| 113 | * @param bool $translateURIDashes Indique si les tirets dans les URI doivent être convertis en traits de soulignement lors de la détermination des noms de méthode. |
||||
| 114 | */ |
||||
| 115 | public function __construct( |
||||
| 116 | private readonly array $protectedControllers, |
||||
| 117 | string $namespace, |
||||
| 118 | private readonly string $defaultController, |
||||
| 119 | private readonly string $defaultMethod, |
||||
| 120 | private readonly bool $translateURIDashes |
||||
| 121 | ) { |
||||
| 122 | 4 | $this->namespace = rtrim($namespace, '\\'); |
|||
| 123 | |||||
| 124 | 4 | $routingConfig = (object) config('routing'); |
|||
| 125 | 4 | $this->moduleRoutes = $routingConfig->module_routes; |
|||
| 126 | 4 | $this->translateUriToCamelCase = $routingConfig->translate_uri_to_camel_case; |
|||
|
0 ignored issues
–
show
|
|||||
| 127 | |||||
| 128 | // Definir les valeurs par defaut |
||||
| 129 | 4 | $this->controller = $this->defaultController; |
|||
| 130 | } |
||||
| 131 | |||||
| 132 | private function createSegments(string $uri): array |
||||
| 133 | { |
||||
| 134 | 4 | $segments = explode('/', $uri); |
|||
| 135 | 4 | $segments = array_filter($segments, static fn ($segment) => $segment !== ''); |
|||
| 136 | |||||
| 137 | // réindexer numériquement le tableau, en supprimant les lacunes |
||||
| 138 | 4 | return array_values($segments); |
|||
| 139 | } |
||||
| 140 | |||||
| 141 | /** |
||||
| 142 | * Recherchez le premier contrôleur correspondant au segment URI. |
||||
| 143 | * |
||||
| 144 | * S'il y a un contrôleur correspondant au premier segment, la recherche s'arrête là. |
||||
| 145 | * Les segments restants sont des paramètres du contrôleur. |
||||
| 146 | * |
||||
| 147 | * @return bool true si une classe de contrôleur est trouvée. |
||||
| 148 | */ |
||||
| 149 | private function searchFirstController(): bool |
||||
| 150 | { |
||||
| 151 | 4 | $segments = $this->segments; |
|||
|
0 ignored issues
–
show
It seems like
$this->segments of type array is incompatible with the declared type BlitzPHP\Router\list of property $segments.
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. Loading history...
|
|||||
| 152 | |||||
| 153 | 4 | $controller = '\\' . $this->namespace; |
|||
| 154 | |||||
| 155 | 4 | $controllerPos = -1; |
|||
| 156 | |||||
| 157 | while ($segments !== []) { |
||||
| 158 | 4 | $segment = array_shift($segments); |
|||
| 159 | 4 | $controllerPos++; |
|||
| 160 | |||||
| 161 | 4 | $class = $this->translateURI($segment); |
|||
| 162 | |||||
| 163 | // dès que nous rencontrons un segment qui n'est pas compatible PSR-4, arrêter la recherche |
||||
| 164 | if (! $this->isValidSegment($class)) { |
||||
| 165 | return false; |
||||
| 166 | } |
||||
| 167 | |||||
| 168 | 4 | $controller = $this->makeController($controller . '\\' . $class); |
|||
| 169 | |||||
| 170 | if (class_exists($controller)) { |
||||
| 171 | 4 | $this->controller = $controller; |
|||
| 172 | 4 | $this->controllerPos = $controllerPos; |
|||
| 173 | |||||
| 174 | 4 | $this->checkUriForController($controller); |
|||
| 175 | |||||
| 176 | // Le premier élément peut être un nom de méthode. |
||||
| 177 | 4 | $this->params = $segments; |
|||
| 178 | if ($segments !== []) { |
||||
| 179 | 2 | $this->paramPos = $this->controllerPos + 1; |
|||
| 180 | } |
||||
| 181 | |||||
| 182 | 4 | return true; |
|||
| 183 | } |
||||
| 184 | } |
||||
| 185 | |||||
| 186 | 2 | return false; |
|||
| 187 | } |
||||
| 188 | |||||
| 189 | /** |
||||
| 190 | * Recherchez le dernier contrôleur par défaut correspondant aux segments URI. |
||||
| 191 | * |
||||
| 192 | * @return bool true si une classe de contrôleur est trouvée. |
||||
| 193 | */ |
||||
| 194 | private function searchLastDefaultController(): bool |
||||
| 195 | { |
||||
| 196 | 2 | $segments = $this->segments; |
|||
|
0 ignored issues
–
show
It seems like
$this->segments of type array is incompatible with the declared type BlitzPHP\Router\list of property $segments.
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. Loading history...
|
|||||
| 197 | |||||
| 198 | 2 | $segmentCount = count($this->segments); |
|||
| 199 | 2 | $paramPos = null; |
|||
| 200 | 2 | $params = []; |
|||
| 201 | |||||
| 202 | while ($segments !== []) { |
||||
| 203 | if ($segmentCount > count($segments)) { |
||||
| 204 | $paramPos = count($segments); |
||||
| 205 | } |
||||
| 206 | |||||
| 207 | $namespaces = array_map( |
||||
| 208 | fn ($segment) => $this->translateURI($segment), |
||||
| 209 | $segments |
||||
| 210 | ); |
||||
| 211 | |||||
| 212 | $controller = '\\' . $this->namespace |
||||
| 213 | . '\\' . implode('\\', $namespaces) |
||||
| 214 | . '\\' . $this->defaultController; |
||||
| 215 | |||||
| 216 | if (class_exists($controller)) { |
||||
| 217 | $this->controller = $controller; |
||||
| 218 | $this->params = $params; |
||||
|
0 ignored issues
–
show
It seems like
$params of type array is incompatible with the declared type BlitzPHP\Router\list of property $params.
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. Loading history...
|
|||||
| 219 | |||||
| 220 | if ($params !== []) { |
||||
| 221 | $this->paramPos = $paramPos; |
||||
| 222 | } |
||||
| 223 | |||||
| 224 | return true; |
||||
| 225 | } |
||||
| 226 | |||||
| 227 | // ajoutons le dernier élément dans $segments au début de $params. |
||||
| 228 | array_unshift($params, array_pop($segments)); |
||||
| 229 | } |
||||
| 230 | |||||
| 231 | // Vérifiez le contrôleur par défaut dans le répertoire des contrôleurs. |
||||
| 232 | $controller = '\\' . $this->namespace |
||||
| 233 | 2 | . '\\' . $this->defaultController; |
|||
| 234 | |||||
| 235 | if (class_exists($controller)) { |
||||
| 236 | 2 | $this->controller = $controller; |
|||
| 237 | 2 | $this->params = $params; |
|||
| 238 | |||||
| 239 | if ($params !== []) { |
||||
| 240 | $this->paramPos = 0; |
||||
| 241 | } |
||||
| 242 | |||||
| 243 | 2 | return true; |
|||
| 244 | } |
||||
| 245 | |||||
| 246 | return false; |
||||
| 247 | } |
||||
| 248 | |||||
| 249 | /** |
||||
| 250 | * Recherche contrôleur, méthode et params dans l'URI. |
||||
| 251 | * |
||||
| 252 | * @return array [directory_name, controller_name, controller_method, params] |
||||
| 253 | */ |
||||
| 254 | public function getRoute(string $uri, string $httpVerb): array |
||||
| 255 | { |
||||
| 256 | 4 | $this->uri = $uri; |
|||
| 257 | 4 | $httpVerb = strtolower($httpVerb); |
|||
| 258 | |||||
| 259 | // Reinitialise les parametres de la methode du controleur. |
||||
| 260 | 4 | $this->params = []; |
|||
|
0 ignored issues
–
show
It seems like
array() of type array is incompatible with the declared type BlitzPHP\Router\list of property $params.
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. Loading history...
|
|||||
| 261 | |||||
| 262 | 4 | $defaultMethod = $httpVerb . ucfirst($this->defaultMethod); |
|||
| 263 | 4 | $this->method = $defaultMethod; |
|||
| 264 | |||||
| 265 | 4 | $this->segments = $this->createSegments($uri); |
|||
|
0 ignored issues
–
show
It seems like
$this->createSegments($uri) of type array is incompatible with the declared type BlitzPHP\Router\list of property $segments.
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. Loading history...
|
|||||
| 266 | |||||
| 267 | // Verifier les routes de modules |
||||
| 268 | if ($this->segments !== [] && array_key_exists($this->segments[0], $this->moduleRoutes)) { |
||||
| 269 | 2 | $uriSegment = array_shift($this->segments); |
|||
| 270 | 2 | $this->namespace = rtrim($this->moduleRoutes[$uriSegment], '\\'); |
|||
| 271 | } |
||||
| 272 | |||||
| 273 | if ($this->searchFirstController()) { |
||||
| 274 | // Le contrôleur a ete trouvé. |
||||
| 275 | 4 | $baseControllerName = Helpers::classBasename($this->controller); |
|||
| 276 | |||||
| 277 | // Empêcher l'accès au chemin de contrôleur par défaut |
||||
| 278 | if (strtolower($baseControllerName) === strtolower($this->defaultController)) { |
||||
| 279 | throw new PageNotFoundException( |
||||
| 280 | 'Impossible d\'accéder au contrôleur par défaut "' . $this->controller . '" avec le nom du contrôleur comme chemin de l\'URI.' |
||||
| 281 | 4 | ); |
|||
| 282 | } |
||||
| 283 | } elseif ($this->searchLastDefaultController()) { |
||||
| 284 | // Le controleur par defaut a ete trouve. |
||||
| 285 | 2 | $baseControllerName = Helpers::classBasename($this->controller); |
|||
| 286 | } else { |
||||
| 287 | // Aucun controleur trouvé |
||||
| 288 | throw new PageNotFoundException('Aucun contrôleur trouvé pour: ' . $uri); |
||||
| 289 | } |
||||
| 290 | |||||
| 291 | // Le premier élément peut être un nom de méthode. |
||||
| 292 | /** @var list<string> $params */ |
||||
| 293 | 4 | $params = $this->params; |
|||
| 294 | |||||
| 295 | 4 | $methodParam = array_shift($params); |
|||
|
0 ignored issues
–
show
$params of type BlitzPHP\Router\list is incompatible with the type array expected by parameter $array of array_shift().
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 296 | |||||
| 297 | 4 | $method = ''; |
|||
| 298 | if ($methodParam !== null) { |
||||
| 299 | 2 | $method = $httpVerb . $this->translateURI($methodParam); |
|||
| 300 | |||||
| 301 | 2 | $this->checkUriForMethod($method); |
|||
| 302 | } |
||||
| 303 | |||||
| 304 | if ($methodParam !== null && method_exists($this->controller, $method)) { |
||||
| 305 | // Methode trouvee. |
||||
| 306 | 2 | $this->method = $method; |
|||
| 307 | 2 | $this->params = $params; |
|||
| 308 | |||||
| 309 | // Mise a jour des positions. |
||||
| 310 | 2 | $this->methodPos = $this->paramPos; |
|||
| 311 | if ($params === []) { |
||||
| 312 | 2 | $this->paramPos = null; |
|||
| 313 | } |
||||
| 314 | if ($this->paramPos !== null) { |
||||
| 315 | 2 | $this->paramPos++; |
|||
| 316 | } |
||||
| 317 | |||||
| 318 | // Empêcher l'accès à la méthode du contrôleur par défaut |
||||
| 319 | if (strtolower($baseControllerName) === strtolower($this->defaultController)) { |
||||
| 320 | throw new PageNotFoundException( |
||||
| 321 | 'Impossible d\'accéder au contrôleur par défaut "' . $this->controller . '::' . $this->method . '"' |
||||
| 322 | 2 | ); |
|||
| 323 | } |
||||
| 324 | |||||
| 325 | // Empêcher l'accès au chemin de méthode par défaut |
||||
| 326 | if (strtolower($this->method) === strtolower($defaultMethod)) { |
||||
| 327 | throw new PageNotFoundException( |
||||
| 328 | 'Impossible d\'accéder à la méthode par défaut "' . $this->method . '" avec le nom de méthode comme chemin d\'URI.' |
||||
| 329 | 2 | ); |
|||
| 330 | } |
||||
| 331 | } elseif (method_exists($this->controller, $defaultMethod)) { |
||||
| 332 | // La methode par defaut a ete trouvée |
||||
| 333 | 4 | $this->method = $defaultMethod; |
|||
| 334 | } else { |
||||
| 335 | // Aucune methode trouvee |
||||
| 336 | throw PageNotFoundException::controllerNotFound($this->controller, $method); |
||||
| 337 | } |
||||
| 338 | |||||
| 339 | // Vérifiez le contrôleur n'est pas défini dans les routes. |
||||
| 340 | 4 | $this->protectDefinedRoutes(); |
|||
| 341 | |||||
| 342 | // Assurez-vous que le contrôleur n'a pas la méthode _remap(). |
||||
| 343 | 4 | $this->checkRemap(); |
|||
| 344 | |||||
| 345 | // Assurez-vous que les segments URI pour le contrôleur et la méthode |
||||
| 346 | // ne contiennent pas de soulignement lorsque $translateURIDashes est true. |
||||
| 347 | 4 | $this->checkUnderscore(); |
|||
| 348 | |||||
| 349 | // Verifier le nombre de parametres |
||||
| 350 | try { |
||||
| 351 | 4 | $this->checkParameters(); |
|||
| 352 | } catch (MethodNotFoundException) { |
||||
| 353 | 2 | throw PageNotFoundException::controllerNotFound($this->controller, $this->method); |
|||
| 354 | } |
||||
| 355 | |||||
| 356 | 4 | $this->setDirectory(); |
|||
| 357 | |||||
| 358 | 4 | return [$this->directory, $this->controllerName(), $this->methodName(), $this->params]; |
|||
| 359 | } |
||||
| 360 | |||||
| 361 | /** |
||||
| 362 | * @internal Juste pour les tests. |
||||
| 363 | * |
||||
| 364 | * @return array<string, int|null> |
||||
| 365 | */ |
||||
| 366 | public function getPos(): array |
||||
| 367 | { |
||||
| 368 | return [ |
||||
| 369 | 'controller' => $this->controllerPos, |
||||
| 370 | 'method' => $this->methodPos, |
||||
| 371 | 'params' => $this->paramPos, |
||||
| 372 | 2 | ]; |
|||
| 373 | } |
||||
| 374 | |||||
| 375 | private function checkParameters(): void |
||||
| 376 | { |
||||
| 377 | try { |
||||
| 378 | 4 | $refClass = new ReflectionClass($this->controller); |
|||
| 379 | } catch (ReflectionException) { |
||||
| 380 | throw PageNotFoundException::controllerNotFound($this->controller, $this->method); |
||||
| 381 | } |
||||
| 382 | |||||
| 383 | try { |
||||
| 384 | 4 | $refMethod = $refClass->getMethod($this->method); |
|||
| 385 | 4 | $refParams = $refMethod->getParameters(); |
|||
| 386 | } catch (ReflectionException) { |
||||
| 387 | throw new MethodNotFoundException(); |
||||
| 388 | } |
||||
| 389 | |||||
| 390 | if (! $refMethod->isPublic()) { |
||||
| 391 | 4 | throw new MethodNotFoundException(); |
|||
| 392 | } |
||||
| 393 | |||||
| 394 | if (count($refParams) < count($this->params)) { |
||||
| 395 | throw new PageNotFoundException( |
||||
| 396 | 'Le nombre de param dans l\'URI est supérieur aux paramètres de la méthode du contrôleur.' |
||||
| 397 | . ' Handler:' . $this->controller . '::' . $this->method |
||||
| 398 | . ', URI:' . $this->uri |
||||
| 399 | 4 | ); |
|||
| 400 | } |
||||
| 401 | } |
||||
| 402 | |||||
| 403 | private function checkRemap(): void |
||||
| 404 | { |
||||
| 405 | try { |
||||
| 406 | 4 | $refClass = new ReflectionClass($this->controller); |
|||
| 407 | 4 | $refClass->getMethod('_remap'); |
|||
| 408 | |||||
| 409 | throw new PageNotFoundException( |
||||
| 410 | 'AutoRouterImproved ne prend pas en charge la methode `_remap()`.' |
||||
| 411 | . ' Contrôleur:' . $this->controller |
||||
| 412 | ); |
||||
| 413 | } catch (ReflectionException) { |
||||
| 414 | // Ne rien faire |
||||
| 415 | } |
||||
| 416 | } |
||||
| 417 | |||||
| 418 | private function checkUnderscore(): void |
||||
| 419 | { |
||||
| 420 | if ($this->translateURIDashes === false) { |
||||
| 421 | return; |
||||
| 422 | } |
||||
| 423 | |||||
| 424 | 4 | $paramPos = $this->paramPos ?? count($this->segments); |
|||
| 425 | |||||
| 426 | 4 | for ($i = 0; $i < $paramPos; $i++) { |
|||
| 427 | if (str_contains($this->segments[$i], '_')) { |
||||
| 428 | throw new PageNotFoundException( |
||||
| 429 | 'AutoRouterImproved interdit l\'accès à l\'URI' |
||||
| 430 | . ' contenant les undescore ("' . $this->segments[$i] . '")' |
||||
| 431 | . ' quand $translate_uri_dashes est activé.' |
||||
| 432 | . ' Veuillez utiliser les tiret.' |
||||
| 433 | . ' Handler:' . $this->controller . '::' . $this->method |
||||
| 434 | . ', URI:' . $this->uri |
||||
| 435 | 4 | ); |
|||
| 436 | } |
||||
| 437 | } |
||||
| 438 | } |
||||
| 439 | |||||
| 440 | /** |
||||
| 441 | * Vérifier l'URI du contrôleur pour $translateUriToCamelCase |
||||
| 442 | * |
||||
| 443 | * @param string $classname Nom de classe du contrôleur généré à partir de l'URI. |
||||
| 444 | * La casse peut être un peu incorrecte. |
||||
| 445 | */ |
||||
| 446 | private function checkUriForController(string $classname): void |
||||
| 447 | { |
||||
| 448 | if ($this->translateUriToCamelCase === false) { |
||||
| 449 | 4 | return; |
|||
| 450 | } |
||||
| 451 | |||||
| 452 | if (! in_array(ltrim($classname, '\\'), get_declared_classes(), true)) { |
||||
| 453 | throw new PageNotFoundException( |
||||
| 454 | '"' . $classname . '" n\'a pas été trouvé.' |
||||
| 455 | ); |
||||
| 456 | } |
||||
| 457 | } |
||||
| 458 | |||||
| 459 | /** |
||||
| 460 | * Vérifier l'URI pour la méthode $translateUriToCamelCase |
||||
| 461 | * |
||||
| 462 | * @param string $method Nom de la méthode du contrôleur généré à partir de l'URI. |
||||
| 463 | * La casse peut être un peu incorrecte. |
||||
| 464 | */ |
||||
| 465 | private function checkUriForMethod(string $method): void |
||||
| 466 | { |
||||
| 467 | if ($this->translateUriToCamelCase === false) { |
||||
| 468 | 2 | return; |
|||
| 469 | } |
||||
| 470 | |||||
| 471 | if ( |
||||
| 472 | // Par exemple, si `getSomeMethod()` existe dans le contrôleur, seul l'URI `controller/some-method` devrait être accessible. |
||||
| 473 | // Mais si un visiteur navigue vers l'URI `controller/somemethod`, `getSomemethod()` sera vérifié, et `method_exists()` retournera true parce que les noms de méthodes en PHP sont insensibles à la casse. |
||||
| 474 | method_exists($this->controller, $method) |
||||
| 475 | // Mais nous n'autorisons pas `controller/somemethod`, donc vérifiez le nom exact de la méthode. |
||||
| 476 | && ! in_array($method, get_class_methods($this->controller), true) |
||||
| 477 | ) { |
||||
| 478 | throw new PageNotFoundException( |
||||
| 479 | '"' . $this->controller . '::' . $method . '()" n\'a pas été trouvé.' |
||||
| 480 | ); |
||||
| 481 | } |
||||
| 482 | } |
||||
| 483 | |||||
| 484 | /** |
||||
| 485 | * Renvoie true si la chaîne $segment fournie représente un segment d'espace de noms/répertoire valide conforme à PSR-4 |
||||
| 486 | * |
||||
| 487 | * La regex vient de https://www.php.net/manual/en/language.variables.basics.php |
||||
| 488 | */ |
||||
| 489 | private function isValidSegment(string $segment): bool |
||||
| 490 | { |
||||
| 491 | 4 | return (bool) preg_match('/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/', $segment); |
|||
| 492 | } |
||||
| 493 | |||||
| 494 | private function translateURI(string $segment): string |
||||
| 495 | { |
||||
| 496 | if ($this->translateUriToCamelCase) { |
||||
| 497 | if (strtolower($segment) !== $segment) { |
||||
| 498 | throw new PageNotFoundException( |
||||
| 499 | 'AutoRouter interdit l\'accès à l\'URI' |
||||
| 500 | . ' contenant des lettres majuscules ("' . $segment . '")' |
||||
| 501 | . ' lorsque $translateUriToCamelCase est activé.' |
||||
| 502 | . ' Veuillez utiliser le tiret.' |
||||
| 503 | . ' URI:' . $this->uri |
||||
| 504 | ); |
||||
| 505 | } |
||||
| 506 | |||||
| 507 | if (str_contains($segment, '--')) { |
||||
| 508 | throw new PageNotFoundException( |
||||
| 509 | 'AutoRouter interdit l\'accès à l\'URI' |
||||
| 510 | . ' contenant un double tiret ("' . $segment . '")' |
||||
| 511 | . ' lorsque $translateUriToCamelCase est activé.' |
||||
| 512 | . ' Veuillez utiliser le tiret simple.' |
||||
| 513 | . ' URI:' . $this->uri |
||||
| 514 | ); |
||||
| 515 | } |
||||
| 516 | |||||
| 517 | return str_replace( |
||||
| 518 | ' ', |
||||
| 519 | '', |
||||
| 520 | ucwords( |
||||
| 521 | preg_replace('/[\-]+/', ' ', $segment) |
||||
| 522 | ) |
||||
| 523 | ); |
||||
| 524 | } |
||||
| 525 | |||||
| 526 | 4 | $segment = ucfirst($segment); |
|||
| 527 | |||||
| 528 | if ($this->translateURIDashes) { |
||||
| 529 | 4 | return str_replace('-', '_', $segment); |
|||
| 530 | } |
||||
| 531 | |||||
| 532 | return $segment; |
||||
| 533 | } |
||||
| 534 | |||||
| 535 | /** |
||||
| 536 | * Obtenez le chemin du dossier du contrôleur et définissez-le sur la propriété. |
||||
| 537 | */ |
||||
| 538 | private function setDirectory(): void |
||||
| 539 | { |
||||
| 540 | 4 | $segments = explode('\\', trim($this->controller, '\\')); |
|||
| 541 | |||||
| 542 | // Supprimer le court nom de classe. |
||||
| 543 | 4 | array_pop($segments); |
|||
| 544 | |||||
| 545 | 4 | $namespaces = implode('\\', $segments); |
|||
| 546 | |||||
| 547 | $dir = str_replace( |
||||
| 548 | '\\', |
||||
| 549 | '/', |
||||
| 550 | ltrim(substr($namespaces, strlen($this->namespace)), '\\') |
||||
| 551 | 4 | ); |
|||
| 552 | |||||
| 553 | if ($dir !== '') { |
||||
| 554 | 4 | $this->directory = $dir . '/'; |
|||
| 555 | } |
||||
| 556 | } |
||||
| 557 | |||||
| 558 | private function protectDefinedRoutes(): void |
||||
| 559 | { |
||||
| 560 | 4 | $controller = strtolower($this->controller); |
|||
| 561 | |||||
| 562 | foreach ($this->protectedControllers as $controllerInRoutes) { |
||||
| 563 | 4 | $routeLowerCase = strtolower($controllerInRoutes); |
|||
| 564 | |||||
| 565 | if ($routeLowerCase === $controller) { |
||||
| 566 | throw new PageNotFoundException( |
||||
| 567 | 'Impossible d\'accéder à un contrôleur définie dans les routes. Contrôleur : ' . $controllerInRoutes |
||||
| 568 | ); |
||||
| 569 | } |
||||
| 570 | } |
||||
| 571 | } |
||||
| 572 | |||||
| 573 | /** |
||||
| 574 | * Renvoie le nom du sous-répertoire dans lequel se trouve le contrôleur. |
||||
| 575 | * Relatif à CONTROLLER_PATH |
||||
| 576 | * |
||||
| 577 | * @deprecated 1.0 |
||||
| 578 | */ |
||||
| 579 | public function directory(): string |
||||
| 580 | { |
||||
| 581 | return $this->directory !== null && $this->directory !== '' && $this->directory !== '0' ? $this->directory : ''; |
||||
| 582 | } |
||||
| 583 | |||||
| 584 | /** |
||||
| 585 | * Renvoie le nom du contrôleur matché |
||||
| 586 | */ |
||||
| 587 | private function controllerName(): string |
||||
| 588 | { |
||||
| 589 | return $this->translateURIDashes |
||||
| 590 | ? str_replace('-', '_', trim($this->controller, '/\\')) |
||||
| 591 | 4 | : Text::convertTo($this->controller, 'pascal'); |
|||
| 592 | } |
||||
| 593 | |||||
| 594 | /** |
||||
| 595 | * Retourne le nom de la méthode à exécuter |
||||
| 596 | */ |
||||
| 597 | private function methodName(): string |
||||
| 598 | { |
||||
| 599 | return $this->translateURIDashes |
||||
| 600 | ? str_replace('-', '_', $this->method) |
||||
| 601 | 4 | : Text::convertTo($this->method, 'camel'); |
|||
| 602 | } |
||||
| 603 | |||||
| 604 | /** |
||||
| 605 | * Construit un nom de contrôleur valide |
||||
| 606 | */ |
||||
| 607 | public function makeController(string $name): string |
||||
| 608 | { |
||||
| 609 | return preg_replace( |
||||
| 610 | ['#(\_)?Controller$#i', '#' . config('app.url_suffix') . '$#i'], |
||||
|
0 ignored issues
–
show
Are you sure
config('app.url_suffix') of type T|null|object can be used in concatenation?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 611 | '', |
||||
| 612 | ucfirst($name) |
||||
| 613 | 4 | ) . 'Controller'; |
|||
| 614 | } |
||||
| 615 | } |
||||
| 616 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths