]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Irc/extlib/phergie/Phergie/Plugin/Karma.php
Documentation + filename uniqueness in File class
[quix0rs-gnu-social.git] / plugins / Irc / extlib / phergie / Phergie / Plugin / Karma.php
1 <?php
2 /**
3  * Phergie
4  *
5  * PHP version 5
6  *
7  * LICENSE
8  *
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
13  *
14  * @category  Phergie
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
20  */
21
22 /**
23  * Handles requests for incrementation or decrementation of a maintained list
24  * of counters for specified terms.
25  *
26  * @category Phergie
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
31  * @uses     extension PDO
32  * @uses     extension pdo_sqlite
33  * @uses     Phergie_Plugin_Command pear.phergie.org
34  */
35 class Phergie_Plugin_Karma extends Phergie_Plugin_Abstract
36 {
37     /**
38      * SQLite object
39      *
40      * @var resource
41      */
42     protected $db = null;
43
44     /**
45      * Prepared statement to add a new karma record
46      *
47      * @var PDOStatement
48      */
49     protected $insertKarma;
50
51     /**
52      * Prepared statement to update an existing karma record
53      *
54      * @var PDOStatement
55      */
56     protected $updateKarma;
57
58     /**
59      * Retrieves an existing karma record
60      *
61      * @var PDOStatement
62      */
63     protected $fetchKarma;
64
65     /**
66      * Retrieves an existing fixed karma record
67      *
68      * @var PDOStatement
69      */
70     protected $fetchFixedKarma;
71
72     /**
73      * Retrieves a positive answer for a karma comparison
74      *
75      * @var PDOStatement
76      */
77     protected $fetchPositiveAnswer;
78
79     /**
80      * Retrieves a negative answer for a karma comparison
81      *
82      * @var PDOStatement
83      */
84     protected $fetchNegativeAnswer;
85
86     /**
87      * Check for dependencies and initializes a database connection and
88      * prepared statements.
89      *
90      * @return void
91      */
92     public function onLoad()
93     {
94         $plugins = $this->getPluginHandler();
95         $plugins->getPlugin('Command');
96         $this->getDb();
97     }
98
99     /**
100      * Initializes prepared statements used by the plugin.
101      *
102      * @return void
103      */
104     protected function initializePreparedStatements()
105     {
106         $this->fetchKarma = $this->db->prepare('
107             SELECT karma
108             FROM karmas
109             WHERE term = :term
110             LIMIT 1
111         ');
112
113         $this->insertKarma = $this->db->prepare('
114             INSERT INTO karmas (term, karma)
115             VALUES (:term, :karma)
116         ');
117
118         $this->updateKarma = $this->db->prepare('
119             UPDATE karmas
120             SET karma = :karma
121             WHERE term = :term
122         ');
123
124         $this->fetchFixedKarma = $this->db->prepare('
125             SELECT karma
126             FROM fixed_karmas
127             WHERE term = :term
128             LIMIT 1
129         ');
130
131         $this->fetchPositiveAnswer = $this->db->prepare('
132             SELECT answer
133             FROM positive_answers
134             ORDER BY RANDOM()
135             LIMIT 1
136         ');
137
138         $this->fetchNegativeAnswer = $this->db->prepare('
139             SELECT answer
140             FROM negative_answers
141             ORDER BY RANDOM()
142             LIMIT 1
143         ');
144     }
145
146     /**
147      * Returns a connection to the plugin database, initializing one if none
148      * is explicitly set.
149      *
150      * @return PDO Database connection
151      */
152     public function getDb()
153     {
154         if (empty($this->db)) {
155             $this->db = new PDO('sqlite:' . dirname(__FILE__) . '/Karma/karma.db');
156             $this->initializePreparedStatements();
157         }
158         return $this->db;
159     }
160
161     /**
162      * Sets the connection to the plugin database, mainly intended for unit
163      * testing.
164      *
165      * @param PDO $db Database connection
166      *
167      * @return Phergie_Plugin_Karma Provides a fluent interface
168      */
169     public function setDb(PDO $db)
170     {
171         $this->db = $db;
172         $this->initializePreparedStatements();
173         return $this;
174     }
175
176     /**
177      * Get the canonical form of a given term.
178      *
179      * In the canonical form all sequences of whitespace
180      * are replaced by a single space and all characters
181      * are lowercased.
182      *
183      * @param string $term Term for which a canonical form is required
184      *
185      * @return string Canonical term
186      */
187     protected function getCanonicalTerm($term)
188     {
189         $canonicalTerm = strtolower(preg_replace('|\s+|', ' ', trim($term, '()')));
190         switch ($canonicalTerm) {
191             case 'me':
192                 $canonicalTerm = strtolower($this->event->getNick());
193                 break;
194             case 'all':
195             case '*':
196             case 'everything':
197                 $canonicalTerm = 'everything';
198                 break;
199         }
200         return $canonicalTerm;
201     }
202
203     /**
204      * Intercepts a message and processes any contained recognized commands.
205      *
206      * @return void
207      */
208     public function onPrivmsg()
209     {
210         $message = $this->getEvent()->getText();
211
212         $termPattern = '\S+?|\([^<>]+?\)+';
213         $actionPattern = '(?P<action>\+\+|--)';
214
215         $modifyPattern = <<<REGEX
216                 {^
217                 (?J) # allow overwriting capture names
218                 \s*  # ignore leading whitespace
219
220                 (?:  # start with ++ or -- before the term
221             $actionPattern
222             (?P<term>$termPattern)
223                 |   # follow the term with ++ or --
224             (?P<term>$termPattern)
225                         $actionPattern # allow no whitespace between the term and the action
226                 )
227                 $}ix
228 REGEX;
229
230         $versusPattern = <<<REGEX
231         {^
232                 (?P<term0>$termPattern)
233                         \s+(?P<method><|>)\s+
234                 (?P<term1>$termPattern)$#
235         $}ix
236 REGEX;
237
238         $match = null;
239
240         if (preg_match($modifyPattern, $message, $match)) {
241             $action = $match['action'];
242             $term = $this->getCanonicalTerm($match['term']);
243             $this->modifyKarma($term, $action);
244         } elseif (preg_match($versusPattern, $message, $match)) {
245             $term0 = trim($match['term0']);
246             $term1 = trim($match['term1']);
247             $method = $match['method'];
248             $this->compareKarma($term0, $term1, $method);
249         }
250     }
251
252     /**
253      * Get the karma rating for a given term.
254      *
255      * @param string $term Term for which the karma rating needs to be
256      *        retrieved
257      *
258      * @return void
259      */
260     public function onCommandKarma($term)
261     {
262         $source = $this->getEvent()->getSource();
263         $nick = $this->getEvent()->getNick();
264
265         $canonicalTerm = $this->getCanonicalTerm($term);
266
267         $fixedKarma = $this->fetchFixedKarma($canonicalTerm);
268         if ($fixedKarma) {
269             $message = $nick . ': ' . $term . ' ' . $fixedKarma;
270             $this->doPrivmsg($source, $message);
271             return;
272         }
273
274         $karma = $this->fetchKarma($canonicalTerm);
275
276         $message = $nick . ': ';
277
278         if ($term == 'me') {
279             $message .= 'You have';
280         } else {
281             $message .= $term . ' has';
282         }
283
284         $message .= ' ';
285
286         if ($karma) {
287             $message .= 'karma of ' . $karma;
288         } else {
289             $message .= 'neutral karma';
290         }
291
292         $message .= '.';
293
294         $this->doPrivmsg($source, $message);
295     }
296
297     /**
298      * Resets the karma for a term to 0.
299      *
300      * @param string $term Term for which to reset the karma rating
301      *
302      * @return void
303      */
304     public function onCommandReincarnate($term)
305     {
306         $data = array(
307             ':term' => $term,
308             ':karma' => 0
309         );
310         $this->updateKarma->execute($data);
311     }
312
313     /**
314      * Compares the karma between two terms. Optionally increases/decreases
315      * the karma of either term.
316      *
317      * @param string $term0  First term
318      * @param string $term1  Second term
319      * @param string $method Comparison method (< or >)
320      *
321      * @return void
322      */
323     protected function compareKarma($term0, $term1, $method)
324     {
325         $event = $this->getEvent();
326         $nick = $event->getNick();
327         $source = $event->getSource();
328
329         $canonicalTerm0 = $this->getCanonicalTerm($term0);
330         $canonicalTerm1 = $this->getCanonicalTerm($term1);
331
332         $fixedKarma0 = $this->fetchFixedKarma($canonicalTerm0);
333         $fixedKarma1 = $this->fetchFixedKarma($canonicalTerm1);
334
335         if ($fixedKarma0 || $fixedKarma1) {
336             return;
337         }
338
339         if ($canonicalTerm0 == 'everything') {
340             $change = $method == '<' ? '++' : '--';
341             $karma0 = 0;
342             $karma1 = $this->modifyKarma($canonicalTerm1, $change);
343         } elseif ($canonicalTerm1 == 'everything') {
344             $change = $method == '<' ? '--' : '++';
345             $karma0 = $this->modifyKarma($canonicalTerm0, $change);
346             $karma1 = 0;
347         } else {
348             $karma0 = $this->fetchKarma($canonicalTerm0);
349             $karma1 = $this->fetchKarma($canonicalTerm1);
350         }
351
352         // Combining the first and second branches here causes an odd
353         // single-line lapse in code coverage, but the lapse disappears if
354         // they're separated
355         if ($method == '<' && $karma0 < $karma1) {
356             $replies = $this->fetchPositiveAnswer;
357         } elseif ($method == '>' && $karma0 > $karma1) {
358             $replies = $this->fetchPositiveAnswer;
359         } else {
360             $replies = $this->fetchNegativeAnswer;
361         }
362         $replies->execute();
363         $reply = $replies->fetchColumn();
364
365         if (max($karma0, $karma1) == $karma1) {
366             list($canonicalTerm0, $canonicalTerm1) =
367                 array($canonicalTerm1, $canonicalTerm0);
368         }
369
370         $message = str_replace(
371             array('%owner%','%owned%'),
372             array($canonicalTerm0, $canonicalTerm1),
373             $reply
374         );
375
376         $this->doPrivmsg($source, $message);
377     }
378
379     /**
380      * Modifes a term's karma.
381      *
382      * @param string $term   Term to modify
383      * @param string $action Karma action (either ++ or --)
384      *
385      * @return int Modified karma rating
386      */
387     protected function modifyKarma($term, $action)
388     {
389         $karma = $this->fetchKarma($term);
390         if ($karma !== false) {
391             $statement = $this->updateKarma;
392         } else {
393             $statement = $this->insertKarma;
394         }
395
396         $karma += ($action == '++') ? 1 : -1;
397
398         $args = array(
399             ':term'  => $term,
400             ':karma' => $karma
401         );
402         $statement->execute($args);
403
404         return $karma;
405     }
406
407     /**
408      * Returns the karma rating for a specified term for which the karma
409      * rating can be modified.
410      *
411      * @param string $term Term for which to fetch the corresponding karma
412      *        rating
413      *
414      * @return integer|boolean Integer value denoting the term's karma or
415      *         FALSE if there is the specified term has no associated karma
416      *         rating
417      */
418     protected function fetchKarma($term)
419     {
420         $this->fetchKarma->execute(array(':term' => $term));
421         $result = $this->fetchKarma->fetch(PDO::FETCH_ASSOC);
422
423         if ($result === false) {
424             return false;
425         }
426
427         return (int) $result['karma'];
428     }
429
430     /**
431      * Returns a phrase describing the karma rating for a specified term for
432      * which the karma rating is fixed.
433      *
434      * @param string $term Term for which to fetch the corresponding karma
435      *        rating
436      *
437      * @return string Phrase describing the karma rating, which may be append
438      *         to the term to form a complete response
439      */
440     protected function fetchFixedKarma($term)
441     {
442         $this->fetchFixedKarma->execute(array(':term' => $term));
443         $result = $this->fetchFixedKarma->fetch(PDO::FETCH_ASSOC);
444
445         if ($result === false) {
446             return false;
447         }
448
449         return $result['karma'];
450     }
451 }