diff --git a/composer.json b/composer.json index b64bc04..94f621a 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "vendor-dir": "vendor" }, "require-dev": { - "phpunit/phpunit": "^9.5" + "phpunit/phpunit": "^10" }, "scripts": { "test": "phpunit" diff --git a/phpunit.xml.dist b/phpunit.xml.dist index c216ef1..4ea85d6 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,14 +1,8 @@ - + ./tests/ - \ No newline at end of file + diff --git a/readme.md b/readme.md index de3d862..5251215 100644 --- a/readme.md +++ b/readme.md @@ -43,6 +43,26 @@ $classes = \SH\AutoHook\ComposerJsonParser::getClasses($composerJsonPath); // Process classes to string [$output] = \SH\AutoHook\AttributeResolver::processClassesToString($classes); +// Write to file +(bool) $written = \SH\AutoHook\FileWriter::write($output, $outputPath); + ``` + +### Advanced Usage + +Some projects may not have the composer.json available at runtime, so you can use the class loader object. + +#### Build/Wire Up + + ```php +// Get Classloader object +$loader = require 'vendor/autoload.php'; + +// Get the list of classes +$classes = \SH\AutoHook\ComposerClassLoaderParser::getClasses($loader, ['App\\', 'MyNamespace\\']); + +// Process classes to string +[$output] = \SH\AutoHook\AttributeResolver::processClassesToString($classes); + // Write to file (bool) $written = \SH\AutoHook\FileWriter::write($output, $outputPath); ``` diff --git a/src/ComposerClassLoaderParser.php b/src/ComposerClassLoaderParser.php new file mode 100644 index 0000000..664eb21 --- /dev/null +++ b/src/ComposerClassLoaderParser.php @@ -0,0 +1,68 @@ + $namespaces Since the classloader does not know which are project vs vendor namespaces, you can pass in an array of namespaces to filter by. + * + * @return array + */ + public static function getClasses(ClassLoader $classLoader, array $namespaces = []): array + { + ['namespaces' => $allNamespaces, 'classes' => $classes] = self::getNamespacesAndClasses($classLoader); + + $namespaces = $namespaces ?: array_keys($allNamespaces); + $classes = array_keys($classes); + + $matches = []; + foreach ($namespaces as $namespace) { + foreach ($classes as $key => $class) { + if (str_starts_with($class, $namespace)) { + $matches[] = $class; + + unset($classes[$key]); + } + } + } + + return $matches; + } + + /** + * Returns an array with detailed information about namespaces and classes. + * + * Namespaces(k:namespace, v:paths array): map of namespaces and their absolute paths. + * Classes(k:class, v:path): map of classes and their absolute path. + * + * @return array{ + * namespaces: array>, + * classes: array + * } + * + * Example: + * [ + * 'namespaces' => [ + * 'MyApp\\Controllers' => ['/Users/jphndpe/Project/src/Controllers/'], + * 'MyApp\\Models' => ['/Users/jphndpe/Project/src/Models/'], + * ], + * 'classes' => [ + * 'MyApp\\Controllers\\HomeController' => '/Users/jphndpe/Project/src/Controllers/HomeController.php', + * 'MyApp\\Models\\UserModel' => '/Users/jphndpe/Project/src/Models/UserModel.php', + * ] + * ] + */ + public static function getNamespacesAndClasses(ClassLoader $classLoader): array + { + return [ + 'namespaces' => $classLoader->getPrefixesPsr4(), + 'classes' => $classLoader->getClassMap() + ]; + } +} \ No newline at end of file diff --git a/tests/ComposerClassLoaderParserTest.php b/tests/ComposerClassLoaderParserTest.php new file mode 100644 index 0000000..d511734 --- /dev/null +++ b/tests/ComposerClassLoaderParserTest.php @@ -0,0 +1,40 @@ + $namespaces, 'classes' => $classes] = ComposerClassLoaderParser::getNamespacesAndClasses(self::getClassLoader()); + + self::assertArrayHasKey('SH\\AutoHook\\', $namespaces); + self::assertArrayHasKey(ComposerClassLoaderParser::class, $classes); + } + + private static function getClassLoader(): ClassLoader + { + static $classLoader; + + if (null === $classLoader) { + $classLoader = require __DIR__.'/../vendor/autoload.php'; + } + + return $classLoader; + } +} \ No newline at end of file