| Current Path : /var/www/html/redd/app/Services/ |
| Current File : /var/www/html/redd/app/Services/ControllerScanner.php |
<?php
namespace App\Services;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
use ReflectionClass;
use ReflectionMethod;
class ControllerScanner
{
protected string $controllersPath;
protected array $resourceMethods = [
'index' => 'GET',
'create' => 'GET',
'store' => 'POST',
'show' => 'GET',
'edit' => 'GET',
'update' => 'PUT',
'destroy' => 'DELETE',
];
public function __construct()
{
$this->controllersPath = app_path('Http/Controllers');
}
public function scan(): array
{
$controllers = $this->findControllers($this->controllersPath);
$routes = [];
foreach ($controllers as $controller) {
$routes = array_merge($routes, $this->processController($controller));
}
return $routes;
}
protected function findControllers(string $path): array
{
$controllers = [];
$items = glob($path . '/*');
foreach ($items as $item) {
if (is_dir($item)) {
$controllers = array_merge($controllers, $this->findControllers($item));
} elseif (is_file($item) && str_ends_with($item, 'Controller.php')) {
$controllers[] = $item;
}
}
return $controllers;
}
protected function processController(string $filePath): array
{
$className = $this->getFullClassName($filePath);
if (!$className || !class_exists($className)) {
return [];
}
$reflection = new ReflectionClass($className);
if ($reflection->isAbstract()) {
return [];
}
$methods = $reflection->getMethods(ReflectionMethod::IS_PUBLIC);
$routes = [];
foreach ($methods as $method) {
if ($method->getDeclaringClass()->getName() !== $className) {
continue;
}
if ($this->shouldSkipMethod($method->getName())) {
continue;
}
$routes[] = $this->generateRouteData($className, $method);
}
return $routes;
}
protected function shouldSkipMethod(string $methodName): bool
{
$skipMethods = [
'__construct', '__destruct', '__call', '__callStatic',
'__get', '__set', '__isset', '__unset',
'__sleep', '__wakeup', '__serialize', '__unserialize',
'__toString', '__invoke', '__set_state',
'Middleware', 'middleware',
];
if (str_starts_with($methodName, 'middleware')) {
return true;
}
return in_array($methodName, $skipMethods);
}
protected function generateRouteData(string $className, ReflectionMethod $method): array
{
$shortName = $this->getShortControllerName($className);
$methodName = $method->getName();
$baseUri = $this->generateUriFromController($className, $methodName);
$methodType = $this->determineMethodType($methodName);
return [
'controller' => $className,
'action' => $methodName,
'uri' => $baseUri,
'method' => $methodType,
'type' => $this->determineTypeFromNamespace($className),
];
}
protected function getFullClassName(string $filePath): ?string
{
$content = file_get_contents($filePath);
if (preg_match('/namespace\s+([^;]+);/', $content, $matches)) {
$namespace = $matches[1];
$className = basename($filePath, '.php');
return $namespace . '\\' . $className;
}
return null;
}
protected function getShortControllerName(string $fullClassName): string
{
return class_basename($fullClassName);
}
protected function generateUriFromController(string $className, string $methodName): string
{
$baseName = class_basename($className);
$controllerName = str_replace('Controller', '', $baseName);
$controllerUri = Str::kebab($controllerName);
if ($methodName === 'index') {
return '/' . $controllerUri;
}
if (isset($this->resourceMethods[$methodName])) {
if ($methodName === 'create') {
return '/' . $controllerUri . '/create';
}
if ($methodName === 'edit') {
return '/' . $controllerUri . '/{' . Str::camel(Str::singular($controllerUri)) . '}/edit';
}
if ($methodName === 'show') {
return '/' . $controllerUri . '/{' . Str::camel(Str::singular($controllerUri)) . '}';
}
if ($methodName === 'store') {
return '/' . $controllerUri;
}
if ($methodName === 'update') {
return '/' . $controllerUri . '/{' . Str::camel(Str::singular($controllerUri)) . '}';
}
if ($methodName === 'destroy') {
return '/' . $controllerUri . '/{' . Str::camel(Str::singular($controllerUri)) . '}';
}
}
return '/' . $controllerUri . '/' . Str::kebab($methodName);
}
protected function determineMethodType(string $methodName): string
{
return $this->resourceMethods[$methodName] ?? 'GET';
}
protected function determineTypeFromNamespace(string $className): string
{
if (str_contains($className, 'Admin\\')) {
return 'admin';
}
if (str_contains($className, 'Api\\') || str_contains($className, 'Controllers\\Api\\')) {
return 'api';
}
return 'web';
}
public function scanAndCache(): array
{
$routes = $this->scan();
Cache::put('scanned_controllers', $routes, now()->addDay());
return $routes;
}
public function getCached(): ?array
{
return Cache::get('scanned_controllers');
}
public function clearCache(): bool
{
return Cache::forget('scanned_controllers');
}
public function refresh(): array
{
$this->clearCache();
return $this->scanAndCache();
}
}