Passed
Push — master ( 92128b...d5c2c1 )
by Andreas
17:19
created

net_nemein_wiki_handler_view::_on_initialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
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
use midcom\datamanager\datamanager;
10
use Symfony\Component\HttpFoundation\Request;
11
12
/**
13
 * Wikipage view handler
14
 *
15
 * @package net.nemein.wiki
16
 */
17
class net_nemein_wiki_handler_view extends midcom_baseclasses_components_handler
18
{
19
    use net_nemein_wiki_handler;
0 ignored issues
show
introduced by
The trait net_nemein_wiki_handler requires some properties which are not provided by net_nemein_wiki_handler_view: $id, $extra
Loading history...
20
21
    /**
22
     * The wikipage we're viewing
23
     *
24
     * @var net_nemein_wiki_wikipage
25
     */
26
    private $_page;
27
28
    /**
29
     * The Datamanager for article to display
30
     *
31
     * @var datamanager
32
     */
33
    private $_datamanager;
34
35
    /**
36
     * Internal helper, loads the datamanager for the current wikipage. Any error triggers a 500.
37
     */
38 4
    private function _load_datamanager()
39
    {
40 4
        $this->_datamanager = datamanager::from_schemadb($this->_config->get('schemadb'))
0 ignored issues
show
Bug introduced by
It seems like $this->_config->get('schemadb') can also be of type false; however, parameter $path of midcom\datamanager\datamanager::from_schemadb() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

40
        $this->_datamanager = datamanager::from_schemadb(/** @scrutinizer ignore-type */ $this->_config->get('schemadb'))
Loading history...
41 4
            ->set_storage($this->_page);
42 4
    }
43
44 3
    private function _populate_toolbar()
45
    {
46 3
        $workflow = $this->get_workflow('datamanager');
47
        $buttons = [
48
            [
49 3
                MIDCOM_TOOLBAR_URL => "{$this->_page->name}/",
50 3
                MIDCOM_TOOLBAR_LABEL => $this->_l10n_midcom->get('view'),
51 3
                MIDCOM_TOOLBAR_GLYPHICON => 'search',
52 3
                MIDCOM_TOOLBAR_ACCESSKEY => 'v',
53
            ],
54 3
            $workflow->get_button("edit/{$this->_page->name}/", [
55 3
                MIDCOM_TOOLBAR_ACCESSKEY => 'e',
56 3
                MIDCOM_TOOLBAR_ENABLED => $this->_page->can_do('midgard:update'),
57
            ])
58
        ];
59 3
        if ($this->_page->can_do('midgard:delete')) {
60 1
            $workflow = $this->get_workflow('delete', ['object' => $this->_page]);
61 1
            $buttons[] = $workflow->get_button("delete/{$this->_page->name}/");
62
        }
63
64 3
        $buttons[] = [
65 3
            MIDCOM_TOOLBAR_URL => "whatlinks/{$this->_page->name}/",
66 3
            MIDCOM_TOOLBAR_LABEL => $this->_l10n->get('what links'),
67 3
            MIDCOM_TOOLBAR_GLYPHICON => 'link',
68
        ];
69
70 3
        if (midcom::get()->auth->user) {
71
            $user = midcom::get()->auth->user->get_storage();
72
            if ($this->_page->get_parameter('net.nemein.wiki:watch', $user->guid)) {
73
                $action = 'unsubscribe';
74
            } else {
75
                $action = 'subscribe';
76
            }
77
            $buttons[] = [
78
                MIDCOM_TOOLBAR_URL => "subscribe/{$this->_page->name}/",
79
                MIDCOM_TOOLBAR_LABEL => $this->_l10n->get($action),
80
                MIDCOM_TOOLBAR_GLYPHICON => 'envelope-o',
81
                MIDCOM_TOOLBAR_POST => true,
82
                MIDCOM_TOOLBAR_POST_HIDDENARGS => [$action => 1],
83
            ];
84
        }
85
86 3
        if ($this->_page->can_do('midgard:update')) {
87 1
            midcom::get()->head->add_link_head([
88 1
                'rel' => 'alternate',
89 1
                'type' => 'application/x-wiki',
90 1
                'title' => $this->_l10n_midcom->get('edit'),
91 1
                'href' => $this->router->generate('edit', ['wikipage' => $this->_page->name]),
92
            ]);
93
        }
94 3
        $this->_view_toolbar->add_items($buttons);
95 3
        org_openpsa_relatedto_plugin::add_button($this->_view_toolbar, $this->_page->guid);
96
97 3
        $this->bind_view_to_object($this->_page, $this->_datamanager->get_schema()->get_name());
98 3
    }
99
100 5
    private function _load_page(string $wikiword, bool $autocreate = true)
101
    {
102 5
        $qb = net_nemein_wiki_wikipage::new_query_builder();
103 5
        $qb->add_constraint('topic', '=', $this->_topic->id);
104 5
        $qb->add_constraint('name', '=', $wikiword);
105 5
        midcom::get()->auth->request_sudo($this->_component);
106 5
        $result = $qb->execute();
107 5
        midcom::get()->auth->drop_sudo();
108 5
        if (!empty($result)) {
109 4
            $this->_page = $result[0];
110 4
            $this->_page->require_do('midgard:read');
111 4
            return;
112
        }
113
114 1
        if ($wikiword == 'index') {
115
            // Autoinitialize
116 1
            $this->_topic->require_do('midgard:create');
117 1
            $this->_page = $this->initialize_index_article($this->_topic);
118 1
            return;
119
        }
120
121
        $urlized_wikiword = midcom_helper_misc::urlize($wikiword);
122
        if ($urlized_wikiword != $wikiword) {
123
            // Lets see if the page for the wikiword exists
124
            $qb = net_nemein_wiki_wikipage::new_query_builder();
125
            $qb->add_constraint('topic', '=', $this->_topic->id);
126
            $qb->add_constraint('title', '=', $wikiword);
127
            $result = $qb->execute();
128
            if (!empty($result)) {
129
                // This wiki page actually exists, so go there as "Permanent Redirect"
130
                return new midcom_response_relocate($this->router->generate('view', ['wikipage' => $result[0]->name]), 301);
131
            }
132
        }
133
        if ($autocreate) {
134
            return new midcom_response_relocate($this->router->generate('notfound', ['wikiword' => rawurlencode($wikiword)]));
135
        }
136
        throw new midcom_error_notfound('The page ' . $wikiword . ' could not be found.');
137
    }
138
139 2
    public function _handler_view(array &$data, string $wikipage = 'index')
140
    {
141 2
        if ($response = $this->_load_page($wikipage)) {
142
            return $response;
143
        }
144 2
        $this->_load_datamanager();
145
146 2
        if ($this->_datamanager->get_schema()->get_name() == 'redirect') {
147
            $qb = net_nemein_wiki_wikipage::new_query_builder();
148
            $qb->add_constraint('topic.component', '=', 'net.nemein.wiki');
149
            $qb->add_constraint('name', '=', $this->_page->url);
150
            $result = $qb->execute();
151
            if (empty($result)) {
152
                // No matching redirection page found, relocate to editing
153
                // TODO: Add UI message
154
                return new midcom_response_relocate("edit/{$this->_page->name}/");
155
            }
156
157
            if ($result[0]->topic == $this->_topic->id) {
158
                return new midcom_response_relocate("{$result[0]->name}/");
159
            }
160
            return new midcom_response_relocate(midcom::get()->permalinks->create_permalink($result[0]->guid));
161
        }
162
163 2
        $this->_populate_toolbar();
164 2
        $this->_view_toolbar->hide_item("{$this->_page->name}/");
165
166 2
        if ($this->_page->name != 'index') {
167 1
            $this->add_breadcrumb("{$this->_page->name}/", $this->_page->title);
168
        }
169
170 2
        midcom::get()->head->set_pagetitle($this->_page->title);
171 2
        midcom::get()->metadata->set_request_metadata($this->_page->metadata->revised, $this->_page->guid);
172
173 2
        $data['wikipage_view'] = $this->_datamanager->get_content_html();
174 2
        $data['wikipage'] = $this->_page;
175
176
        // Replace wikiwords
177 2
        $parser = new net_nemein_wiki_parser($this->_page);
178 2
        $data['wikipage_view']['content'] = $parser->get_markdown($data['wikipage_view']['content']);
179 2
        if ($this->_config->get('autogenerate_toc')) {
180 2
            $data['wikipage_view']['content'] = $this->_autogenerate_toc($data['wikipage_view']['content']);
181
        }
182
183 2
        return $this->show('view-wikipage');
184
    }
185
186
    /**
187
     * Parse HTML content and look for header tags, making index of them.
188
     *
189
     * It looks for all H<num> tags and converts them to named
190
     * anchors, and prepends a list of links to them to the start of HTML.
191
     */
192 2
    private function _autogenerate_toc(string $content) : string
193
    {
194 2
        if (!preg_match_all("/(<(h([1-9][0-9]*))[^>]*?>)(.*?)(<\/\\2>)/i", $content, $headings)) {
195 2
            return $content;
196
        }
197
198
        $toc = '';
199
200
        $current_tag_level = false;
201
        $current_list_level = 1;
202
        $toc .= "\n<ol class=\"midcom_helper_toc_formatter level_{$current_list_level}\">\n";
203
        foreach ($headings[4] as $key => $heading) {
204
            $anchor = 'heading-' . md5($heading);
205
            $tag_level =& $headings[3][$key];
206
            $heading_code =& $headings[0][$key];
207
            $heading_tag =& $headings[2][$key];
208
            $heading_new_code = "<a id='{$anchor}'></a>{$heading_code}";
209
            $content = str_replace($heading_code, $heading_new_code, $content);
210
            if ($current_tag_level === false) {
211
                $current_tag_level = $tag_level;
212
            } elseif ($current_tag_level == $tag_level) {
213
                $toc .= "</li>\n";
214
            } elseif ($tag_level > $current_tag_level) {
215
                for ($i = $current_tag_level; $i < $tag_level; $i++) {
216
                    $current_tag_level = $tag_level;
217
                    $current_list_level++;
218
                    $toc .= "<ol class=\"level_{$current_list_level}\">\n";
219
                    if ($tag_level > $i + 1) {
220
                        $toc .= "<li>\n";
221
                    }
222
                }
223
            } else {
224
                for ($i = $current_tag_level; $i > $tag_level; $i--) {
225
                    $toc .= "</li>\n";
226
                    $current_tag_level = $tag_level;
227
                    if ($current_list_level > 1) {
228
                        $current_list_level--;
229
                        $toc .= "</ol>\n";
230
                    }
231
                }
232
            }
233
            $toc .= "<li class='{$heading_tag}'><a href='#{$anchor}'>" . strip_tags($heading) . "</a>";
234
        }
235
        $toc .= str_repeat("</li>\n</ol>\n", $current_list_level);
236
237
        return $toc . $content;
238
    }
239
240 1
    public function _handler_raw(string $wikipage, array &$data)
241
    {
242 1
        if ($response = $this->_load_page($wikipage, false)) {
243
            return $response;
244
        }
245 1
        midcom::get()->skip_page_style = true;
246 1
        $this->_load_datamanager();
247
248 1
        $data['wikipage_view'] = $this->_datamanager->get_content_html();
249
250
        // Replace wikiwords
251 1
        $parser = new net_nemein_wiki_parser($this->_page);
252 1
        $data['wikipage_view']['content'] = $parser->get_markdown($data['wikipage_view']['content']);
253
254 1
        return $this->show('view-wikipage-raw');
255
    }
256
257 1
    public function _handler_subscribe(Request $request, string $wikipage)
258
    {
259 1
        midcom::get()->auth->require_valid_user();
260
261 1
        if ($response = $this->_load_page($wikipage, false)) {
262
            return $response;
263
        }
264
265 1
        midcom::get()->auth->request_sudo('net.nemein.wiki');
266
267 1
        $user = midcom::get()->auth->user->get_storage();
268
269 1
        if ($request->request->get('target') == 'folder') {
270
            // We're subscribing to the whole wiki
271
            $object = $this->_topic;
272
            $target = sprintf($this->_l10n->get('whole wiki %s'), $this->_topic->extra);
273
        } else {
274 1
            $object = $this->_page;
275 1
            $target = sprintf($this->_l10n->get('page %s'), $this->_page->title);
276
        }
277
278 1
        if ($request->request->has('subscribe')) {
279
            // Subscribe to page
280 1
            $object->set_parameter('net.nemein.wiki:watch', $user->guid, time());
281 1
            midcom::get()->uimessages->add($this->_l10n->get($this->_component), sprintf($this->_l10n->get('subscribed to changes in %s'), $target));
282
        } else {
283
            // Remove subscription
284
            $object->delete_parameter('net.nemein.wiki:watch', $user->guid);
285
            midcom::get()->uimessages->add($this->_l10n->get($this->_component), sprintf($this->_l10n->get('unsubscribed from changes in %s'), $target));
286
        }
287
288 1
        midcom::get()->auth->drop_sudo();
289
290
        // Redirect to editing
291 1
        if ($this->_page->name == 'index') {
292
            return new midcom_response_relocate("");
293
        }
294 1
        return new midcom_response_relocate("{$this->_page->name}/");
295
    }
296
297 1
    public function _handler_whatlinks(string $wikipage, array &$data)
298
    {
299 1
        if ($response = $this->_load_page($wikipage, false)) {
300
            return $response;
301
        }
302
303 1
        $this->_load_datamanager();
304
305 1
        $this->_populate_toolbar();
306 1
        $this->_view_toolbar->hide_item("whatlinks/{$this->_page->name}/");
307 1
        $this->add_breadcrumb("{$this->_page->name}/", $this->_page->title);
308
309 1
        $qb = net_nemein_wiki_link_dba::new_query_builder();
310 1
        $qb->add_constraint('topage', '=', $this->_page->title);
311 1
        $data['wikilinks'] = $qb->execute();
312 1
        $data['wikipage_view'] = $this->_datamanager->get_content_html();
313
314
        // Replace wikiwords
315 1
        $parser = new net_nemein_wiki_parser($this->_page);
316 1
        $data['wikipage_view']['content'] = $parser->get_markdown($data['wikipage_view']['content']);
317
318 1
        return $this->show('view-wikipage-whatlinks');
319
    }
320
321
    /**
322
     * Callback for sorting wikipages by title
323
     */
324
    public static function sort_by_title(net_nemein_wiki_wikipage $a, net_nemein_wiki_wikipage $b)
325
    {
326
        return strnatcmp($a->title, $b->title);
327
    }
328
}
329