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