175 lines
4.9 KiB
175 lines
4.9 KiB
<?php |
|
|
|
/** |
|
* This file is part of CodeIgniter 4 framework. |
|
* |
|
* (c) CodeIgniter Foundation <admin@codeigniter.com> |
|
* |
|
* For the full copyright and license information, please view |
|
* the LICENSE file that was distributed with this source code. |
|
*/ |
|
|
|
namespace CodeIgniter\Commands\Utilities\Routes; |
|
|
|
use ReflectionClass; |
|
use ReflectionMethod; |
|
|
|
/** |
|
* Reads a controller and returns a list of auto route listing. |
|
* |
|
* @see \CodeIgniter\Commands\Utilities\Routes\ControllerMethodReaderTest |
|
*/ |
|
final class ControllerMethodReader |
|
{ |
|
/** |
|
* @var string the default namespace |
|
*/ |
|
private string $namespace; |
|
|
|
/** |
|
* @param string $namespace the default namespace |
|
*/ |
|
public function __construct(string $namespace) |
|
{ |
|
$this->namespace = $namespace; |
|
} |
|
|
|
/** |
|
* @param class-string $class |
|
* |
|
* @return list<array{route: string, handler: string}> |
|
*/ |
|
public function read(string $class, string $defaultController = 'Home', string $defaultMethod = 'index'): array |
|
{ |
|
$reflection = new ReflectionClass($class); |
|
|
|
if ($reflection->isAbstract()) { |
|
return []; |
|
} |
|
|
|
$classname = $reflection->getName(); |
|
$classShortname = $reflection->getShortName(); |
|
|
|
$output = []; |
|
$uriByClass = $this->getUriByClass($classname); |
|
|
|
if ($this->hasRemap($reflection)) { |
|
$methodName = '_remap'; |
|
|
|
$routeWithoutController = $this->getRouteWithoutController( |
|
$classShortname, |
|
$defaultController, |
|
$uriByClass, |
|
$classname, |
|
$methodName |
|
); |
|
$output = [...$output, ...$routeWithoutController]; |
|
|
|
$output[] = [ |
|
'route' => $uriByClass . '[/...]', |
|
'handler' => '\\' . $classname . '::' . $methodName, |
|
]; |
|
|
|
return $output; |
|
} |
|
|
|
foreach ($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { |
|
$methodName = $method->getName(); |
|
|
|
$route = $uriByClass . '/' . $methodName; |
|
|
|
// Exclude BaseController and initController |
|
// See system/Config/Routes.php |
|
if (preg_match('#\AbaseController.*#', $route) === 1) { |
|
continue; |
|
} |
|
if (preg_match('#.*/initController\z#', $route) === 1) { |
|
continue; |
|
} |
|
|
|
if ($methodName === $defaultMethod) { |
|
$routeWithoutController = $this->getRouteWithoutController( |
|
$classShortname, |
|
$defaultController, |
|
$uriByClass, |
|
$classname, |
|
$methodName |
|
); |
|
$output = [...$output, ...$routeWithoutController]; |
|
|
|
$output[] = [ |
|
'route' => $uriByClass, |
|
'handler' => '\\' . $classname . '::' . $methodName, |
|
]; |
|
} |
|
|
|
$output[] = [ |
|
'route' => $route . '[/...]', |
|
'handler' => '\\' . $classname . '::' . $methodName, |
|
]; |
|
} |
|
|
|
return $output; |
|
} |
|
|
|
/** |
|
* Whether the class has a _remap() method. |
|
*/ |
|
private function hasRemap(ReflectionClass $class): bool |
|
{ |
|
if ($class->hasMethod('_remap')) { |
|
$remap = $class->getMethod('_remap'); |
|
|
|
return $remap->isPublic(); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
/** |
|
* @param class-string $classname |
|
* |
|
* @return string URI path part from the folder(s) and controller |
|
*/ |
|
private function getUriByClass(string $classname): string |
|
{ |
|
// remove the namespace |
|
$pattern = '/' . preg_quote($this->namespace, '/') . '/'; |
|
$class = ltrim(preg_replace($pattern, '', $classname), '\\'); |
|
|
|
$classParts = explode('\\', $class); |
|
$classPath = ''; |
|
|
|
foreach ($classParts as $part) { |
|
// make the first letter lowercase, because auto routing makes |
|
// the URI path's first letter uppercase and search the controller |
|
$classPath .= lcfirst($part) . '/'; |
|
} |
|
|
|
return rtrim($classPath, '/'); |
|
} |
|
|
|
/** |
|
* Gets a route without default controller. |
|
*/ |
|
private function getRouteWithoutController( |
|
string $classShortname, |
|
string $defaultController, |
|
string $uriByClass, |
|
string $classname, |
|
string $methodName |
|
): array { |
|
if ($classShortname !== $defaultController) { |
|
return []; |
|
} |
|
|
|
$pattern = '#' . preg_quote(lcfirst($defaultController), '#') . '\z#'; |
|
$routeWithoutController = rtrim(preg_replace($pattern, '', $uriByClass), '/'); |
|
$routeWithoutController = $routeWithoutController ?: '/'; |
|
|
|
return [[ |
|
'route' => $routeWithoutController, |
|
'handler' => '\\' . $classname . '::' . $methodName, |
|
]]; |
|
} |
|
}
|
|
|