cache = $cache; if ($folderList !== null) { $this->folderList = $folderList; } if ($annotations !== null) { $this->annotations = $annotations; } else { $this->annotations = [ 'object' => [ Attribute\Command::class, Attribute\Option::class ], 'method' => [ Attribute\Command::class, Attribute\Option::class ], ]; } } public function addFolder($folder) : void { $this->folderList[] = $folder; } public function setFolderList(array $list) : void { $this->folderList = $list; } public function scan(? array $folders = null) : Generator { foreach($folders ?: $this->folderList as $namespace => $folder) { if ( ! file_exists($folder) ) { throw new RuntimeException(sprintf("Folder `%s` can not be found or scanned", $folder)); } foreach (new DirectoryIterator($folder) as $fileinfo) { if ( ! $fileinfo->isDot() ) { if ( $fileinfo->isDir() ) { foreach($this->scan([ "{$namespace}\\" . $fileinfo->getBasename() => $fileinfo->getPathname() ]) as $ns2 => $fi2) { yield $ns2 => $fi2; } } else { yield $namespace => $fileinfo; } } } } } public function compile() : CommandStack { return $this->handleCaching(substr(md5(serialize($this->annotations)), 0, 7), function() : CommandStack { $stack = new CommandStack(); $classCmd = []; foreach($this->scan() as $namespace => $file) { if ( $file->getExtension() !== "php" ) { continue; } $basename = $file->getBasename(".php"); $class = $this->generateClassname($basename, $namespace); $objectResolver = new ObjectResolver($class, $this->cache); $attributes = $objectResolver->getAttributeListFromClassname( $this->annotations['object'], false ) ; $commandList = array_filter($attributes, fn($e) => $e instanceof Attribute\Command); ksort($commandList); if ($commandList) { $fullCommand = []; # Build full command token foreach($commandList as $cmd) { if ($cmd->command) { $fullCommand[] = $cmd->command; } } $fullCommand = implode(' ', $fullCommand); $commandHeader = new Command(name: $fullCommand, description: end($commandList)->description); $commandHeader->pushOption(array_filter($attributes, fn($e) => $e instanceof Attribute\Option)); $stack->append($commandHeader); foreach($objectResolver->getAttributeListFromClassname( $this->annotations['method'], false ) as $method => $commands) { if (is_array($commands) ) { $commandAttribute = array_filter($commands, fn($e) => $e instanceof Attribute\Command)[0] ?? null; $name = implode(' ', array_filter( [ $fullCommand, $commandAttribute->command ?? $method ])); $commandFunction = new Command(name: $name, description: $commandAttribute->description, parent: $commandHeader, callback: "$class::$method"); $stack->append($commandFunction); $commandFunction->pushOption(array_filter($commands, fn($e) => $e instanceof Attribute\Option)); } } } } return $stack; }); } protected function generateClassname($file, $namespace) { return "\\$namespace\\$file"; } }