]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/FuzzyPages.php
td => th in FuzzyPages
[SourceForge/phpwiki.git] / lib / plugin / FuzzyPages.php
1 <?php // -*-php-*-
2 rcs_id('$Id: FuzzyPages.php,v 1.8 2002-08-20 18:26:12 rurban 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
24 //require_once('lib/PageList.php');
25
26 /**
27  * FuzzyPages is plugin which searches for similar page titles.
28  *
29  * Pages are considered similar by averaging the similarity scores of
30  * the spelling comparison and the metaphone comparison for each page
31  * title in the database (php's metaphone() is an improved soundex
32  * function).
33  *
34  * http://www.php.net/manual/en/function.similar-text.php
35  * http://www.php.net/manual/en/function.metaphone.php
36  */
37 class WikiPlugin_FuzzyPages
38 extends WikiPlugin
39 {
40     function getName() {
41         return _("FuzzyPages");
42     }
43
44     function getDescription() {
45         return sprintf(_("List FuzzyPages for %s"), '[pagename]');
46     }
47
48     function getDefaultArguments() {
49         return array('s'     => false,
50                      'debug' => false);
51     }
52
53     function spelling_similarity($subject) {
54         $spelling_similarity_score = 0;
55         similar_text($subject, $this->_searchterm,
56                      &$spelling_similarity_score);
57         return $spelling_similarity_score;
58     }
59
60     function sound_similarity($subject) {
61         $sound_similarity_score = 0;
62         similar_text(metaphone($subject), $this->_searchterm_metaphone,
63                      &$sound_similarity_score);
64         return $sound_similarity_score;
65     }
66
67     function averageSimilarities($subject) {
68         return ($this->spelling_similarity($subject)
69                 + $this->sound_similarity($subject)) / 2;
70     }
71
72     function collectSimilarPages(&$list, &$dbi) {
73         if (! defined('MIN_SCORE_CUTOFF'))
74             define('MIN_SCORE_CUTOFF', 33);
75
76         $this->_searchterm_metaphone = metaphone($this->_searchterm);
77
78         $allPages = $dbi->getAllPages();
79
80         while ($pagehandle = $allPages->next()) {
81             $pagename = $pagehandle->getName();
82             $similarity_score = $this->averageSimilarities($pagename);
83             if ($similarity_score > MIN_SCORE_CUTOFF)
84                 $list = array_merge($list,
85                                     array($pagename => $similarity_score));
86         }
87     }
88
89     function sortCollectedPages(&$list) {
90         array_multisort(&$list, SORT_NUMERIC, SORT_DESC);
91     }
92
93
94
95     function addTableCaption(&$table, &$dbi) {
96         if ($dbi->isWikiPage($this->_searchterm))
97             $link = WikiLink($this->_searchterm, 'auto');
98         else
99             $link = $this->_searchterm;
100         $caption = fmt("These page titles match fuzzy with '%s'", $link);
101         $table->pushContent(HTML::caption(array('align'=>'top'), $caption));
102     }
103
104     function addTableHead(&$table) {
105         $row = HTML::tr(HTML::th(_("Name")),
106                         HTML::th(array('align' => 'right'), _("Score")));
107         if ($this->debug)
108             $this->_pushDebugHeadingTDinto($row);
109
110         $table->pushContent(HTML::thead($row));
111     }
112
113     function addTableBody(&$list, &$table) {
114         if (! defined('HIGHLIGHT_ROWS_CUTOFF_SCORE'))
115             define('HIGHLIGHT_ROWS_CUTOFF_SCORE', 60);
116
117         $tbody = HTML::tbody();
118         foreach ($list as $found_pagename => $score) {
119             $row = HTML::tr(array('class' =>
120                                   $score > HIGHLIGHT_ROWS_CUTOFF_SCORE
121                                   ? 'evenrow' : 'oddrow'),
122                             HTML::td(WikiLink($found_pagename)),
123                             HTML::td(array('align' => 'right'),
124                                      round($score)));
125
126             if ($this->debug)
127                 $this->_pushDebugTDinto($row, $found_pagename);
128
129             $tbody->pushContent($row);
130         }
131         $table->pushContent($tbody);
132     }
133
134     function formatTable(&$list, &$dbi) {
135
136         $table = HTML::table(array('cellpadding' => 2,
137                                    'cellspacing' => 1,
138                                    'border'      => 0,
139                                    'class' => 'pagelist'));
140         $this->addTableCaption($table, &$dbi);
141         $this->addTableHead($table);
142         $this->addTableBody($list, $table);
143         return $table;
144     }
145
146
147     function run($dbi, $argstr, $request) {
148         $args = $this->getArgs($argstr, $request);
149         extract($args);
150         if (empty($s))
151             return '';
152         $this->debug = $debug;
153
154         $this->_searchterm = $s;
155         $this->_list = array();
156
157         $this->collectSimilarPages($this->_list, &$dbi);
158
159         $this->sortCollectedPages($this->_list);
160
161         return $this->formatTable($this->_list, &$dbi);
162     }
163
164
165
166     function _pushDebugHeadingTDinto(&$row) {
167         $row->pushContent(HTML::td(_("Spelling Score")),
168                           HTML::td(_("Sound Score")),
169                           HTML::td('Metaphones'));
170     }
171
172     function _pushDebugTDinto(&$row, $pagename) {
173         // This actually calculates everything a second time for each pagename
174         // so the individual scores can be displayed separately for debugging.
175         $debug_spelling = round($this->spelling_similarity($pagename), 1);
176         $debug_sound = round($this->sound_similarity($pagename), 1);
177         $debug_metaphone = sprintf("(%s, %s)", metaphone($pagename),
178                                    $this->_searchterm_metaphone);
179
180         $row->pushcontent(HTML::td(array('align' => 'center'), $debug_spelling),
181                           HTML::td(array('align' => 'center'), $debug_sound),
182                           HTML::td($debug_metaphone));
183     }
184 };
185
186 // Local Variables:
187 // mode: php
188 // tab-width: 8
189 // c-basic-offset: 4
190 // c-hanging-comment-ender-p: nil
191 // indent-tabs-mode: nil
192 // End:
193 ?>