diff --git a/phpunit.xml b/phpunit.xml index 8544648..1db7bd2 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -3,6 +3,7 @@ xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.1/phpunit.xsd" colors="true" bootstrap="vendor/autoload.php" + displayDetailsOnTestsThatTriggerWarnings="true" executionOrder="random" cacheResultFile="var/cache/.phpunit.result.cache" cacheDirectory="var/cache/.phpunit.cache"> diff --git a/src/Exception/RootMissingException.php b/src/Exception/RootMissingException.php index 8aa6f67..acfd797 100644 --- a/src/Exception/RootMissingException.php +++ b/src/Exception/RootMissingException.php @@ -5,11 +5,8 @@ namespace Atoolo\Resource\Exception; /** - * This exception is used when a resource is invalid. This can have the - * following reasons: - * - * - If the resource is syntactically incorrect. - * - If the resource does not contain necessary data. + * Is used by the ResourceHierarchyLoader to indicate that the requested + * data could not be determined because no root element can be resolved. */ class RootMissingException extends \RuntimeException { diff --git a/src/Loader/SiteKitResourceHierarchyLoader.php b/src/Loader/SiteKitResourceHierarchyLoader.php index 75bd761..fdfc876 100644 --- a/src/Loader/SiteKitResourceHierarchyLoader.php +++ b/src/Loader/SiteKitResourceHierarchyLoader.php @@ -43,15 +43,14 @@ public function loadParent(string $location): ?Resource /** * @return Resource[] + * @throws InvalidResourceException if an encountered Resource has no + * parent but is not considered a root. */ public function loadPath(string $location): array { $resource = $this->resourceLoader->load($location); $path = [$resource]; - while (true) { - if ($this->isRoot($resource)) { - break; - } + while (!$this->isRoot($resource)) { $parent = $this->loadPrimaryParentResource($resource); array_unshift($path, $parent); $resource = $parent; @@ -75,6 +74,9 @@ public function loadChildren(string $location): array return $children; } + /** + * @throws InvalidResourceException if no primary parent can be found + */ protected function loadPrimaryParentResource( Resource $resource ): Resource { @@ -114,15 +116,47 @@ protected function getPrimaryParentLocation(Resource $resource): ?string $firstParent = null; foreach ($parentList as $parent) { - if ($firstParent === null) { - $firstParent = $parent; - } + $firstParent ??= $parent; $isPrimary = $parent['isPrimary'] ?? false; - if ($isPrimary) { + if ($isPrimary === true) { + if (!isset($parent['url'])) { + throw new InvalidResourceException( + $resource->getLocation(), + 'primary parent in ' . + 'base.trees.' . $this->treeName . '.parents ' . + 'as no url' + ); + } + if (!is_string($parent['url'])) { + throw new InvalidResourceException( + $resource->getLocation(), + 'url of primary parent in ' . + 'base.trees.' . $this->treeName . '.parents ' . + 'is not a string' + ); + } return $parent['url']; } } + if (!isset($firstParent['url'])) { + throw new InvalidResourceException( + $resource->getLocation(), + 'first parent in ' . + 'base.trees.' . $this->treeName . '.parents ' . + 'has no url' + ); + } + + if (!is_string($firstParent['url'])) { + throw new InvalidResourceException( + $resource->getLocation(), + 'url of first parent in ' . + 'base.trees.' . $this->treeName . '.parents ' . + 'is not a string' + ); + } + return $firstParent['url']; } diff --git a/src/ResourceHierarchyLoader.php b/src/ResourceHierarchyLoader.php index c8b1f9d..1723928 100644 --- a/src/ResourceHierarchyLoader.php +++ b/src/ResourceHierarchyLoader.php @@ -5,22 +5,36 @@ namespace Atoolo\Resource; /** - * The ResourceHierarchyLoader interface defines the method used to load + * The ResourceHierarchyLoader interface defines the methods used to load * resources or nodes whose hierarchical structure is defined in the resources. * For example, the navigation tree. */ interface ResourceHierarchyLoader { + /** + * Determines the root resource via the parent links contained in the + * resource data. + */ public function loadRoot(string $location): Resource; + /** + * Determines the parent resource via the parent links contained in the + * resource data. + */ public function loadParent(string $location): ?Resource; /** + * Determines the path to the root resource via the parent links contained + * in the resource data. + * The array contains the resources starting with the root resource. The + * last element of the array is the resource of the passed `$location` * @return Resource[] */ public function loadPath(string $location): array; /** + * Determines the children resources via the children links contained in the + * resource data. * @return Resource[] */ public function loadChildren(string $location): array; diff --git a/test/Loader/SiteKitLoaderTest.php b/test/Loader/SiteKitLoaderTest.php index 5186f76..f182f16 100644 --- a/test/Loader/SiteKitLoaderTest.php +++ b/test/Loader/SiteKitLoaderTest.php @@ -25,7 +25,7 @@ protected function setUp(): void public function testExists(): void { $exists = $this->loader->exists('validResource.php'); - $this->assertTrue($exists, 'resource should be exists'); + $this->assertTrue($exists, 'resource should exist'); } public function testLoadValidResource(): void diff --git a/test/Loader/SiteKitNavigationHierarchyLoaderTest.php b/test/Loader/SiteKitNavigationHierarchyLoaderTest.php index f61dce2..edc74f2 100644 --- a/test/Loader/SiteKitNavigationHierarchyLoaderTest.php +++ b/test/Loader/SiteKitNavigationHierarchyLoaderTest.php @@ -4,6 +4,7 @@ namespace Atoolo\Resource\Test\Loader; +use Atoolo\Resource\Exception\InvalidResourceException; use Atoolo\Resource\Exception\RootMissingException; use Atoolo\Resource\Loader\SiteKitNavigationHierarchyLoader; use Atoolo\Resource\ResourceLoader; diff --git a/test/Loader/SiteKitResourceHierarchyLoaderTest.php b/test/Loader/SiteKitResourceHierarchyLoaderTest.php index 1fe15df..a122293 100644 --- a/test/Loader/SiteKitResourceHierarchyLoaderTest.php +++ b/test/Loader/SiteKitResourceHierarchyLoaderTest.php @@ -132,4 +132,29 @@ public function testLoadParentWithoutParent(): void $parent = $this->hierarchyLoader->loadParent('/a.php'); $this->assertNull($parent, 'parent should be null'); } + + public function testLoadRootResourcePrimaryParentWithoutUrl(): void + { + $this->expectException(InvalidResourceException::class); + $this->hierarchyLoader->loadParent('/primaryParentWithoutUrl.php'); + } + + public function testLoadRootResourcePrimaryParentWithNonStringUrl(): void + { + $this->expectException(InvalidResourceException::class); + $this->hierarchyLoader->loadParent('/primaryParentWithNonStringUrl.php'); + } + + public function testLoadRootResourceFirstParentWithoutUrl(): void + { + $this->expectException(InvalidResourceException::class); + $this->hierarchyLoader->loadParent('/firstParentWithoutUrl.php'); + } + + public function testLoadRootResourceFirstParentWithNonStringUrl(): void + { + $this->expectException(InvalidResourceException::class); + $this->hierarchyLoader->loadParent('/firstParentWithNonStringUrl.php'); + } + } diff --git a/test/resources/Loader/SiteKitResourceHierarchyLoader/firstParentWithNonStringUrl.php b/test/resources/Loader/SiteKitResourceHierarchyLoader/firstParentWithNonStringUrl.php new file mode 100644 index 0000000..0a0d75c --- /dev/null +++ b/test/resources/Loader/SiteKitResourceHierarchyLoader/firstParentWithNonStringUrl.php @@ -0,0 +1,22 @@ + [ + 'trees' => [ + 'category' => [ + 'parents' => [ + 'a' => [ + 'url' => false + ] + ] + ] + ] + ] + ] +); diff --git a/test/resources/Loader/SiteKitResourceHierarchyLoader/firstParentWithoutUrl.php b/test/resources/Loader/SiteKitResourceHierarchyLoader/firstParentWithoutUrl.php new file mode 100644 index 0000000..4884293 --- /dev/null +++ b/test/resources/Loader/SiteKitResourceHierarchyLoader/firstParentWithoutUrl.php @@ -0,0 +1,21 @@ + [ + 'trees' => [ + 'category' => [ + 'parents' => [ + 'a' => [ + ] + ] + ] + ] + ] + ] +); diff --git a/test/resources/Loader/SiteKitResourceHierarchyLoader/primaryParentWithNonStringUrl.php b/test/resources/Loader/SiteKitResourceHierarchyLoader/primaryParentWithNonStringUrl.php new file mode 100644 index 0000000..de2cf15 --- /dev/null +++ b/test/resources/Loader/SiteKitResourceHierarchyLoader/primaryParentWithNonStringUrl.php @@ -0,0 +1,23 @@ + [ + 'trees' => [ + 'category' => [ + 'parents' => [ + 'a' => [ + 'isPrimary' => true, + 'url' => false + ] + ] + ] + ] + ] + ] +); diff --git a/test/resources/Loader/SiteKitResourceHierarchyLoader/primaryParentWithoutUrl.php b/test/resources/Loader/SiteKitResourceHierarchyLoader/primaryParentWithoutUrl.php new file mode 100644 index 0000000..944640b --- /dev/null +++ b/test/resources/Loader/SiteKitResourceHierarchyLoader/primaryParentWithoutUrl.php @@ -0,0 +1,22 @@ + [ + 'trees' => [ + 'category' => [ + 'parents' => [ + 'a' => [ + 'isPrimary' => true, + ] + ] + ] + ] + ] + ] +);