diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 8b092b3..ade9b06 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -82,7 +82,7 @@ jobs: run: composer-require-checker check --config-file=tools/composer-require-checker.json composer.json - name: Check code for unused dependencies in composer.json - run: composer-unused + run: composer-unused --excludePackage=simplesamlphp/composer-xmlprovider-installer - name: PHP Code Sniffer run: phpcs diff --git a/composer.json b/composer.json index b60c64c..abf7e51 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "simplesamlphp/xml-common", "description": "A library with classes and utilities for handling XML structures.", - "type": "project", + "type": "simplesamlphp-xmlprovider", "keywords": ["saml", "xml"], "homepage": "http://simplesamlphp.org", "license": "LGPL-2.1-or-later", @@ -34,7 +34,9 @@ "ext-spl": "*", "ext-xmlreader": "*", - "simplesamlphp/assert": "^1.2" + "simplesamlphp/assert": "^1.2", + "simplesamlphp/composer-xmlprovider-installer": "dev-master", + "symfony/finder": "^6.4" }, "require-dev": { "simplesamlphp/simplesamlphp-test-framework": "^1.7" @@ -47,7 +49,8 @@ "allow-plugins": { "composer/package-versions-deprecated": true, "dealerdirect/phpcodesniffer-composer-installer": true, - "phpstan/extension-installer": true + "phpstan/extension-installer": true, + "simplesamlphp/composer-xmlprovider-installer": true } } } diff --git a/src/Registry/ElementRegistry.php b/src/Registry/ElementRegistry.php new file mode 100644 index 0000000..9bb707a --- /dev/null +++ b/src/Registry/ElementRegistry.php @@ -0,0 +1,97 @@ +> */ + private array $registry = []; + + + private function __construct() + { + // Initialize the registry with all the elements we know + $classesDir = dirname(__FILE__, 6) . '/vendor/simplesamlphp/composer-xmlprovider-installer/classes'; + + if (file_exists($classesDir) === true) { + $finder = Finder::create()->files()->name('element.registry.*.php')->in($classesDir); + if ($finder->hasResults()) { + foreach ($finder as $file) { + $this->importFromFile($file->getPathName()); + } + } + } + } + + + public function importFromFile(string $file): void + { + if (file_exists($file) === true) { + $elements = include($file); + $this->registry = array_merge_recursive($this->registry, $elements); + } else { + throw new IOException('File not found.'); + } + } + + + public static function getInstance(): ElementRegistry + { + if (self::$instance === null) { + self::$instance = new static(); + } + + return self::$instance; + } + + + /** + * Register a class that can process a certain XML-element. + * + * @param string $class The class name of a class extending AbstractElement. + */ + public function registerElementHandler(string $class): void + { + Assert::subclassOf($class, AbstractElement::class); + $className = AbstractElement::getClassName($class); + $namespace = $class::NS; + + $this->registry[$namespace][$className] = $class; + } + + + /** + * Search for a class that implements an $element in the given $namespace. + * + * Such classes must have been registered previously by calling registerElementHandler(), and they must + * extend \SimpleSAML\XML\AbstractElement. + * + * @param string|null $namespace The namespace URI for the given element. + * @param string $element The local name of the element. + * + * @return string|null The fully-qualified name of a class extending \SimpleSAML\XML\AbstractElement and + * implementing support for the given element, or null if no such class has been registered before. + */ + public function getElementHandler(?string $namespace, string $element): ?string + { + Assert::nullOrValidURI($namespace, InvalidDOMElementException::class); + Assert::validNCName($element, InvalidDOMElementException::class); + + return $this->registry[$namespace][$element] ?? null; + } +} diff --git a/tests/Registry/ElementRegistryTest.php b/tests/Registry/ElementRegistryTest.php new file mode 100644 index 0000000..f38acf3 --- /dev/null +++ b/tests/Registry/ElementRegistryTest.php @@ -0,0 +1,58 @@ +registerElementHandler('\SimpleSAML\Test\XML\Element'); + } + + + /** + */ + public function testFetchingHandlerWorks(): void + { + $handler = self::$registry->getElementHandler('urn:x-simplesamlphp:namespace', 'Element'); + $this->assertEquals($handler, '\SimpleSAML\Test\XML\Element'); + } + + + /** + */ + public function testAddingHandlerWorks(): void + { + self::$registry->registerElementHandler('\SimpleSAML\Test\XML\ExtendableElement'); + $handler = self::$registry->getElementHandler('urn:x-simplesamlphp:namespace', 'ExtendableElement'); + $this->assertEquals($handler, '\SimpleSAML\Test\XML\ExtendableElement'); + } + + + /** + */ + public function testUnknownHandlerReturnsNull(): void + { + $handler = self::$registry->getElementHandler('urn:x-simplesamlphp:namespace', 'UnknownElement'); + $this->assertNull($handler); + } +}