Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 92 additions & 86 deletions src/StaticPHP/Registry/Registry.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use StaticPHP\Config\ArtifactConfig;
use StaticPHP\Config\PackageConfig;
use StaticPHP\ConsoleApplication;
use StaticPHP\Exception\FileSystemException;
use StaticPHP\Exception\RegistryException;
use StaticPHP\Util\FileSystem;
use Symfony\Component\Yaml\Yaml;
Expand Down Expand Up @@ -87,116 +88,121 @@ public static function loadRegistry(string $registry_file, bool $auto_require =

self::$current_registry_name = $registry_name;

// Load composer autoload if specified (for external registries with their own dependencies)
if (isset($data['autoload']) && is_string($data['autoload'])) {
$autoload_path = FileSystem::fullpath($data['autoload'], dirname($registry_file));
if (file_exists($autoload_path)) {
logger()->debug("Loading external autoload from: {$autoload_path}");
require_once $autoload_path;
} else {
logger()->warning("Autoload file not found: {$autoload_path}");
try {
// Load composer autoload if specified (for external registries with their own dependencies)
if (isset($data['autoload']) && is_string($data['autoload'])) {
$autoload_path = FileSystem::fullpath($data['autoload'], dirname($registry_file));
if (file_exists($autoload_path)) {
logger()->debug("Loading external autoload from: {$autoload_path}");
require_once $autoload_path;
} else {
logger()->warning("Autoload file not found: {$autoload_path}");
}
}
}

// load package configs
if (isset($data['package']['config']) && is_array($data['package']['config'])) {
foreach ($data['package']['config'] as $path) {
$path = FileSystem::fullpath($path, dirname($registry_file));
if (is_file($path)) {
self::$loaded_package_configs[] = PackageConfig::loadFromFile($path, $registry_name);
} elseif (is_dir($path)) {
self::$loaded_package_configs = array_merge(self::$loaded_package_configs, PackageConfig::loadFromDir($path, $registry_name));
// load package configs
if (isset($data['package']['config']) && is_array($data['package']['config'])) {
foreach ($data['package']['config'] as $path) {
$path = FileSystem::fullpath($path, dirname($registry_file));
if (is_file($path)) {
self::$loaded_package_configs[] = PackageConfig::loadFromFile($path, $registry_name);
} elseif (is_dir($path)) {
self::$loaded_package_configs = array_merge(self::$loaded_package_configs, PackageConfig::loadFromDir($path, $registry_name));
}
}
}
}

// load artifact configs
if (isset($data['artifact']['config']) && is_array($data['artifact']['config'])) {
foreach ($data['artifact']['config'] as $path) {
$path = FileSystem::fullpath($path, dirname($registry_file));
if (is_file($path)) {
self::$loaded_artifact_configs[] = ArtifactConfig::loadFromFile($path, $registry_name);
} elseif (is_dir($path)) {
self::$loaded_package_configs = array_merge(self::$loaded_package_configs, ArtifactConfig::loadFromDir($path, $registry_name));
// load artifact configs
if (isset($data['artifact']['config']) && is_array($data['artifact']['config'])) {
foreach ($data['artifact']['config'] as $path) {
$path = FileSystem::fullpath($path, dirname($registry_file));
if (is_file($path)) {
self::$loaded_artifact_configs[] = ArtifactConfig::loadFromFile($path, $registry_name);
} elseif (is_dir($path)) {
self::$loaded_package_configs = array_merge(self::$loaded_package_configs, ArtifactConfig::loadFromDir($path, $registry_name));
}
}
}
}

// load doctor items from PSR-4 directories
if (isset($data['doctor']['psr-4']) && is_assoc_array($data['doctor']['psr-4'])) {
foreach ($data['doctor']['psr-4'] as $namespace => $path) {
$path = FileSystem::fullpath($path, dirname($registry_file));
DoctorLoader::loadFromPsr4Dir($path, $namespace, $auto_require);
// load doctor items from PSR-4 directories
if (isset($data['doctor']['psr-4']) && is_assoc_array($data['doctor']['psr-4'])) {
foreach ($data['doctor']['psr-4'] as $namespace => $path) {
$path = FileSystem::fullpath($path, dirname($registry_file));
DoctorLoader::loadFromPsr4Dir($path, $namespace, $auto_require);
}
}
}

// load doctor items from specific classes
// Supports both array format ["ClassName"] and map format {"ClassName": "path/to/file.php"}
if (isset($data['doctor']['classes']) && is_array($data['doctor']['classes'])) {
foreach ($data['doctor']['classes'] as $key => $value) {
[$class, $file] = self::parseClassEntry($key, $value);
self::requireClassFile($class, $file, dirname($registry_file), $auto_require);
DoctorLoader::loadFromClass($class);
// load doctor items from specific classes
// Supports both array format ["ClassName"] and map format {"ClassName": "path/to/file.php"}
if (isset($data['doctor']['classes']) && is_array($data['doctor']['classes'])) {
foreach ($data['doctor']['classes'] as $key => $value) {
[$class, $file] = self::parseClassEntry($key, $value);
self::requireClassFile($class, $file, dirname($registry_file), $auto_require);
DoctorLoader::loadFromClass($class);
}
}
}

// load packages from PSR-4 directories
if (isset($data['package']['psr-4']) && is_assoc_array($data['package']['psr-4'])) {
foreach ($data['package']['psr-4'] as $namespace => $path) {
$path = FileSystem::fullpath($path, dirname($registry_file));
PackageLoader::loadFromPsr4Dir($path, $namespace, $auto_require);
// load packages from PSR-4 directories
if (isset($data['package']['psr-4']) && is_assoc_array($data['package']['psr-4'])) {
foreach ($data['package']['psr-4'] as $namespace => $path) {
$path = FileSystem::fullpath($path, dirname($registry_file));
PackageLoader::loadFromPsr4Dir($path, $namespace, $auto_require);
}
}

// load packages from specific classes
// Supports both array format ["ClassName"] and map format {"ClassName": "path/to/file.php"}
if (isset($data['package']['classes']) && is_array($data['package']['classes'])) {
foreach ($data['package']['classes'] as $key => $value) {
[$class, $file] = self::parseClassEntry($key, $value);
self::requireClassFile($class, $file, dirname($registry_file), $auto_require);
PackageLoader::loadFromClass($class);
}
}
}

// load packages from specific classes
// Supports both array format ["ClassName"] and map format {"ClassName": "path/to/file.php"}
if (isset($data['package']['classes']) && is_array($data['package']['classes'])) {
foreach ($data['package']['classes'] as $key => $value) {
[$class, $file] = self::parseClassEntry($key, $value);
self::requireClassFile($class, $file, dirname($registry_file), $auto_require);
PackageLoader::loadFromClass($class);
// load artifacts from PSR-4 directories
if (isset($data['artifact']['psr-4']) && is_assoc_array($data['artifact']['psr-4'])) {
foreach ($data['artifact']['psr-4'] as $namespace => $path) {
$path = FileSystem::fullpath($path, dirname($registry_file));
ArtifactLoader::loadFromPsr4Dir($path, $namespace, $auto_require);
}
}
}

// load artifacts from PSR-4 directories
if (isset($data['artifact']['psr-4']) && is_assoc_array($data['artifact']['psr-4'])) {
foreach ($data['artifact']['psr-4'] as $namespace => $path) {
$path = FileSystem::fullpath($path, dirname($registry_file));
ArtifactLoader::loadFromPsr4Dir($path, $namespace, $auto_require);
// load artifacts from specific classes
// Supports both array format ["ClassName"] and map format {"ClassName": "path/to/file.php"}
if (isset($data['artifact']['classes']) && is_array($data['artifact']['classes'])) {
foreach ($data['artifact']['classes'] as $key => $value) {
[$class, $file] = self::parseClassEntry($key, $value);
self::requireClassFile($class, $file, dirname($registry_file), $auto_require);
ArtifactLoader::loadFromClass($class);
}
}
}

// load artifacts from specific classes
// Supports both array format ["ClassName"] and map format {"ClassName": "path/to/file.php"}
if (isset($data['artifact']['classes']) && is_array($data['artifact']['classes'])) {
foreach ($data['artifact']['classes'] as $key => $value) {
[$class, $file] = self::parseClassEntry($key, $value);
self::requireClassFile($class, $file, dirname($registry_file), $auto_require);
ArtifactLoader::loadFromClass($class);
// load additional commands from PSR-4 directories
if (isset($data['command']['psr-4']) && is_assoc_array($data['command']['psr-4'])) {
foreach ($data['command']['psr-4'] as $namespace => $path) {
$path = FileSystem::fullpath($path, dirname($registry_file));
$classes = FileSystem::getClassesPsr4($path, $namespace, auto_require: $auto_require);
$instances = array_map(fn ($x) => new $x(), $classes);
ConsoleApplication::_addAdditionalCommands($instances);
}
}
}

// load additional commands from PSR-4 directories
if (isset($data['command']['psr-4']) && is_assoc_array($data['command']['psr-4'])) {
foreach ($data['command']['psr-4'] as $namespace => $path) {
$path = FileSystem::fullpath($path, dirname($registry_file));
$classes = FileSystem::getClassesPsr4($path, $namespace, auto_require: $auto_require);
$instances = array_map(fn ($x) => new $x(), $classes);
// load additional commands from specific classes
// Supports both array format ["ClassName"] and map format {"ClassName": "path/to/file.php"}
if (isset($data['command']['classes']) && is_array($data['command']['classes'])) {
$instances = [];
foreach ($data['command']['classes'] as $key => $value) {
[$class, $file] = self::parseClassEntry($key, $value);
self::requireClassFile($class, $file, dirname($registry_file), $auto_require);
$instances[] = new $class();
}
ConsoleApplication::_addAdditionalCommands($instances);
}
} catch (FileSystemException $e) {
throw new RegistryException($e->getMessage(), 0, $e);
}

// load additional commands from specific classes
// Supports both array format ["ClassName"] and map format {"ClassName": "path/to/file.php"}
if (isset($data['command']['classes']) && is_array($data['command']['classes'])) {
$instances = [];
foreach ($data['command']['classes'] as $key => $value) {
[$class, $file] = self::parseClassEntry($key, $value);
self::requireClassFile($class, $file, dirname($registry_file), $auto_require);
$instances[] = new $class();
}
ConsoleApplication::_addAdditionalCommands($instances);
}
self::$current_registry_name = null;
}

Expand Down
30 changes: 15 additions & 15 deletions tests/StaticPHP/Config/ArtifactConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function testLoadFromDirThrowsExceptionWhenDirectoryDoesNotExist(): void
$this->expectException(WrongUsageException::class);
$this->expectExceptionMessage('Directory /nonexistent/path does not exist, cannot load artifact config.');

ArtifactConfig::loadFromDir('/nonexistent/path');
ArtifactConfig::loadFromDir('/nonexistent/path', 'test');
}

public function testLoadFromDirWithValidArtifactJson(): void
Expand All @@ -63,7 +63,7 @@ public function testLoadFromDirWithValidArtifactJson(): void

file_put_contents($this->tempDir . '/artifact.json', $artifactContent);

ArtifactConfig::loadFromDir($this->tempDir);
ArtifactConfig::loadFromDir($this->tempDir, 'test');

$config = ArtifactConfig::get('test-artifact');
$this->assertIsArray($config);
Expand All @@ -88,7 +88,7 @@ public function testLoadFromDirWithMultipleArtifactFiles(): void
file_put_contents($this->tempDir . '/artifact.lib.json', $artifact2Content);
file_put_contents($this->tempDir . '/artifact.json', json_encode(['artifact-3' => ['source' => 'custom']]));

ArtifactConfig::loadFromDir($this->tempDir);
ArtifactConfig::loadFromDir($this->tempDir, 'test');

$this->assertNotNull(ArtifactConfig::get('artifact-1'));
$this->assertNotNull(ArtifactConfig::get('artifact-2'));
Expand All @@ -100,7 +100,7 @@ public function testLoadFromFileThrowsExceptionWhenFileCannotBeRead(): void
$this->expectException(WrongUsageException::class);
$this->expectExceptionMessage('Failed to read artifact config file:');

ArtifactConfig::loadFromFile('/nonexistent/file.json');
ArtifactConfig::loadFromFile('/nonexistent/file.json', 'test');
}

public function testLoadFromFileThrowsExceptionWhenJsonIsInvalid(): void
Expand All @@ -111,7 +111,7 @@ public function testLoadFromFileThrowsExceptionWhenJsonIsInvalid(): void
$this->expectException(WrongUsageException::class);
$this->expectExceptionMessage('Invalid JSON format in artifact config file:');

ArtifactConfig::loadFromFile($file);
ArtifactConfig::loadFromFile($file, 'test');
}

public function testLoadFromFileWithValidJson(): void
Expand All @@ -127,7 +127,7 @@ public function testLoadFromFileWithValidJson(): void
]);
file_put_contents($file, $content);

ArtifactConfig::loadFromFile($file);
ArtifactConfig::loadFromFile($file, 'test');

$config = ArtifactConfig::get('my-artifact');
$this->assertIsArray($config);
Expand All @@ -144,7 +144,7 @@ public function testGetAllReturnsAllLoadedArtifacts(): void
]);
file_put_contents($file, $content);

ArtifactConfig::loadFromFile($file);
ArtifactConfig::loadFromFile($file, 'test');

$all = ArtifactConfig::getAll();
$this->assertIsArray($all);
Expand All @@ -170,7 +170,7 @@ public function testGetReturnsConfigWhenArtifactExists(): void
]);
file_put_contents($file, $content);

ArtifactConfig::loadFromFile($file);
ArtifactConfig::loadFromFile($file, 'test');

$config = ArtifactConfig::get('test-artifact');
$this->assertIsArray($config);
Expand All @@ -188,7 +188,7 @@ public function testLoadFromFileWithExpandedUrlInSource(): void
]);
file_put_contents($file, $content);

ArtifactConfig::loadFromFile($file);
ArtifactConfig::loadFromFile($file, 'test');

$config = ArtifactConfig::get('test-artifact');
$this->assertIsArray($config);
Expand All @@ -208,7 +208,7 @@ public function testLoadFromFileWithBinaryCustom(): void
]);
file_put_contents($file, $content);

