9 * This source file is subject to the new BSD license that is bundled
10 * with this package in the file LICENSE.
11 * It is also available through the world-wide-web at this URL:
12 * http://phergie.org/license
15 * @package Phergie_Plugin_Karma
16 * @author Phergie Development Team <team@phergie.org>
17 * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
18 * @license http://phergie.org/license New BSD License
19 * @link http://pear.phergie.org/package/Phergie_Plugin_Karma
23 * Handles requests for incrementation or decrementation of a maintained list
24 * of counters for specified terms.
27 * @package Phergie_Plugin_Karma
28 * @author Phergie Development Team <team@phergie.org>
29 * @license http://phergie.org/license New BSD License
30 * @link http://pear.phergie.org/package/Phergie_Plugin_Karma
32 * @uses extension pdo_sqlite
33 * @uses Phergie_Plugin_Command pear.phergie.org
34 * @uses Phergie_Plugin_Message pear.phergie.org
36 class Phergie_Plugin_Karma extends Phergie_Plugin_Abstract
46 * Prepared statement to add a new karma record
50 protected $insertKarma;
53 * Prepared statement to update an existing karma record
57 protected $updateKarma;
60 * Retrieves an existing karma record
64 protected $fetchKarma;
67 * Retrieves an existing fixed karma record
71 protected $fetchFixedKarma;
74 * Retrieves a positive answer for a karma comparison
78 protected $fetchPositiveAnswer;
81 * Retrieves a negative answer for a karma comparison
85 protected $fetchNegativeAnswer;
88 * Check for dependencies and initializes a database connection and
89 * prepared statements.
93 public function onLoad()
95 $plugins = $this->getPluginHandler();
96 $plugins->getPlugin('Command');
97 $plugins->getPlugin('Message');
99 $file = dirname(__FILE__) . '/Karma/karma.db';
100 $this->db = new PDO('sqlite:' . $file);
102 $this->fetchKarma = $this->db->prepare('
109 $this->insertKarma = $this->db->prepare('
110 INSERT INTO karmas (term, karma)
111 VALUES (:term, :karma)
114 $this->updateKarma = $this->db->prepare('
120 $this->fetchFixedKarma = $this->db->prepare('
127 $this->fetchPositiveAnswer = $this->db->prepare('
129 FROM positive_answers
134 $this->fetchNegativeAnswer = $this->db->prepare('
136 FROM negative_answers
143 * Get the canonical form of a given term.
145 * In the canonical form all sequences of whitespace
146 * are replaced by a single space and all characters
149 * @param string $term Term for which a canonical form is required
151 * @return string Canonical term
153 protected function getCanonicalTerm($term)
155 $canonicalTerm = strtolower(preg_replace('|\s+|', ' ', trim($term, '()')));
156 switch ($canonicalTerm) {
158 $canonicalTerm = strtolower($this->event->getNick());
163 $canonicalTerm = 'everything';
166 return $canonicalTerm;
170 * Intercepts a message and processes any contained recognized commands.
174 public function onPrivmsg()
176 $message = $this->getEvent()->getText();
178 $termPattern = '\S+?|\([^<>]+?\)+';
179 $actionPattern = '(?P<action>\+\+|--)';
181 $modifyPattern = <<<REGEX
183 (?J) # allow overwriting capture names
184 \s* # ignore leading whitespace
186 (?: # start with ++ or -- before the term
188 (?P<term>$termPattern)
189 | # follow the term with ++ or --
190 (?P<term>$termPattern)
191 $actionPattern # allow no whitespace between the term and the action
196 $versusPattern = <<<REGEX
198 (?P<term0>$termPattern)
199 \s+(?P<method><|>)\s+
200 (?P<term1>$termPattern)$#
206 if (preg_match($modifyPattern, $message, $match)) {
207 $action = $match['action'];
208 $term = $this->getCanonicalTerm($match['term']);
209 $this->modifyKarma($term, $action);
210 } elseif (preg_match($versusPattern, $message, $match)) {
211 $term0 = trim($match['term0']);
212 $term1 = trim($match['term1']);
213 $method = $match['method'];
214 $this->compareKarma($term0, $term1, $method);
219 * Get the karma rating for a given term.
221 * @param string $term Term for which the karma rating needs to be
226 public function onCommandKarma($term)
228 $source = $this->getEvent()->getSource();
229 $nick = $this->getEvent()->getNick();
235 $canonicalTerm = $this->getCanonicalTerm($term);
237 $fixedKarma = $this->fetchFixedKarma($canonicalTerm);
239 $message = $nick . ': ' . $term . $fixedKarma . '.';
240 $this->doPrivmsg($source, $message);
244 $karma = $this->fetchKarma($canonicalTerm);
246 $message = $nick . ': ';
249 $message .= 'You have';
251 $message .= $term . ' has';
257 $message .= 'karma of ' . $karma;
259 $message .= 'neutral karma';
264 $this->doPrivmsg($source, $message);
268 * Resets the karma for a term to 0.
270 * @param string $term Term for which to reset the karma rating
274 public function onCommandReincarnate($term)
280 $this->updateKarma->execute($data);
284 * Compares the karma between two terms. Optionally increases/decreases
285 * the karma of either term.
287 * @param string $term0 First term
288 * @param string $term1 Second term
289 * @param string $method Comparison method (< or >)
293 protected function compareKarma($term0, $term1, $method)
295 $event = $this->getEvent();
296 $nick = $event->getNick();
297 $source = $event->getSource();
299 $canonicalTerm0 = $this->getCanonicalTerm($term0);
300 $canonicalTerm1 = $this->getCanonicalTerm($term1);
302 $fixedKarma0 = $this->fetchFixedKarma($canonicalTerm0);
303 $fixedKarma1 = $this->fetchFixedKarma($canonicalTerm1);
307 || empty($canonicalTerm0)
308 || empty($canonicalTerm1)
313 if ($canonicalTerm0 == 'everything') {
314 $change = $method == '<' ? '++' : '--';
315 $this->modifyKarma($canonicalTerm1, $change);
317 $karma1 = $this->fetchKarma($canonicalTerm1);
318 } elseif ($canonicalTerm1 == 'everything') {
319 $change = $method == '<' ? '--' : '++';
320 $this->modifyKarma($canonicalTerm0, $change);
321 $karma0 = $this->fetchKarma($canonicalTerm1);
324 $karma0 = $this->fetchKarma($canonicalTerm0);
325 $karma1 = $this->fetchKarma($canonicalTerm1);
329 && $karma0 < $karma1)
331 && $karma0 > $karma1)) {
332 $replies = $this->fetchPositiveAnswer;
334 $replies = $this->fetchNegativeAnswer;
337 $reply = $replies->fetchColumn();
339 if (max($karma0, $karma1) == $karma1) {
340 list($canonicalTerm0, $canonicalTerm1) =
341 array($canonicalTerm1, $canonicalTerm0);
344 $message = str_replace(
345 array('%owner%','%owned%'),
346 array($canonicalTerm0, $canonicalTerm1),
350 $this->doPrivmsg($source, $message);
354 * Modifes a term's karma.
356 * @param string $term Term to modify
357 * @param string $action Karma action (either ++ or --)
361 protected function modifyKarma($term, $action)
367 $karma = $this->fetchKarma($term);
368 if ($karma !== false) {
369 $statement = $this->updateKarma;
371 $statement = $this->insertKarma;
374 $karma += ($action == '++') ? 1 : -1;
380 $statement->execute($args);
384 * Returns the karma rating for a specified term for which the karma
385 * rating can be modified.
387 * @param string $term Term for which to fetch the corresponding karma
390 * @return integer|boolean Integer value denoting the term's karma or
391 * FALSE if there is the specified term has no associated karma
394 protected function fetchKarma($term)
396 $this->fetchKarma->execute(array(':term' => $term));
397 $result = $this->fetchKarma->fetch(PDO::FETCH_ASSOC);
399 if ($result === false) {
403 return (int) $result['karma'];
407 * Returns a phrase describing the karma rating for a specified term for
408 * which the karma rating is fixed.
410 * @param string $term Term for which to fetch the corresponding karma
413 * @return string Phrase describing the karma rating, which may be append
414 * to the term to form a complete response
416 protected function fetchFixedKarma($term)
418 $this->fetchFixedKarma->execute(array(':term' => $term));
419 $result = $this->fetchFixedKarma->fetch(PDO::FETCH_ASSOC);
421 if ($result === false) {
425 return $result['karma'];