diff --git a/src/IO/Directory.php b/src/IO/Directory.php index 04ddd94..b6ffebb 100644 --- a/src/IO/Directory.php +++ b/src/IO/Directory.php @@ -1,78 +1,89 @@ <?php namespace Keruald\OmniTools\IO; class Directory { /// /// Constructors /// public function __construct ( private string $path, ) {} /// /// Getters and setters /// public function getPath () : string { return $this->path; } public function setPath (string $path) : self { $this->path = $path; return $this; } /// /// Directory properties methods /// public function exists () : bool { return is_dir($this->path); } public function isReadable () : bool { return is_readable($this->path); } public function isWritable () : bool { return is_writable($this->path); } /** * @return array<string, string> */ public function getPathInfo () : array { return pathinfo($this->path); } public function getParentDirectory () : string { return pathinfo($this->path, PATHINFO_DIRNAME); } public function getDirectoryName () : string { return pathinfo($this->path, PATHINFO_BASENAME); } /// /// Search files /// /** * Gets files in the directory matching a specific pattern, * using the PHP glob function. * * @return File[] */ public function glob (string $pattern) : array { return array_map( function ($file) { return new File($file); }, glob("$this->path/$pattern") ); } + /** + * @return Directory[] + */ + public function getSubdirectories () : array { + return array_map( + function ($dir) { + return new Directory($dir); + }, glob("$this->path/*", GLOB_ONLYDIR) + ); + } + } diff --git a/src/Registration/PSR4/PSR4Namespace.php b/src/Registration/PSR4/PSR4Namespace.php new file mode 100644 index 0000000..dc096df --- /dev/null +++ b/src/Registration/PSR4/PSR4Namespace.php @@ -0,0 +1,76 @@ +<?php +declare(strict_types=1); + +namespace Keruald\OmniTools\Registration\PSR4; + +use Keruald\OmniTools\IO\Directory; +use Keruald\OmniTools\IO\File; + +class PSR4Namespace { + + public function __construct ( + public string $namespacePrefix, + public string $baseDirectory, + ) { + } + + /// + /// Auto-discovery + /// + + /** + * Discover classes in the namespace folder following PSR-4 convention, + * directly at top-level, ignoring subdirectories. + * + * @see discoverRecursive + * @return string[] + */ + public function discover () : array { + $files = (new Directory($this->baseDirectory)) + ->glob("*.php"); + + return array_map(function (File $file) { + return $this->namespacePrefix + . "\\" . $file->getFileNameWithoutExtension(); + }, $files); + } + + /** + * Discover classes in the namespace folder following PSR-4 convention, + * including all subfolders. + * + * @return string[] + */ + public function discoverRecursive () : array { + $classes = $this->discover(); + + $subDirectories = (new Directory($this->baseDirectory)) + ->getSubdirectories(); + + foreach ($subDirectories as $dir) { + $ns = new PSR4Namespace( + $this->namespacePrefix . "\\" . $dir->getDirectoryName(), + $dir->getPath(), + ); + + array_push($classes, ...$ns->discoverRecursive()); + } + + return $classes; + } + + /** + * Discover classes for a specific namespace in a specific folder, + * following the PSR-4 convention, including all subfolders. + * + * @return string[] + */ + public static function discoverAllClasses ( + string $namespacePrefix, + string $baseDirectory + ) : array { + $ns = new PSR4Namespace($namespacePrefix, $baseDirectory); + return $ns->discoverRecursive(); + } + +} diff --git a/tests/Registration/PSR4/PSR4NamespaceTest.php b/tests/Registration/PSR4/PSR4NamespaceTest.php new file mode 100644 index 0000000..93dffc5 --- /dev/null +++ b/tests/Registration/PSR4/PSR4NamespaceTest.php @@ -0,0 +1,84 @@ +<?php +declare(strict_types=1); + +namespace Keruald\OmniTools\Tests\Registration\PSR4; + +use Keruald\OmniTools\Registration\PSR4\PSR4Namespace; + +use Keruald\OmniTools\Tests\WithData; +use PHPUnit\Framework\TestCase; + +class PSR4NamespaceTest extends TestCase { + + use WithData; + + /// + /// Discovery tests + /// + + const ALL_CLASSES = [ + "Acme\\SolarSystemLib\\Sun", + "Acme\\SolarSystemLib\\Planets\\Pluton", + "Acme\\SolarSystemLib\\Planets\\Inner\\Mercure", + "Acme\\SolarSystemLib\\Planets\\Inner\\Venus", + ]; + + /** + * @dataProvider provideClasses + */ + public function testDiscover ( + string $path, string $prefix, array $expected + ) : void { + $ns = new PSR4Namespace($prefix, $this->getDataPath($path)); + + $this->assertEquals($expected, $ns->discover()); + } + + public function testDiscoverRecursive () : void { + $baseDirectory = $this->getDataPath("SolarSystemLib"); + $ns = new PSR4Namespace("Acme\\SolarSystemLib", $baseDirectory); + + $this->assertEquals(self::ALL_CLASSES, $ns->discoverRecursive()); + } + + public function testDiscoverAllClasses () : void { + $actual = PSR4Namespace::discoverAllClasses( + "Acme\\SolarSystemLib", + $this->getDataPath("SolarSystemLib"), + ); + + $this->assertEquals(self::ALL_CLASSES, $actual); + + } + + /// + /// Data providers + /// + + public function provideClasses () : iterable { + // [string $path, string $prefix, string[] $expectedClasses] + yield ["MockLib", "Acme\\MockLib", [ + "Acme\\MockLib\\Bar", + "Acme\\MockLib\\Foo", + ]]; + + yield ["SolarSystemLib", "Acme\\SolarSystemLib", [ + "Acme\\SolarSystemLib\\Sun", + ]]; + + yield ["SolarSystemLib/Planets", "Acme\\SolarSystemLib\\Planets", [ + "Acme\\SolarSystemLib\\Planets\\Pluton", + ]]; + + yield [ + "SolarSystemLib/Planets/Inner", + "Acme\\SolarSystemLib\\Planets\\Inner", + [ + "Acme\\SolarSystemLib\\Planets\\Inner\\Mercure", + "Acme\\SolarSystemLib\\Planets\\Inner\\Venus", + ] + ]; + + yield ["NotExisting", "AnyPrefix", []]; + } +} diff --git a/tests/data/SolarSystemLib/Planets/Inner/Mercure.php b/tests/data/SolarSystemLib/Planets/Inner/Mercure.php new file mode 100644 index 0000000..73763dd --- /dev/null +++ b/tests/data/SolarSystemLib/Planets/Inner/Mercure.php @@ -0,0 +1,8 @@ +<?php +declare(strict_types=1); + +namespace Acme\SolarSystemLib\Planets\Inner; + +class Mercure { + +} diff --git a/tests/data/SolarSystemLib/Planets/Inner/Venus.php b/tests/data/SolarSystemLib/Planets/Inner/Venus.php new file mode 100644 index 0000000..0546152 --- /dev/null +++ b/tests/data/SolarSystemLib/Planets/Inner/Venus.php @@ -0,0 +1,8 @@ +<?php +declare(strict_types=1); + +namespace Acme\SolarSystemLib\Planets\Inner; + +class Venus { + +} diff --git a/tests/data/SolarSystemLib/Planets/Pluton.php b/tests/data/SolarSystemLib/Planets/Pluton.php new file mode 100644 index 0000000..5e7c5ec --- /dev/null +++ b/tests/data/SolarSystemLib/Planets/Pluton.php @@ -0,0 +1,8 @@ +<?php +declare(strict_types=1); + +namespace Acme\SolarSystemLib\Planets; + +class Pluton { + +} diff --git a/tests/data/SolarSystemLib/Sun.php b/tests/data/SolarSystemLib/Sun.php new file mode 100644 index 0000000..aa283f1 --- /dev/null +++ b/tests/data/SolarSystemLib/Sun.php @@ -0,0 +1,8 @@ +<?php +declare(strict_types=1); + +namespace Acme\SolarSystemLib; + +class Sun { + +}