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