* @license PHP License * @package WB * @subpackage db */ WBClass::load('WBDatasource_XReference'); /** * Rate everything * * Manage storage of ratings for anything related to other tables. Hence, this allows * to comment blog entries as well as users or uploaded files * * @version 0.2.1 * @package WB * @subpackage db */ class WBDatasource_Rate extends WBDatasource_XReference { /** * anonymous user */ const GROUP_ANON = '__anonymous'; /** * Session * @var patSession_Storage */ private $sess; /** * Simple query * @var WBDatasource_SimpleQuery */ private $query; /** * static constructor * * Load configuration into static property and merge it with * default values. */ static public function staticConstruct() { $conf = array( 'default' => array( 'requiredgroup' => self::GROUP_ANON, 'values' => array(1, 2, 3, 4, 5), 'minrates' => 5 ), 'namespaces' => array() ); parent::staticConstructLoader($conf, 'rate'); } /** * Constructor * * Call parent's constructor and start session. * @param array $parameter */ public function __construct($parameter = array()) { parent::__construct($parameter); $this->query = WBClass::create('WBDatasource_SimpleQuery'); $this->sess = WBClass::create('patSession'); } /** * Add rating for current record * * Store rating value for selected namespace and xid. The actual rating value must be one of the * configured values, Also permissions are checked to prevent ratings from wrong users or * duplicates. * * @param int value * @param string blurb * @return bool */ public function add($value, $blurb = '') { $data = array( 'value' => $value, 'blurb' => htmlspecialchars($blurb), $this->uPrimary => $this->uid, 'namespace' => $this->clause[0]['value'], 'xid' => $this->clause[1]['value'], ); $values = self::$conf['namespaces'][$data['namespace']]['values']; if (!in_array($value, $values)) { return false; } if (!$this->isAllowed(true)) { // return false; } if($this->mandator->isEnabled()) { foreach ($this->clause as $c) { if ($this->mandator->getIdentifier() != $c['field']) { continue; } $data[$c['field']] = $c['value']; break; } } $this->table->save('rating', '__new', $data); return true; } /** * Check wheather current use may rate * * First check in session wheather current record was rated already. * If not, access control is check for user according namespace settings. * Return true if user may rate, false otherwise. * * @param bool $updateSess wheather to update in session * @return bool */ public function isAllowed($updateSess = false) { $ns = $this->clause[0]['value']; $xid = $this->clause[1]['value']; $rgroup = self::$conf['namespaces'][$ns]['requiredgroup']; // see wheather user already voted in this session $sess = $this->sess->get(__CLASS__ . ':rated:' . $this->uid); if (!is_array($sess)) { $sess = array(); } if (!isset($sess[$ns])) { $sess[$ns] = array(); } if (isset($sess[$ns][$xid])) { return false; } $sess[$ns][$xid] = true; if ($updateSess) { $this->sess->set(__CLASS__ . ':rated:' . $this->uid, $sess); } // check permissions if (self::GROUP_ANON == $rgroup) { return true; } if (0 == $this->uid) { return false; } // check database for old ratings $old = $this->table->get('rating', null, $this->uid, $this->clause); if (!empty($old)) { return false; } if (empty($rgroup)) { return true; } if (in_array($rgroup, $this->uGroups)) { return true; } return false; } /** * Get rating of item * * Get total number of rates, average as well as min and max created timestamp * @return array */ public function get() { $table = $this->query->getTableInfo('rating'); $where = array(); $this->query->clause2Where('rating', $this->clause, $where); $query = array('SELECT count(*) AS total, avg(value) AS average, min(created) AS createdmin, max(created) AS createdmax'); $query[] = 'FROM ' . $table['table']; $query[] = 'WHERE ' . implode(' AND ', $where); $rating = $this->query->query($query); if (empty($rating)) { $rating = array( array( 'total' => 0, 'average' => 0, 'createdmin' => '0000-00-00 00:00:00', 'createdmax' => '0000-00-00 00:00:00' ) ); } $rating = $rating[0]; $rating['average'] = round($rating['average'], 2); $rating['average_round'] = round($rating['average']); $namespace = $this->clause[0]['value']; $values = self::$conf['namespaces'][$namespace]['values']; for ($i = 1; $i <= $rating['average_round']; ++$i) { if (!in_array($i, $values)) { continue; } $rating['rating_' . $i] = 1; } return $rating; } /** * Get best rated records for namespace * * Select items from table defined by namespace. Select only records with a minimum * number of rates. Also order by average rating value to get the best 10 records. * * The optional clause allows to e.g. select the best blog article of a specific category * or whatsoever. * * @param array $clause * @param int $limit * @return array */ public function getBest($clause = array(), $limit = 10) { if (empty($this->clause[0]['value'])) { WBClass::load('WBException_Call'); throw new WBException_Call('There is no namespace set, yet. Use setNamespace() first.', 1, __CLASS__); } $namespace = $this->clause[0]['value']; $clause[] = array( 'field' => $this->clause[0]['field'], 'table' => 'rating', 'value' => $namespace ); $options = array( 'join' => array( array( 'table' => 'rating', 'onleft' => $this->table->getIdentifier($namespace, true), 'onright' => 'xid' ) ), 'column'=> array( '*', array( 'table' => 'rating', 'field' => 'xid', 'function' => 'count', 'as' => 'total' ), array( 'table' => 'rating', 'field' => 'value', 'function' => 'avg', 'as' => 'average' ) ), 'order' => array( array( 'table' => 'rating', 'field' => 'value', 'function' => 'avg', 'asc' => 0 ), array( 'table' => 'rating', 'field' => 'value', 'function' => 'count', 'asc' => 0 ), ), 'groupby' => array( array( 'table' => 'rating', 'field' => 'xid', 'having' => 'count(xid) >= ' . intval(self::$conf['namespaces'][$namespace]['minrates']) ) ), 'limit' => 10 ); if ($this->mandator->isEnabled()) { $primary = $this->table->getIdentifier($namespace); if (is_array($primary) && in_array($this->mandator->getIdentifier(), $primary)) { $options['join'][0] = array( 'table' => 'rating', 'on' => array( array( 'onleft' => $this->mandator->getIdentifier(), 'onright' => $this->mandator->getIdentifier() ), array( 'onleft' => $this->table->getIdentifier($namespace, true), 'onright' => 'xid' ) ) ); } } return $this->table->get($namespace, null, null, $clause, $options); } }