]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/FuzzyPages.php
Code cleanup:
[SourceForge/phpwiki.git] / lib / plugin / FuzzyPages.php
1 <?php // -*-php-*-
2 rcs_id('$Id: FuzzyPages.php,v 1.9 2003-01-18 21:41:02 carstenklapp Exp $');
3 /*
4  Copyright 1999, 2000, 2001, 2002 $ThePhpWikiProgrammingTeam
5
6  This file is part of PhpWiki.
7
8  PhpWiki is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  PhpWiki is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with PhpWiki; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 //require_once('lib/PageList.php');
24
25 /**
26  * FuzzyPages is plugin which searches for similar page titles.
27  *
28  * Pages are considered similar by averaging the similarity scores of
29  * the spelling comparison and the metaphone comparison for each page
30  * title in the database (php's metaphone() is an improved soundex
31  * function).
32  *
33  * http://www.php.net/manual/en/function.similar-text.php
34  * http://www.php.net/manual/en/function.metaphone.php
35  */
36 class WikiPlugin_FuzzyPages
37 extends WikiPlugin
38 {
39     function getName() {
40         return _("FuzzyPages");
41     }
42
43     function getDescription() {
44         return sprintf(_("Search for page titles similar to %s."),
45                        '[pagename]');
46     }
47
48     function getVersion() {
49         return preg_replace("/[Revision: $]/", '',
50                             "\$Revision: 1.9 $");
51     }
52
53     function getDefaultArguments() {
54         return array('s'     => false,
55                      'debug' => false);
56     }
57
58     function spelling_similarity($subject) {
59         $spelling_similarity_score = 0;
60         similar_text($subject, $this->_searchterm,
61                      &$spelling_similarity_score);
62         return $spelling_similarity_score;
63     }
64
65     function sound_similarity($subject) {
66         $sound_similarity_score = 0;
67         similar_text(metaphone($subject), $this->_searchterm_metaphone,
68                      &$sound_similarity_score);
69         return $sound_similarity_score;
70     }
71
72     function averageSimilarities($subject) {
73         return ($this->spelling_similarity($subject)
74                 + $this->sound_similarity($subject)) / 2;
75     }
76
77     function collectSimilarPages(&$list, &$dbi) {
78         if (! defined('MIN_SCORE_CUTOFF'))
79             define('MIN_SCORE_CUTOFF', 33);
80
81         $this->_searchterm_metaphone = metaphone($this->_searchterm);
82
83         $allPages = $dbi->getAllPages();
84
85         while ($pagehandle = $allPages->next()) {
86             $pagename = $pagehandle->getName();
87             $similarity_score = $this->averageSimilarities($pagename);
88             if ($similarity_score > MIN_SCORE_CUTOFF)
89                 $list = array_merge($list,
90                                     array($pagename => $similarity_score));
91         }
92     }
93
94     function sortCollectedPages(&$list) {
95         array_multisort(&$list, SORT_NUMERIC, SORT_DESC);
96     }
97
98     function addTableCaption(&$table, &$dbi) {
99         if ($dbi->isWikiPage($this->_searchterm))
100             $link = WikiLink($this->_searchterm, 'auto');
101         else
102             $link = $this->_searchterm;
103         $caption = fmt("These page titles match fuzzy with '%s'", $link);
104         $table->pushContent(HTML::caption(array('align'=>'top'), $caption));
105     }
106
107     function addTableHead(&$table) {
108         $row = HTML::tr(HTML::th(_("Name")),
109                         HTML::th(array('align' => 'right'), _("Score")));
110         if ($this->debug)
111             $this->_pushDebugHeadingTDinto($row);
112
113         $table->pushContent(HTML::thead($row));
114     }
115
116     function addTableBody(&$list, &$table) {
117         if (! defined('HIGHLIGHT_ROWS_CUTOFF_SCORE'))
118             define('HIGHLIGHT_ROWS_CUTOFF_SCORE', 60);
119
120         $tbody = HTML::tbody();
121         foreach ($list as $found_pagename => $score) {
122             $row = HTML::tr(array('class' =>
123                                   $score > HIGHLIGHT_ROWS_CUTOFF_SCORE
124                                   ? 'evenrow' : 'oddrow'),
125                             HTML::td(WikiLink($found_pagename)),
126                             HTML::td(array('align' => 'right'),
127                                      round($score)));
128
129             if ($this->debug)
130                 $this->_pushDebugTDinto($row, $found_pagename);
131
132             $tbody->pushContent($row);
133         }
134         $table->pushContent($tbody);
135     }
136
137     function formatTable(&$list, &$dbi) {
138
139         $table = HTML::table(array('cellpadding' => 2,
140                                    'cellspacing' => 1,
141                                    'border'      => 0,
142                                    'class' => 'pagelist'));
143         $this->addTableCaption($table, &$dbi);
144         $this->addTableHead($table);
145         $this->addTableBody($list, $table);
146         return $table;
147     }
148
149
150     function run($dbi, $argstr, $request) {
151         $args = $this->getArgs($argstr, $request);
152         extract($args);
153         if (empty($s))
154             return '';
155         $this->debug = $debug;
156
157         $this->_searchterm = $s;
158         $this->_list = array();
159
160         $this->collectSimilarPages($this->_list, &$dbi);
161
162         $this->sortCollectedPages($this->_list);
163
164         return $this->formatTable($this->_list, &$dbi);
165     }
166
167
168
169     function _pushDebugHeadingTDinto(&$row) {
170         $row->pushContent(HTML::td(_("Spelling Score")),
171                           HTML::td(_("Sound Score")),
172                           HTML::td('Metaphones'));
173     }
174
175     function _pushDebugTDinto(&$row, $pagename) {
176         // This actually calculates everything a second time for each pagename
177         // so the individual scores can be displayed separately for debugging.
178         $debug_spelling = round($this->spelling_similarity($pagename), 1);
179         $debug_sound = round($this->sound_similarity($pagename), 1);
180         $debug_metaphone = sprintf("(%s, %s)", metaphone($pagename),
181                                    $this->_searchterm_metaphone);
182
183         $row->pushcontent(HTML::td(array('align' => 'center'), $debug_spelling),
184                           HTML::td(array('align' => 'center'), $debug_sound),
185                           HTML::td($debug_metaphone));
186     }
187 };
188
189 // $Log: not supported by cvs2svn $
190
191 // Local Variables:
192 // mode: php
193 // tab-width: 8
194 // c-basic-offset: 4
195 // c-hanging-comment-ender-p: nil
196 // indent-tabs-mode: nil
197 // End:
198 ?>