blob: 22598986853832ec8da0ec439345e2f0b9335309 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
<?php
namespace dokuwiki\TreeBuilder;
use dokuwiki\File\PageResolver;
use dokuwiki\TreeBuilder\Node\AbstractNode;
use dokuwiki\TreeBuilder\Node\ExternalLink;
use dokuwiki\TreeBuilder\Node\Top;
use dokuwiki\TreeBuilder\Node\WikiPage;
/**
* A tree builder that generates a tree from a control page
*
* A control page is a wiki page containing a nested list of external and internal links. This builder
* parses the control page and generates a tree of nodes representing the links.
*/
class ControlPageBuilder extends AbstractBuilder
{
/** @var int do not include internal links */
const FLAG_NOINTERNAL = 1;
/** @var int do not include external links */
const FLAG_NOEXTERNAL = 2;
/** @var string */
protected string $controlPage;
/** @var int */
protected int $flags = 0;
/**
* Parse the control page
*
* Check the flag constants on how to influence the behaviour
*
* @param string $controlPage
* @param int $flags
*/
public function __construct(string $controlPage)
{
$this->controlPage = $controlPage;
}
/**
* @inheritdoc
* @todo theoretically it should be possible to also take the recursionDecision into account, even though
* we don't recurse here. Passing the depth would be easy, but actually aborting going deeper is difficult.
*/
public function generate(): void
{
$this->top = new Top();
$instructions = p_cached_instructions(wikiFN($this->controlPage));
if (!$instructions) {
throw new \RuntimeException('No instructions for control page found');
}
$parents = [
0 => $this->top
];
$level = 0;
$resolver = new PageResolver($this->controlPage);
foreach ($instructions as $instruction) {
switch ($instruction[0]) {
case 'listu_open':
$level++; // new list level
break;
case 'listu_close':
// if we had a node on this level, remove it from the parents
if(isset($parents[$level])) {
unset($parents[$level]);
}
$level--; // close list level
break;
case 'internallink':
case 'externallink':
if ($instruction[0] == 'internallink') {
if ($this->flags & self::FLAG_NOINTERNAL) break;
$newpage = new WikiPage(
$resolver->resolveId($instruction[1][0]),
$instruction[1][1]
);
} else {
if ($this->flags & self::FLAG_NOEXTERNAL) break;
$newpage = new ExternalLink(
$instruction[1][0],
$instruction[1][1]
);
}
if($level) {
// remember this page as the parent for this level
$parents[$level] = $newpage;
// parent is the last page on the previous level
// levels may not be evenly distributed, so we need to check the count
$parent = $parents[count($parents) - 2];
} else {
// not in a list, so parent is always the top
$parent = $this->top;
}
$newpage->setParent($parent);
$newpage = $this->applyNodeProcessor($newpage);
if($newpage instanceof AbstractNode) {
$parent->addChild($newpage);
}
break;
}
}
$this->generated = true;
}
}
|