Skip to content

Commit 7a39166

Browse files
committed
Fix GH-177: Extract JSON index logic into dedicated JsonIndex class
Move processJsonIndex(), processCombinedJsonIndex(), and findParentBookOrSet() out of Package_PHP_Web into a new JsonIndex class so the logic can be unit-tested independently.
1 parent e012bdf commit 7a39166

5 files changed

Lines changed: 641 additions & 134 deletions

File tree

‎phpdotnet/phd/JsonIndex.php‎

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
namespace phpdotnet\phd;
3+
4+
class JsonIndex
5+
{
6+
private const array ALWAYS_INCLUDE_ELEMENTS = [
7+
'refentry',
8+
'stream_wrapper',
9+
'phpdoc:classref',
10+
'phpdoc:exceptionref',
11+
'phpdoc:varentry',
12+
];
13+
14+
public function __construct(
15+
private readonly array $indexes,
16+
private readonly array $indexesWithDuplicates,
17+
) {}
18+
19+
/**
20+
* Processes the index to extract entries and descriptions. These are
21+
* used to generate the search index and the descriptions JSON files.
22+
*/
23+
public function processJsonIndex(): array
24+
{
25+
$entries = [];
26+
$descriptions = [];
27+
foreach ($this->indexes as $id => $index) {
28+
if (
29+
(! $index['chunk'])
30+
&& (! in_array($index['element'], self::ALWAYS_INCLUDE_ELEMENTS, true))
31+
) {
32+
continue;
33+
}
34+
35+
if ($index["sdesc"] === "" && $index["ldesc"] !== "") {
36+
$index["sdesc"] = $index["ldesc"];
37+
$bookOrSet = $this->findParentBookOrSet($index['parent_id']);
38+
if ($bookOrSet) {
39+
$index["ldesc"] = $this->getLongDescription(
40+
$bookOrSet['docbook_id']
41+
);
42+
}
43+
}
44+
45+
$entries[] = [
46+
$index["sdesc"], $index["filename"], $index["element"]
47+
];
48+
$descriptions[$id] = html_entity_decode($index["ldesc"]);
49+
}
50+
return [$entries, $descriptions];
51+
}
52+
53+
public function processCombinedJsonIndex(): array
54+
{
55+
$entries = [];
56+
foreach ($this->indexesWithDuplicates as $index) {
57+
if (
58+
(! $index['chunk'])
59+
&& (! in_array($index['element'], self::ALWAYS_INCLUDE_ELEMENTS, true))
60+
) {
61+
continue;
62+
}
63+
64+
if ($index["sdesc"] === "" && $index["ldesc"] !== "") {
65+
$index["sdesc"] = $index["ldesc"];
66+
$bookOrSet = $this->findParentBookOrSet($index['parent_id']);
67+
if ($bookOrSet) {
68+
$index["ldesc"] = $this->getLongDescription(
69+
$bookOrSet['docbook_id']
70+
);
71+
}
72+
}
73+
74+
$nameParts = explode('::', $index['sdesc']);
75+
$methodName = array_pop($nameParts);
76+
77+
$type = match ($index['element']) {
78+
'phpdoc:varentry' => 'Variable',
79+
'refentry' => 'Function',
80+
'phpdoc:exceptionref' => 'Exception',
81+
'phpdoc:classref' => 'Class',
82+
'set', 'book', 'reference' => 'Extension',
83+
default => 'General',
84+
};
85+
86+
$entries[] = [
87+
'id' => $index['filename'],
88+
'name' => $index['sdesc'],
89+
'description' => html_entity_decode($index['ldesc']),
90+
'tag' => $index['element'],
91+
'type' => $type,
92+
'methodName' => $methodName,
93+
];
94+
}
95+
return $entries;
96+
}
97+
98+
/**
99+
* Finds the closest parent book or set in the index hierarchy.
100+
*/
101+
public function findParentBookOrSet(string $id): ?array
102+
{
103+
// array_key_exists() to guard against undefined array keys, either for
104+
// root elements (no parent) or in case the index structure is broken.
105+
while (array_key_exists($id, $this->indexes)) {
106+
$parent = $this->indexes[$id];
107+
$element = $parent['element'];
108+
109+
if ($element === 'book' || $element === 'set') {
110+
return $parent;
111+
}
112+
113+
$id = $parent['parent_id'];
114+
}
115+
116+
return null;
117+
}
118+
119+
private function getLongDescription(string $id): string
120+
{
121+
if ($this->indexes[$id]["ldesc"]) {
122+
return $this->indexes[$id]["ldesc"];
123+
}
124+
return $this->indexes[$id]["sdesc"];
125+
}
126+
}

‎phpdotnet/phd/Package/PHP/Web.php‎

