Passed
Push — master ( cd8ed8...ef1fc1 )
by Andreas
10:21
created

net_nemein_wiki_resolver::resolve_namespaces()   B

Complexity

Conditions 11
Paths 40

Size

Total Lines 51
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 11.0492

Importance

Changes 0
Metric Value
cc 11
eloc 27
nc 40
nop 5
dl 0
loc 51
ccs 25
cts 27
cp 0.9259
crap 11.0492
rs 7.3166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @package net.nemein.wiki
4
 * @author The Midgard Project, http://www.midgard-project.org
5
 * @copyright The Midgard Project, http://www.midgard-project.org
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 */
8
9
/**
10
 * Wikipage resolver
11
 *
12
 * @package net.nemein.wiki
13
 */
14
class net_nemein_wiki_resolver
15
{
16
    /**
17
     * The topic ID we're starting from
18
     *
19
     * @var int
20
     */
21
    private $_topic;
22
23 3
    public function __construct($topic)
24
    {
25 3
        $this->_topic = $topic;
26
    }
27
28
    public function generate_page_url(net_nemein_wiki_wikipage $wikipage) : ?string
29
    {
30
        $nap = new midcom_helper_nav();
31
        $node = $nap->get_node($wikipage->topic);
32
        if (!$node) {
33
            return null;
34
        }
35
36
        if ($wikipage->name == 'index') {
37
            return $node[MIDCOM_NAV_FULLURL];
38
        }
39
40
        return "{$node[MIDCOM_NAV_FULLURL]}{$wikipage->name}/";
41
    }
42
43 1
    private function _list_wiki_nodes($node, string $prefix = '') : array
44
    {
45
        static $nap = null;
46 1
        if ($nap === null) {
47 1
            $nap = new midcom_helper_nav();
48
        }
49
50 1
        $nodes = [];
51
52 1
        if ($prefix == '') {
53
            // This is the root node
54 1
            $node_identifier = '';
55 1
            $nodes['/'] = $node;
56
        } else {
57 1
            $node_identifier = $prefix . trim($node[MIDCOM_NAV_URL], '/');
58 1
            $nodes[$node_identifier] = $node;
59
        }
60
61
        // Load subnodes uncached, since one may have just been added (by the create handler)
62 1
        $mc = midcom_db_topic::new_collector('up', $node[MIDCOM_NAV_ID]);
63 1
        $mc->add_constraint('component', '=', 'net.nemein.wiki');
64 1
        $subnodes = $mc->get_values('id');
65
66 1
        foreach ($subnodes as $node_id) {
67 1
            $subnode = $nap->get_node($node_id);
68 1
            if ($subnode[MIDCOM_NAV_COMPONENT] == 'net.nemein.wiki') {
69 1
                $subnode_children = $this->_list_wiki_nodes($subnode, "{$node_identifier}/");
70 1
                $nodes = array_merge($nodes, $subnode_children);
71
            }
72
        }
73
74 1
        return $nodes;
75
    }
76
77
    /**
78
     * Traverse hierarchy of wiki folders or "name spaces" to figure out
79
     * if a page exists
80
     *
81
     * @return array containing midcom_db_topic and net_nemein_wiki_wikipage objects if found
82
     */
83 3
    public function path_to_wikipage(string $path, bool $force_resolve_folder_tree = false, bool $force_as_root = false) : array
84
    {
85 3
        $matches = [
86
            'wikipage' => null,
87
            'folder' => null,
88
            'latest_parent' => null,
89
            'remaining_path' => $path,
90
        ];
91
92 3
        $levels = explode('/', $path);
93 3
        $path = implode('/', array_map([midcom_helper_misc::class, 'urlize'], $levels));
94
95 3
        midcom::get()->auth->request_sudo('net.nemein.wiki');
96 3
        if (count($levels) == 1) {
97
            // The linked page is in same namespace
98 2
            $nap = new midcom_helper_nav();
99 2
            $folder = $nap->get_node($this->_topic);
100
        } else {
101 1
            $folder = $this->resolve_namespaces($path, $matches, $levels, $force_resolve_folder_tree, $force_as_root);
102
        }
103
104 3
        if ($folder) {
105
            // Check if the wikipage exists
106 3
            $qb = net_nemein_wiki_wikipage::new_query_builder();
107 3
            $qb->add_constraint('name', '=', basename($path));
108 3
            $qb->add_constraint('topic', '=', $folder[MIDCOM_NAV_ID]);
109 3
            $wikipages = $qb->execute();
110 3
            if (count($wikipages) == 1) {
111
                $matches['wikipage'] = $wikipages[0];
112
            } else {
113
                // No page found, go to create
114 3
                $matches['folder'] = $folder;
115
            }
116
        }
117 3
        midcom::get()->auth->drop_sudo();
118
119 3
        return $matches;
120
    }
121
122 1
    private function resolve_namespaces(string $path, array &$matches, array $levels, bool $force_resolve_folder_tree, bool $force_as_root) : ?array
123
    {
124
        /* We store the Wiki folder hierarchy in a static array
125
         that is populated only once, and even then only the
126
         first time we encounter a namespaced wikilink */
127 1
        static $folder_tree = [];
128 1
        if (empty($folder_tree) || $force_resolve_folder_tree) {
129 1
            $folder_tree = $this->_resolve_folder_tree($force_as_root);
130
        }
131
132 1
        if ($path[0] != '/') {
133
            // This is a relative path, expand to full path
134 1
            foreach ($folder_tree as $prefix => $folder) {
135 1
                if ($folder[MIDCOM_NAV_ID] == $this->_topic) {
136 1
                    $path = "{$prefix}{$path}";
137 1
                    break;
138
                }
139
            }
140
        }
141
142 1
        if (array_key_exists($path, $folder_tree)) {
143
            // This is a direct link to a folder, return the index article
144
            $matches['remaining_path'] = 'index';
145
            return $folder_tree[$path];
146
        }
147
148
        // Resolve topic from path
149 1
        $directory = dirname($path);
150 1
        if (!array_key_exists($directory, $folder_tree)) {
151
            // Wiki folder is missing, go to create
152
153
            // Walk path downwards to locate latest parent
154 1
            $localpath = $path;
155 1
            $matches['latest_parent'] = $folder_tree['/'];
156 1
            $missing_levels = 0;
157 1
            while (   $localpath
158
                   && $localpath != '/') {
159 1
                $localpath = dirname($localpath);
160 1
                $missing_levels++;
161
162 1
                if (array_key_exists($localpath, $folder_tree)) {
163 1
                    $matches['latest_parent'] = $folder_tree[$localpath];
164 1
                    $matches['remaining_path'] = implode('/', array_slice($levels, -$missing_levels));
165 1
                    break;
166
                }
167
            }
168 1
            return null;
169
        }
170
171 1
        $matches['remaining_path'] = substr($path, strlen($directory) + 1);
172 1
        return $folder_tree[$directory];
173
    }
174
175 1
    private function _resolve_folder_tree(bool $force_as_root) : array
176
    {
177 1
        $nap = new midcom_helper_nav();
178
179
        // Traverse the NAP tree upwards until we get the root-most wiki folder
180 1
        $folder = $nap->get_node($this->_topic);
181
182 1
        $root_folder = $folder;
183 1
        $max = 100;
184 1
        while (   $folder[MIDCOM_NAV_COMPONENT] == 'net.nemein.wiki'
185 1
               && (($parent = $nap->get_node_uplink($folder[MIDCOM_NAV_ID])) != -1)
186
               && $max > 0) {
187
            $root_folder = $folder;
188
            if ($force_as_root) {
189
                break;
190
            }
191
            $folder = $nap->get_node($parent);
192
            $max--;
193
        }
194
195 1
        return $this->_list_wiki_nodes($root_folder);
196
    }
197
}
198