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