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