diff options
Diffstat (limited to 'plugins/Irc/extlib/phergie/Phergie/Plugin/Karma.php')
-rw-r--r-- | plugins/Irc/extlib/phergie/Phergie/Plugin/Karma.php | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/plugins/Irc/extlib/phergie/Phergie/Plugin/Karma.php b/plugins/Irc/extlib/phergie/Phergie/Plugin/Karma.php new file mode 100644 index 000000000..27b4a087d --- /dev/null +++ b/plugins/Irc/extlib/phergie/Phergie/Plugin/Karma.php @@ -0,0 +1,451 @@ +<?php +/** + * Phergie + * + * PHP version 5 + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE. + * It is also available through the world-wide-web at this URL: + * http://phergie.org/license + * + * @category Phergie + * @package Phergie_Plugin_Karma + * @author Phergie Development Team <team@phergie.org> + * @copyright 2008-2010 Phergie Development Team (http://phergie.org) + * @license http://phergie.org/license New BSD License + * @link http://pear.phergie.org/package/Phergie_Plugin_Karma + */ + +/** + * Handles requests for incrementation or decrementation of a maintained list + * of counters for specified terms. + * + * @category Phergie + * @package Phergie_Plugin_Karma + * @author Phergie Development Team <team@phergie.org> + * @license http://phergie.org/license New BSD License + * @link http://pear.phergie.org/package/Phergie_Plugin_Karma + * @uses extension PDO + * @uses extension pdo_sqlite + * @uses Phergie_Plugin_Command pear.phergie.org + */ +class Phergie_Plugin_Karma extends Phergie_Plugin_Abstract +{ + /** + * SQLite object + * + * @var resource + */ + protected $db = null; + + /** + * Prepared statement to add a new karma record + * + * @var PDOStatement + */ + protected $insertKarma; + + /** + * Prepared statement to update an existing karma record + * + * @var PDOStatement + */ + protected $updateKarma; + + /** + * Retrieves an existing karma record + * + * @var PDOStatement + */ + protected $fetchKarma; + + /** + * Retrieves an existing fixed karma record + * + * @var PDOStatement + */ + protected $fetchFixedKarma; + + /** + * Retrieves a positive answer for a karma comparison + * + * @var PDOStatement + */ + protected $fetchPositiveAnswer; + + /** + * Retrieves a negative answer for a karma comparison + * + * @var PDOStatement + */ + protected $fetchNegativeAnswer; + + /** + * Check for dependencies and initializes a database connection and + * prepared statements. + * + * @return void + */ + public function onLoad() + { + $plugins = $this->getPluginHandler(); + $plugins->getPlugin('Command'); + $this->getDb(); + } + + /** + * Initializes prepared statements used by the plugin. + * + * @return void + */ + protected function initializePreparedStatements() + { + $this->fetchKarma = $this->db->prepare(' + SELECT karma + FROM karmas + WHERE term = :term + LIMIT 1 + '); + + $this->insertKarma = $this->db->prepare(' + INSERT INTO karmas (term, karma) + VALUES (:term, :karma) + '); + + $this->updateKarma = $this->db->prepare(' + UPDATE karmas + SET karma = :karma + WHERE term = :term + '); + + $this->fetchFixedKarma = $this->db->prepare(' + SELECT karma + FROM fixed_karmas + WHERE term = :term + LIMIT 1 + '); + + $this->fetchPositiveAnswer = $this->db->prepare(' + SELECT answer + FROM positive_answers + ORDER BY RANDOM() + LIMIT 1 + '); + + $this->fetchNegativeAnswer = $this->db->prepare(' + SELECT answer + FROM negative_answers + ORDER BY RANDOM() + LIMIT 1 + '); + } + + /** + * Returns a connection to the plugin database, initializing one if none + * is explicitly set. + * + * @return PDO Database connection + */ + public function getDb() + { + if (empty($this->db)) { + $this->db = new PDO('sqlite:' . dirname(__FILE__) . '/Karma/karma.db'); + $this->initializePreparedStatements(); + } + return $this->db; + } + + /** + * Sets the connection to the plugin database, mainly intended for unit + * testing. + * + * @param PDO $db Database connection + * + * @return Phergie_Plugin_Karma Provides a fluent interface + */ + public function setDb(PDO $db) + { + $this->db = $db; + $this->initializePreparedStatements(); + return $this; + } + + /** + * Get the canonical form of a given term. + * + * In the canonical form all sequences of whitespace + * are replaced by a single space and all characters + * are lowercased. + * + * @param string $term Term for which a canonical form is required + * + * @return string Canonical term + */ + protected function getCanonicalTerm($term) + { + $canonicalTerm = strtolower(preg_replace('|\s+|', ' ', trim($term, '()'))); + switch ($canonicalTerm) { + case 'me': + $canonicalTerm = strtolower($this->event->getNick()); + break; + case 'all': + case '*': + case 'everything': + $canonicalTerm = 'everything'; + break; + } + return $canonicalTerm; + } + + /** + * Intercepts a message and processes any contained recognized commands. + * + * @return void + */ + public function onPrivmsg() + { + $message = $this->getEvent()->getText(); + + $termPattern = '\S+?|\([^<>]+?\)+'; + $actionPattern = '(?P<action>\+\+|--)'; + + $modifyPattern = <<<REGEX + {^ + (?J) # allow overwriting capture names + \s* # ignore leading whitespace + + (?: # start with ++ or -- before the term + $actionPattern + (?P<term>$termPattern) + | # follow the term with ++ or -- + (?P<term>$termPattern) + $actionPattern # allow no whitespace between the term and the action + ) + $}ix +REGEX; + + $versusPattern = <<<REGEX + {^ + (?P<term0>$termPattern) + \s+(?P<method><|>)\s+ + (?P<term1>$termPattern)$# + $}ix +REGEX; + + $match = null; + + if (preg_match($modifyPattern, $message, $match)) { + $action = $match['action']; + $term = $this->getCanonicalTerm($match['term']); + $this->modifyKarma($term, $action); + } elseif (preg_match($versusPattern, $message, $match)) { + $term0 = trim($match['term0']); + $term1 = trim($match['term1']); + $method = $match['method']; + $this->compareKarma($term0, $term1, $method); + } + } + + /** + * Get the karma rating for a given term. + * + * @param string $term Term for which the karma rating needs to be + * retrieved + * + * @return void + */ + public function onCommandKarma($term) + { + $source = $this->getEvent()->getSource(); + $nick = $this->getEvent()->getNick(); + + $canonicalTerm = $this->getCanonicalTerm($term); + + $fixedKarma = $this->fetchFixedKarma($canonicalTerm); + if ($fixedKarma) { + $message = $nick . ': ' . $term . ' ' . $fixedKarma; + $this->doPrivmsg($source, $message); + return; + } + + $karma = $this->fetchKarma($canonicalTerm); + + $message = $nick . ': '; + + if ($term == 'me') { + $message .= 'You have'; + } else { + $message .= $term . ' has'; + } + + $message .= ' '; + + if ($karma) { + $message .= 'karma of ' . $karma; + } else { + $message .= 'neutral karma'; + } + + $message .= '.'; + + $this->doPrivmsg($source, $message); + } + + /** + * Resets the karma for a term to 0. + * + * @param string $term Term for which to reset the karma rating + * + * @return void + */ + public function onCommandReincarnate($term) + { + $data = array( + ':term' => $term, + ':karma' => 0 + ); + $this->updateKarma->execute($data); + } + + /** + * Compares the karma between two terms. Optionally increases/decreases + * the karma of either term. + * + * @param string $term0 First term + * @param string $term1 Second term + * @param string $method Comparison method (< or >) + * + * @return void + */ + protected function compareKarma($term0, $term1, $method) + { + $event = $this->getEvent(); + $nick = $event->getNick(); + $source = $event->getSource(); + + $canonicalTerm0 = $this->getCanonicalTerm($term0); + $canonicalTerm1 = $this->getCanonicalTerm($term1); + + $fixedKarma0 = $this->fetchFixedKarma($canonicalTerm0); + $fixedKarma1 = $this->fetchFixedKarma($canonicalTerm1); + + if ($fixedKarma0 || $fixedKarma1) { + return; + } + + if ($canonicalTerm0 == 'everything') { + $change = $method == '<' ? '++' : '--'; + $karma0 = 0; + $karma1 = $this->modifyKarma($canonicalTerm1, $change); + } elseif ($canonicalTerm1 == 'everything') { + $change = $method == '<' ? '--' : '++'; + $karma0 = $this->modifyKarma($canonicalTerm0, $change); + $karma1 = 0; + } else { + $karma0 = $this->fetchKarma($canonicalTerm0); + $karma1 = $this->fetchKarma($canonicalTerm1); + } + + // Combining the first and second branches here causes an odd + // single-line lapse in code coverage, but the lapse disappears if + // they're separated + if ($method == '<' && $karma0 < $karma1) { + $replies = $this->fetchPositiveAnswer; + } elseif ($method == '>' && $karma0 > $karma1) { + $replies = $this->fetchPositiveAnswer; + } else { + $replies = $this->fetchNegativeAnswer; + } + $replies->execute(); + $reply = $replies->fetchColumn(); + + if (max($karma0, $karma1) == $karma1) { + list($canonicalTerm0, $canonicalTerm1) = + array($canonicalTerm1, $canonicalTerm0); + } + + $message = str_replace( + array('%owner%','%owned%'), + array($canonicalTerm0, $canonicalTerm1), + $reply + ); + + $this->doPrivmsg($source, $message); + } + + /** + * Modifes a term's karma. + * + * @param string $term Term to modify + * @param string $action Karma action (either ++ or --) + * + * @return int Modified karma rating + */ + protected function modifyKarma($term, $action) + { + $karma = $this->fetchKarma($term); + if ($karma !== false) { + $statement = $this->updateKarma; + } else { + $statement = $this->insertKarma; + } + + $karma += ($action == '++') ? 1 : -1; + + $args = array( + ':term' => $term, + ':karma' => $karma + ); + $statement->execute($args); + + return $karma; + } + + /** + * Returns the karma rating for a specified term for which the karma + * rating can be modified. + * + * @param string $term Term for which to fetch the corresponding karma + * rating + * + * @return integer|boolean Integer value denoting the term's karma or + * FALSE if there is the specified term has no associated karma + * rating + */ + protected function fetchKarma($term) + { + $this->fetchKarma->execute(array(':term' => $term)); + $result = $this->fetchKarma->fetch(PDO::FETCH_ASSOC); + + if ($result === false) { + return false; + } + + return (int) $result['karma']; + } + + /** + * Returns a phrase describing the karma rating for a specified term for + * which the karma rating is fixed. + * + * @param string $term Term for which to fetch the corresponding karma + * rating + * + * @return string Phrase describing the karma rating, which may be append + * to the term to form a complete response + */ + protected function fetchFixedKarma($term) + { + $this->fetchFixedKarma->execute(array(':term' => $term)); + $result = $this->fetchFixedKarma->fetch(PDO::FETCH_ASSOC); + + if ($result === false) { + return false; + } + + return $result['karma']; + } +} |