Skip to content

Commit 74b3ed0

Browse files
committed
[BUGFIX] Handle "dirty" objects.inv.json data
Handle null values as not set, ignore inventory entries that have non-scalar values or null in the URI. Until now those were causing type errors
1 parent 685d793 commit 74b3ed0

File tree

3 files changed

+87
-4
lines changed

3 files changed

+87
-4
lines changed

packages/guides/src/ReferenceResolvers/Interlink/DefaultInventoryLoader.php

+15-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020

2121
use function count;
2222
use function is_array;
23+
use function is_scalar;
24+
use function is_string;
25+
use function sprintf;
2326
use function strval;
2427

2528
final class DefaultInventoryLoader implements InventoryLoader
@@ -46,11 +49,22 @@ public function loadInventoryFromJson(Inventory $inventory, array $json): void
4649
if (is_array($groupArray)) {
4750
foreach ($groupArray as $linkKey => $linkArray) {
4851
if (!is_array($linkArray) || count($linkArray) < 4) {
52+
$this->logger->warning(sprintf('Invalid Inventory entry found. Each entry in array "%s" MUST be an array with at least 4 entries. ', $groupKey));
53+
continue;
54+
}
55+
56+
if (!is_string($linkArray[2])) {
57+
$this->logger->warning(sprintf('Invalid Inventory entry found. Each entry in array "%s" must have a path as third entry.', $groupKey));
58+
continue;
59+
}
60+
61+
if (!is_scalar($linkArray[0] ?? '') || !is_scalar($linkArray[1] ?? '') || !is_scalar($linkArray[3] ?? '')) {
62+
$this->logger->warning(sprintf('Invalid Inventory entry found. Only scalar values are allowed in each entry of array "%s". ', $groupKey));
4963
continue;
5064
}
5165

5266
$reducedLinkKey = $groupAnchorNormalizer->reduceAnchor(strval($linkKey));
53-
$link = new InventoryLink($linkArray[0], $linkArray[1], $linkArray[2], $linkArray[3]);
67+
$link = new InventoryLink(strval($linkArray[0] ?? ''), strval($linkArray[1] ?? ''), $linkArray[2], strval($linkArray[3] ?? '-'));
5468
$group->addLink($reducedLinkKey, $link);
5569
}
5670
}

packages/guides/tests/unit/Interlink/InventoryLoaderTest.php

+18-3
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@
1414
namespace phpDocumentor\Guides\Interlink;
1515

1616
use Generator;
17+
use JsonException;
1718
use phpDocumentor\Guides\Nodes\Inline\CrossReferenceNode;
1819
use phpDocumentor\Guides\Nodes\Inline\DocReferenceNode;
1920
use phpDocumentor\Guides\Nodes\Inline\ReferenceNode;
2021
use phpDocumentor\Guides\ReferenceResolvers\Interlink\DefaultInventoryLoader;
2122
use phpDocumentor\Guides\ReferenceResolvers\Interlink\DefaultInventoryRepository;
2223
use phpDocumentor\Guides\ReferenceResolvers\Interlink\Inventory;
2324
use phpDocumentor\Guides\ReferenceResolvers\Interlink\InventoryLink;
24-
use phpDocumentor\Guides\ReferenceResolvers\Interlink\InventoryRepository;
2525
use phpDocumentor\Guides\ReferenceResolvers\Interlink\JsonLoader;
2626
use phpDocumentor\Guides\ReferenceResolvers\Messages;
2727
use phpDocumentor\Guides\ReferenceResolvers\SluggerAnchorNormalizer;
@@ -42,7 +42,7 @@ final class InventoryLoaderTest extends TestCase
4242
{
4343
private DefaultInventoryLoader $inventoryLoader;
4444
private JsonLoader&MockObject $jsonLoader;
45-
private InventoryRepository $inventoryRepository;
45+
private DefaultInventoryRepository $inventoryRepository;
4646
private RenderContext&MockObject $renderContext;
4747
/** @var array<string, mixed> */
4848
private array $json;
@@ -57,7 +57,13 @@ protected function setUp(): void
5757
);
5858
$this->renderContext = $this->createMock(RenderContext::class);
5959
$this->inventoryRepository = new DefaultInventoryRepository(new SluggerAnchorNormalizer(), $this->inventoryLoader, []);
60-
$jsonString = file_get_contents(__DIR__ . '/fixtures/objects.inv.json');
60+
$this->loadObjectsJsonInv(__DIR__ . '/fixtures/objects.inv.json');
61+
}
62+
63+
/** @throws JsonException */
64+
public function loadObjectsJsonInv(string $filename): void
65+
{
66+
$jsonString = file_get_contents($filename);
6167
assertIsString($jsonString);
6268
$this->json = (array) json_decode($jsonString, true, 512, JSON_THROW_ON_ERROR);
6369
$inventory = new Inventory('https://example.com/', new SluggerAnchorNormalizer());
@@ -83,6 +89,15 @@ public function testInventoryIsLoadedExactlyOnce(): void
8389
self::assertGreaterThan(1, count($inventory->getGroups()));
8490
}
8591

92+
public function testInventoryLoaderAcceptsNull(): void
93+
{
94+
$this->loadObjectsJsonInv(__DIR__ . '/fixtures/null-in-objects.inv.json');
95+
$node = new DocReferenceNode('SomeDocument', '', 'somekey');
96+
$inventory = $this->inventoryRepository->getInventory($node, $this->renderContext, new Messages());
97+
self::assertTrue($inventory instanceof Inventory);
98+
self::assertGreaterThan(1, count($inventory->getGroups()));
99+
}
100+
86101
#[DataProvider('rawAnchorProvider')]
87102
public function testInventoryContainsLink(string $expected, CrossReferenceNode $node): void
88103
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"std:doc": {
3+
"Index": [
4+
"<project>",
5+
"<version>",
6+
"index.html",
7+
null
8+
],
9+
"Page1": [
10+
null,
11+
"<version>",
12+
"Page1.html",
13+
"-"
14+
],
15+
"Page1/Subpage1": [
16+
"<project>",
17+
null,
18+
"Page1/Subpage1.html",
19+
"-"
20+
],
21+
"Page2/Subpage2": [
22+
"<project>",
23+
"<version>",
24+
null,
25+
"-"
26+
]
27+
},
28+
"std:label": {
29+
"modindex": [
30+
null,
31+
"<version>",
32+
"some_page.html#modindex",
33+
"Module Index"
34+
],
35+
"php-modindex": [
36+
"<project>",
37+
null,
38+
"some_page.html#php-modindex",
39+
"PHP Namespace Index"
40+
],
41+
"php_objectsindex": [
42+
"<project>",
43+
"<version>",
44+
null,
45+
"PHP Objects Index"
46+
],
47+
"php_8-modindex": [
48+
"<project>",
49+
"<version>",
50+
"php-objectsindex.html#php-8-objectsindex",
51+
null
52+
]
53+
}
54+
}

0 commit comments

Comments
 (0)