From 0002837bd6d7192edc23ec05c1733ed043f12348 Mon Sep 17 00:00:00 2001 From: Julien Rosset Date: Fri, 21 Apr 2023 12:43:34 +0200 Subject: [PATCH] =?UTF-8?q?AutoDiscoverySpot=20=E2=86=92=20AutoDiscoveryDi?= =?UTF-8?q?rectory=20+=20manage=20AutoPrefix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...erySpot.php => AutoDiscoveryDirectory.php} | 78 ++++++++-- src/CliProgram/AutoDiscoverySpotClass.php | 136 ------------------ src/CliProgram/IAutoDiscoverySpotClass.php | 21 --- ...tion.php => TAutoDiscoveryApplication.php} | 2 +- ...lication.php => TAutoPrefixManagement.php} | 43 +++--- 5 files changed, 90 insertions(+), 190 deletions(-) rename src/CliProgram/{AutoDiscoverySpot.php => AutoDiscoveryDirectory.php} (52%) delete mode 100644 src/CliProgram/AutoDiscoverySpotClass.php delete mode 100644 src/CliProgram/IAutoDiscoverySpotClass.php rename src/CliProgram/{AutoDiscoveryApplication.php => TAutoDiscoveryApplication.php} (97%) rename src/CliProgram/{AutoPrefixApplication.php => TAutoPrefixManagement.php} (58%) diff --git a/src/CliProgram/AutoDiscoverySpot.php b/src/CliProgram/AutoDiscoveryDirectory.php similarity index 52% rename from src/CliProgram/AutoDiscoverySpot.php rename to src/CliProgram/AutoDiscoveryDirectory.php index 9695c43..995b1e5 100644 --- a/src/CliProgram/AutoDiscoverySpot.php +++ b/src/CliProgram/AutoDiscoveryDirectory.php @@ -3,6 +3,7 @@ namespace jrosset\CliProgram; use FilesystemIterator; +use jrosset\BetterPhpToken\BetterPhpToken; use ReflectionClass; use ReflectionException; use Symfony\Component\Console\Command\Command; @@ -10,7 +11,9 @@ use Symfony\Component\Console\Command\Command; /** * A spot for command auto discovery */ -class AutoDiscoverySpot implements IAutoDiscoverySpot { +class AutoDiscoveryDirectory implements IAutoDiscoverySpot { + use TAutoPrefixManagement; + /** * @var string The directory path */ @@ -75,7 +78,7 @@ class AutoDiscoverySpot implements IAutoDiscoverySpot { * @inheritDoc */ public function getCommands (): array { - return static::getClassesOfDirectory($this->getDirectoryPath(), $this->isProcessSubDirectories()); + return $this->getClassesOfDirectory($this->getDirectoryPath()); } /** * Get spot's classes of a directory @@ -85,7 +88,7 @@ class AutoDiscoverySpot implements IAutoDiscoverySpot { * * @return Command[] Spot's classes */ - private static function getClassesOfDirectory (string $directoryPath, bool $processSubDirectories): array { + private function getClassesOfDirectory (string $directoryPath): array { $classes = []; $directoryIterator = new FilesystemIterator($directoryPath, FilesystemIterator::CURRENT_AS_SELF); @@ -94,24 +97,26 @@ class AutoDiscoverySpot implements IAutoDiscoverySpot { continue; } if ($fileInfo->isDir()) { - if ($processSubDirectories) { - /** @noinspection PhpConditionAlreadyCheckedInspection */ + if ($this->isProcessSubDirectories()) { $classes = array_merge( $classes, - static::getClassesOfDirectory($fileInfo->getPathname(), $processSubDirectories) + $this->getClassesOfDirectory($fileInfo->getPathname()) ); } continue; } - $spotClass = AutoDiscoverySpotClass::createFromFile($fileInfo->getPathname()); - $classPath = realpath($spotClass->getName()); - if (array_key_exists($classPath, $classes)) { + if (array_key_exists($fileInfo->getRealPath(), $classes)) { + continue; + } + + $className = static::getClassNameFromFile($fileInfo->getRealPath()); + if ($className === null) { continue; } try { - $class = new ReflectionClass($spotClass->getName()); + $class = new ReflectionClass($className); if ($class->isAbstract() || $class->isInterface() || $class->isTrait() @@ -120,7 +125,7 @@ class AutoDiscoverySpot implements IAutoDiscoverySpot { continue; } - $classes[$classPath] = $class->newInstance(); + $classes[$fileInfo->getRealPath()] = $this->applyAutoPrefixOnCommand($class->newInstance()); } catch (ReflectionException $exception) { continue; @@ -129,4 +134,55 @@ class AutoDiscoverySpot implements IAutoDiscoverySpot { return $classes; } + /** + * Extract the class name from a file + * + * Extract only the first class name + * + * @param string $path The class file path + * + * @return string|null The class name ou null if none + */ + private static function getClassNameFromFile (string $path): ?string { + defined('T_NAME_QUALIFIED') || define('T_NAME_QUALIFIED', 10002); + + $fileHandler = fopen($path, 'r'); + + $namespace = $buffer = ''; + $currTokenGlobal = 0; + while (!feof($fileHandler)) { + $buffer .= fread($fileHandler, 512); + if (mb_strpos($buffer, '{') === false) { + continue; + } + + $tokens = BetterPhpToken::tokenize($buffer); + $nbTokens = count($tokens); + for (; $currTokenGlobal < $nbTokens; $currTokenGlobal++) { + $token = $tokens[$currTokenGlobal]; + if ($token->is(T_NAMESPACE)) { + for ($currTokenSub = $currTokenGlobal + 1; $currTokenSub < $nbTokens; $currTokenSub++) { + $subToken = $tokens[$currTokenSub]; + + if ($subToken->is(T_STRING, T_NAME_QUALIFIED)) { + $namespace .= '\\' . $subToken->getText(); + } + elseif ($subToken->getText() === '{' || $subToken->getText() === ';') { + break; + } + } + } + elseif ($token->is(T_CLASS) && ($currTokenGlobal === 0 || !$tokens[$currTokenGlobal - 1]->is(T_DOUBLE_COLON))) { + for ($currTokenSub = $currTokenGlobal + 1; $currTokenSub < $nbTokens; $currTokenSub++) { + $subToken = $tokens[$currTokenSub]; + if ($subToken->getText() === '{') { + return (mb_strlen($namespace) > 0 ? $namespace . '\\' : '') . $tokens[$currTokenGlobal + 2]->getText(); + } + } + } + } + } + + return null; + } } \ No newline at end of file diff --git a/src/CliProgram/AutoDiscoverySpotClass.php b/src/CliProgram/AutoDiscoverySpotClass.php deleted file mode 100644 index 2b20b74..0000000 --- a/src/CliProgram/AutoDiscoverySpotClass.php +++ /dev/null @@ -1,136 +0,0 @@ -setPath($path); - $this->setName($name); - } - - /** - * Create from file path only - * - * Get the first class name of the file - * - * @param string $path The class file path - * - * @return $this - */ - public static function createFromFile (string $path): self { - defined('T_NAME_QUALIFIED') || define('T_NAME_QUALIFIED', 10002); - - $fileHandler = fopen($path, 'r'); - - $class = $namespace = $buffer = ''; - $currTokenGlobal = 0; - while (!feof($fileHandler)) { - $buffer .= fread($fileHandler, 512); - if (mb_strpos($buffer, '{') === false) { - continue; - } - - $tokens = BetterPhpToken::tokenize($buffer); - $nbTokens = count($tokens); - for (; $currTokenGlobal < $nbTokens; $currTokenGlobal++) { - $token = $tokens[$currTokenGlobal]; - if ($token->is(T_NAMESPACE)) { - for ($currTokenSub = $currTokenGlobal + 1; $currTokenSub < $nbTokens; $currTokenSub++) { - $subToken = $tokens[$currTokenSub]; - - if ($subToken->is(T_STRING, T_NAME_QUALIFIED)) { - $namespace .= '\\' . $subToken->getText(); - } - elseif ($subToken->getText() === '{' || $subToken->getText() === ';') { - break; - } - } - } - elseif ($token->is(T_CLASS) && ($currTokenGlobal === 0 || !$tokens[$currTokenGlobal - 1]->is(T_DOUBLE_COLON))) { - for ($currTokenSub = $currTokenGlobal + 1; $currTokenSub < $nbTokens; $currTokenSub++) { - $subToken = $tokens[$currTokenSub]; - if ($subToken->getText() === '{') { - $class = $tokens[$currTokenGlobal + 2]->getText(); - } - } - } - } - } - - return new static((mb_strlen($namespace) > 0 ? $namespace . '\\' : '') . $class, $path); - } - - /** - * @inheritDoc - */ - public function getName (): string { - return $this->name; - } - /** - * Set the class name - * - * @param class-string $name The class name - * - * @return $this - */ - public function setName (string $name): self { - $this->name = $name; - return $this; - } - - /** - * @inheritDoc - */ - public function getPath (): string { - return $this->path; - } - /** - * Set the class file path - * - * @param string $path The class file path - * - * @return $this - * - * @throws LogicException If the file path doesn't exist - * @throws RuntimeException If the file path isn't readable - */ - public function setPath (string $path): self { - if (!file_exists($path)) { - throw new LogicException('Invalid class path: file is missing'); - } - if (!is_readable($path)) { - throw new RuntimeException('Invalid class path: file is not readable'); - } - - $this->path = realpath($path); - return $this; - } -} \ No newline at end of file diff --git a/src/CliProgram/IAutoDiscoverySpotClass.php b/src/CliProgram/IAutoDiscoverySpotClass.php deleted file mode 100644 index 5cd6f99..0000000 --- a/src/CliProgram/IAutoDiscoverySpotClass.php +++ /dev/null @@ -1,21 +0,0 @@ -all(), SORT_REGULAR); // Remove commands duplicate caused by aliases - foreach ($commands as $command) { - foreach ($this->getAutoPrefixManagers() as $autoPrefixManager) { - if (($namesPrefix = $autoPrefixManager->getCommandPrefix($command)) !== null) { - if (mb_strlen($namesPrefix) > 0) { - $namesPrefix .= ':'; - } - - $command->setName($namesPrefix . $command->getName()); + protected function applyAutoPrefixOnCommand (Command $command): Command { + foreach ($this->getAutoPrefixManagers() as $autoPrefixManager) { + if (($namesPrefix = $autoPrefixManager->getCommandPrefix($command)) !== null) { + if (mb_strlen($namesPrefix) > 0) { + $namesPrefix .= ':'; + } - $aliases = $command->getAliases(); - foreach ($aliases as &$alias) { - $alias = $namesPrefix . $alias; - } - $command->setAliases($aliases); + $command->setName($namesPrefix . $command->getName()); - break; + $aliases = $command->getAliases(); + foreach ($aliases as &$alias) { + $alias = $namesPrefix . $alias; } + $command->setAliases($aliases); + + break; } } - return $this; + return $command; } } \ No newline at end of file