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