#!/usr/bin/env php clase por nombre de archivo (basename => FQCN) */ function project_commands(): array { $classes = []; foreach (glob(rtrim(ROOT_CORE, '/') . '/Commands/*.php') as $file) { $base = basename($file, '.php'); $class = 'Commands\\' . $base; if (class_exists($class) && is_a($class, 'Interfaces\\CommandInterface', true)) { $classes[$base] = $class; } } return $classes; } /** * @param array $classes * @return array alias => FQCN */ function alias_map(array $classes): array { $map = []; $byLower = []; foreach ($classes as $base => $class) { $byLower[strtolower($base)] = $class; } foreach ($classes as $base => $class) { if (!method_exists($class, 'aliases')) { continue; } foreach ($class::aliases() as $alias) { $owner = strtolower($base); $key = strtolower((string) $alias); if ($key === $owner) { continue; } if (isset($map[$key]) && $map[$key] !== $class) { fwrite(STDERR, "Conflicto de alias '{$alias}': lo declaran {$map[$key]} y {$class}.\n"); exit(1); } if (isset($byLower[$key])) { fwrite(STDERR, "El alias '{$alias}' de {$class} colisiona con el comando {$byLower[$key]}.\n"); exit(1); } $map[$key] = $class; } } return $map; } $classes = project_commands(); $map = alias_map($classes); $command = $argv[1] ?? null; if ($command === null) { $rev = []; foreach ($map as $alias => $class) { $rev[$class][] = $alias; } foreach ($classes as $base => $class) { $line = ' ' . strtolower($base); if (($rev[$class] ?? []) !== []) { $line .= ', ' . implode(', ', $rev[$class]); } fwrite(STDOUT, $line . ' — ' . $class::describe() . "\n"); } exit(0); } $direct = 'Commands\\' . ucfirst($command); $class = null; $slice = 2; if (class_exists($direct) && is_a($direct, 'Interfaces\\CommandInterface', true)) { $class = $direct; } else { $class = $map[strtolower($command)] ?? null; $slice = $class === null ? $slice : 1; } if ($class === null) { fwrite(STDERR, "Comando desconocido: {$command}\n"); exit(1); } $cli = new $class(); call_user_func_array([$cli, 'run'], array_slice($argv, $slice));