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