ArtifactConfig::loadFromFile($file);
ArtifactConfig::loadFromFile($file, 'test');

$config = ArtifactConfig::get('test-artifact');
$this->assertIsArray($config['binary']);
Expand All @@ -228,7 +228,7 @@ public function testLoadFromFileWithBinaryHosted(): void
]);
file_put_contents($file, $content);

ArtifactConfig::loadFromFile($file);
ArtifactConfig::loadFromFile($file, 'test');

$config = ArtifactConfig::get('test-artifact');
$this->assertIsArray($config['binary']);
Expand All @@ -253,7 +253,7 @@ public function testLoadFromFileWithBinaryPlatformSpecific(): void
]);
file_put_contents($file, $content);

ArtifactConfig::loadFromFile($file);
ArtifactConfig::loadFromFile($file, 'test');

$config = ArtifactConfig::get('test-artifact');
$this->assertIsArray($config['binary']);
Expand All @@ -266,7 +266,7 @@ public function testLoadFromFileWithBinaryPlatformSpecific(): void
public function testLoadFromDirWithEmptyDirectory(): void
{
// Empty directory should not throw exception
ArtifactConfig::loadFromDir($this->tempDir);
ArtifactConfig::loadFromDir($this->tempDir, 'test');

$this->assertEquals([], ArtifactConfig::getAll());
}
Expand All @@ -279,8 +279,8 @@ public function testMultipleLoadsAppendConfigs(): void
file_put_contents($file1, json_encode(['art1' => ['source' => 'custom']]));
file_put_contents($file2, json_encode(['art2' => ['source' => 'custom']]));

ArtifactConfig::loadFromFile($file1);
ArtifactConfig::loadFromFile($file2);
ArtifactConfig::loadFromFile($file1, 'test');
ArtifactConfig::loadFromFile($file2, 'test');

$all = ArtifactConfig::getAll();
$this->assertCount(2, $all);
Expand Down
2 changes: 1 addition & 1 deletion tests/StaticPHP/Config/ConfigValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ public function testValidateAndLintPackagesWithAllFieldTypes(): void
public function testValidateAndLintPackagesThrowsExceptionForWrongTypeString(): void
{
$this->expectException(ValidationException::class);
$this->expectExceptionMessage('Package test-pkg [artifact] must be string');
$this->expectExceptionMessage('Package test-pkg [artifact] has invalid type specification');

$data = [
'test-pkg' => [
Expand Down
Loading
Loading