xref: /plugin/qc/renderer.php (revision 293182bb8df16cb86ab290c9f83a9605de753704)
1<?php
2
3/**
4 * The Renderer
5 */
6class renderer_plugin_qc extends Doku_Renderer
7{
8    /**
9     * We store all our data in an array
10     */
11    public $docArray = array(
12        // raw statistics
13        'header_count'  => array(0,0,0,0,0,0),
14        'header_struct' => array(),
15        'linebreak'     => 0,
16        'quote_nest'    => 0,
17        'quote_count'   => 0,
18        'fixme'         => 0,
19        'hr'            => 0,
20        'formatted'     => 0,
21
22        'created'       => 0,
23        'modified'      => 0,
24        'changes'       => 0,
25        'authors'       => array(),
26
27        'internal_links' => 0,
28        'broken_links'  => 0,
29        'external_links' => 0,
30        'link_lengths'  => array(),
31
32        'chars'         => 0,
33        'words'         => 0,
34
35        'score'         => 0,
36
37        // calculated error scores
38        'err' => array(
39            'fixme'      => 0,
40            'noh1'       => 0,
41            'manyh1'     => 0,
42            'headernest' => 0,
43            'manyhr'     => 0,
44            'manybr'     => 0,
45            'longformat' => 0,
46            'multiformat' => 0,
47        ),
48    );
49
50    protected $quotelevel = 0;
51    protected $formatting = 0;
52    protected $tableopen  = false;
53
54    public function document_start() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
55    {
56        global $ID;
57        $meta = p_get_metadata($ID);
58
59        // get some dates from meta data
60        $this->docArray['created']  = $meta['date']['created'];
61        $this->docArray['modified'] = $meta['date']['modified'];
62
63        // get author info
64        $changelog = new PageChangelog($ID);
65        $revs = $changelog->getRevisions(0, 10000); //FIXME find a good solution for 'get ALL revisions'
66        array_push($revs, $meta['last_change']['date']);
67        $this->docArray['changes'] = count($revs);
68        foreach ($revs as $rev) {
69            $info = $changelog->getRevisionInfo($rev);
70            if ($info['user']) {
71                $this->docArray['authors'][$info['user']] += 1;
72            } else {
73                $this->docArray['authors']['*'] += 1;
74            }
75        }
76
77        // work on raw text
78        $text = rawWiki($ID);
79        $this->docArray['chars'] = utf8_strlen($text);
80        $this->docArray['words'] = count(array_filter(preg_split('/[^\w\-_]/u', $text)));
81    }
82
83
84    /**
85     * Here the score is calculated
86     */
87    public function document_end() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
88    {
89        global $ID;
90
91        // 2 points for missing backlinks
92        if (!count(ft_backlinks($ID))) {
93            $this->docArray['err']['nobacklink'] += 2;
94        }
95
96        // 1 point for each FIXME
97        $this->docArray['err']['fixme'] += $this->docArray['fixme'];
98
99        // 5 points for missing H1
100        if ($this->docArray['header_count'][1] == 0) {
101            $this->docArray['err']['noh1'] += 5;
102        }
103        // 1 point for each H1 too much
104        if ($this->docArray['header_count'][1] > 1) {
105            $this->docArray['err']['manyh1'] += $this->docArray['header'][1];
106        }
107
108        // 1 point for each incorrectly nested headline
109        $cnt = count($this->docArray['header_struct']);
110        for ($i = 1; $i < $cnt; $i++) {
111            if ($this->docArray['header_struct'][$i] - $this->docArray['header_struct'][$i - 1] > 1) {
112                $this->docArray['err']['headernest'] += 1;
113            }
114        }
115
116        // 1/2 points for deeply nested quotations
117        if ($this->docArray['quote_nest'] > 2) {
118            $this->docArray['err']['deepquote'] += $this->docArray['quote_nest'] / 2;
119        }
120
121        // FIXME points for many quotes?
122
123        // 1/2 points for too many hr
124        if ($this->docArray['hr'] > 2) {
125            $this->docArray['err']['manyhr'] = ($this->docArray['hr'] - 2) / 2;
126        }
127
128        // 1 point for too many line breaks
129        if ($this->docArray['linebreak'] > 2) {
130            $this->docArray['err']['manybr'] = $this->docArray['linebreak'] - 2;
131        }
132
133        // 1 point for single author only
134        if (!$this->getConf('single_author_only') && count($this->docArray['authors']) == 1) {
135            $this->docArray['err']['singleauthor'] = 1;
136        }
137
138        // 1 point for too small document
139        if ($this->docArray['chars'] < 150) {
140            $this->docArray['err']['toosmall'] = 1;
141        }
142
143        // 1 point for too large document
144        if ($this->docArray['chars'] > 100000) {
145            $this->docArray['err']['toolarge'] = 1;
146        }
147
148        // header to text ratio
149        $hc = $this->docArray['header_count'][1] +
150              $this->docArray['header_count'][2] +
151              $this->docArray['header_count'][3] +
152              $this->docArray['header_count'][4] +
153              $this->docArray['header_count'][5];
154        $hc--; //we expect at least 1
155        if ($hc > 0) {
156            $hr = $this->docArray['chars'] / $hc;
157
158            // 1 point for too many headers
159            if ($hr < 200) {
160                $this->docArray['err']['manyheaders'] = 1;
161            }
162
163            // 1 point for too few headers
164            if ($hr > 2000) {
165                $this->docArray['err']['fewheaders'] = 1;
166            }
167        }
168
169        // 1 point when no link at all
170        if (!$this->docArray['internal_links']) {
171            $this->docArray['err']['nolink'] = 1;
172        }
173
174        // 0.5 for broken links when too many
175        if ($this->docArray['broken_links'] > 2) {
176            $this->docArray['err']['brokenlink'] = $this->docArray['broken_links'] * 0.5;
177        }
178
179        // 2 points for lot's of formatting
180        if ($this->docArray['formatted'] && $this->docArray['chars'] / $this->docArray['formatted'] < 3) {
181            $this->docArray['err']['manyformat'] = 2;
182        }
183
184        // add up all scores
185        foreach ($this->docArray['err'] as $err => $val) $this->docArray['score'] += $val;
186
187
188        //we're done here
189        $this->doc = serialize($this->docArray);
190    }
191
192    /**
193     * the format we produce
194     */
195    public function getFormat()
196    {
197        return 'qc';
198    }
199
200    public function internallink($id, $name = null, $search = null, $returnonly = false, $linktype = 'content')
201    {
202        global $ID;
203        resolve_pageid(getNS($ID), $id, $exists);
204
205        // calculate link width
206        $a = explode(':', getNS($ID));
207        $b = explode(':', getNS($id));
208        while (isset($a[0]) && $a[0] == $b[0]) {
209            array_shift($a);
210            array_shift($b);
211        }
212        $length = count($a) + count($b);
213        $this->docArray['link_lengths'][] = $length;
214
215        $this->docArray['internal_links']++;
216        if (!$exists) $this->docArray['broken_links']++;
217    }
218
219    public function externallink($url, $name = null)
220    {
221        $this->docArray['external_links']++;
222    }
223
224    public function header($text, $level, $pos)
225    {
226        $this->docArray['header_count'][$level]++;
227        $this->docArray['header_struct'][] = $level;
228    }
229
230    public function smiley($smiley)
231    {
232        if ($smiley == 'FIXME') $this->docArray['fixme']++;
233    }
234
235    public function linebreak()
236    {
237        if (!$this->tableopen) {
238            $this->docArray['linebreak']++;
239        }
240    }
241
242    public function table_open($maxcols = null, $numrows = null, $pos = null) // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
243    {
244        $this->tableopen = true;
245    }
246
247    public function table_close($pos = null) // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
248    {
249        $this->tableopen = false;
250    }
251
252    public function hr()
253    {
254        $this->docArray['hr']++;
255    }
256
257    public function quote_open() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
258    {
259        $this->docArray['quote_count']++;
260        $this->quotelevel++;
261        $this->docArray['quote_nest'] = max($this->quotelevel, $this->docArray['quote_nest']);
262    }
263
264    public function quote_close() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
265    {
266        $this->quotelevel--;
267    }
268
269    public function strong_open() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
270    {
271        $this->formatting++;
272    }
273
274    public function strong_close() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
275    {
276        $this->formatting--;
277    }
278
279    public function emphasis_open() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
280    {
281        $this->formatting++;
282    }
283
284    public function emphasis_close() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
285    {
286        $this->formatting--;
287    }
288
289    public function underline_open() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
290    {
291        $this->formatting++;
292    }
293
294    public function underline_close() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
295    {
296        $this->formatting--;
297    }
298
299    public function cdata($text)
300    {
301        if (!$this->formatting) return;
302
303        $len = utf8_strlen($text);
304
305        // 1 point for formattings longer than 500 chars
306        if ($len > 500) $this->docArray['err']['longformat']++;
307
308        // 1 point for each multiformatting
309        if ($this->formatting > 1) $this->docArray['err']['multiformat'] += 1 * ($this->formatting - 1);
310
311        $this->docArray['formatted'] += $len;
312    }
313}
314
315//Setup VIM: ex: et ts=4 enc=utf-8 :
316