Lines changed: 8 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,13 @@ public function footer($id) {
246246

247247
protected function writeJsonIndex() {
248248
$this->outputHandler->v("Writing search indexes..", VERBOSE_FORMAT_RENDERING);
249-
[$entries, $descriptions] = $this->processJsonIndex();
249+
250+
$jsonIndex = new JsonIndex(
251+
$this->indexes,
252+
$this->indexRepository->getIndexesWithDuplicates(),
253+
);
254+
255+
[$entries, $descriptions] = $jsonIndex->processJsonIndex();
250256
file_put_contents(
251257
$this->getOutputDir() . "search-index.json",
252258
json_encode($entries)
@@ -257,7 +263,7 @@ protected function writeJsonIndex() {
257263
);
258264
$this->outputHandler->v("Index written", VERBOSE_FORMAT_RENDERING);
259265

260-
$entries = $this->processCombinedJsonIndex();
266+
$entries = $jsonIndex->processCombinedJsonIndex();
261267
file_put_contents(
262268
$this->getOutputDir() . "search-combined.json",
263269
json_encode($entries)
@@ -270,138 +276,6 @@ protected function writeJsonIndex() {
270276
$this->outputHandler->v("Combined Index written", VERBOSE_FORMAT_RENDERING);
271277
}
272278

273-
/**
274-
* Processes the index to extract entries and descriptions. These are
275-
* used to generate the search index and the descriptions JSON files.
276-
*/
277-
private function processJsonIndex(): array {
278-
$alwaysIncludeElements = [
279-
'refentry',
280-
'stream_wrapper',
281-
'phpdoc:classref',
282-
'phpdoc:exceptionref',
283-
'phpdoc:varentry',
284-
];
285-
286-
$entries = [];
287-
$descriptions = [];
288-
foreach($this->indexes as $id => $index) {
289-
if (
290-
(! $index['chunk'])
291-
&& (! in_array($index['element'], $alwaysIncludeElements, true))
292-
) {
293-
continue;
294-
}
295-
296-
if ($index["sdesc"] === "" && $index["ldesc"] !== "") {
297-
$index["sdesc"] = $index["ldesc"];
298-
$bookOrSet = $this->findParentBookOrSet($index['parent_id']);
299-
if ($bookOrSet) {
300-
$index["ldesc"] = Format::getLongDescription(
301-
$bookOrSet['docbook_id']
302-
);
303-
}
304-
}
305-
306-
$entries[] = [
307-
$index["sdesc"], $index["filename"], $index["element"]
308-
];
309-
$descriptions[$id] = html_entity_decode($index["ldesc"]);
310-
}
311-
return [$entries, $descriptions];
312-
}
313-
314-
private function processCombinedJsonIndex(): array
315-
{
316-
$alwaysIncludeElements = [
317-
'refentry',
318-
'stream_wrapper',
319-
'phpdoc:classref',
320-
'phpdoc:exceptionref',
321-
'phpdoc:varentry',
322-
];
323-
324-
$entries = [];
325-
$indexes = $this->indexRepository->getIndexesWithDuplicates();
326-
foreach ($indexes as $index) {
327-
if (
328-
(! $index['chunk'])
329-
&& (! in_array($index['element'], $alwaysIncludeElements, true))
330-
) {
331-
continue;
332-
}
333-
334-
if ($index["sdesc"] === "" && $index["ldesc"] !== "") {
335-
$index["sdesc"] = $index["ldesc"];
336-
$bookOrSet = $this->findParentBookOrSet($index['parent_id']);
337-
if ($bookOrSet) {
338-
$index["ldesc"] = Format::getLongDescription(
339-
$bookOrSet['docbook_id']
340-
);
341-
}
342-
}
343-
344-
$nameParts = explode('::', $index['sdesc']);
345-
$methodName = array_pop($nameParts);
346-
347-
$type = 'General';
348-
switch ($index['element']) {
349-
case "phpdoc:varentry":
350-
$type = "Variable";
351-
break;
352-
353-
case "refentry":
354-
$type = "Function";
355-
break;
356-
357-
case "phpdoc:exceptionref":
358-
$type = "Exception";
359-
break;
360-
361-
case "phpdoc:classref":
362-
$type = "Class";
363-
break;
364-
365-
case "set":
366-
case "book":
367-
case "reference":
368-
$type = "Extension";
369-
break;
370-
}
371-
372-
$entries[] = [
373-
'id' => $index['filename'],
374-
'name' => $index['sdesc'],
375-
'description' => html_entity_decode($index['ldesc']),
376-
'tag' => $index['element'],
377-
'type' => $type,
378-
'methodName' => $methodName,
379-
];
380-
}
381-
return $entries;
382-
}
383-
384-
/**
385-
* Finds the closest parent book or set in the index hierarchy.
386-
*/
387-
private function findParentBookOrSet(string $id): ?array
388-
{
389-
// array_key_exists() to guard against undefined array keys, either for
390-
// root elements (no parent) or in case the index structure is broken.
391-
while (array_key_exists($id, $this->indexes)) {
392-
$parent = $this->indexes[$id];
393-
$element = $parent['element'];
394-
395-
if ($element === 'book' || $element === 'set') {
396-
return $parent;
397-
}
398-
399-
$id = $parent['parent_id'];
400-
}
401-
402-
return null;
403-
}
404-
405279
public function loadSourcesInfo() {
406280
$this->sources = self::generateSourcesInfo($this->config->phpwebSourcesFilename);
407281
}

0 commit comments

Comments
 (0)