prefix . 'entry`(id, guid, title, author, content_bin, link, date, is_read, is_favorite, id_feed, tags) ' . 'VALUES(?, ?, ?, ?, COMPRESS(?), ?, ?, ?, ?, ?, ?)'; $stm = $this->bd->prepare ($sql); $values = array ( $valuesTmp['id'], substr($valuesTmp['guid'], 0, 760), substr($valuesTmp['title'], 0, 255), substr($valuesTmp['author'], 0, 255), $valuesTmp['content'], substr($valuesTmp['link'], 0, 1023), $valuesTmp['date'], $valuesTmp['is_read'], $valuesTmp['is_favorite'], $valuesTmp['id_feed'], substr($valuesTmp['tags'], 0, 1023), ); if ($stm && $stm->execute ($values)) { return $this->bd->lastInsertId(); } else { $info = $stm->errorInfo(); if ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries Minz_Log::record ('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title'], Minz_Log::ERROR); } /*else { Minz_Log::record ('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title'], Minz_Log::DEBUG); }*/ return false; } } public function markFavorite ($id, $is_favorite = true) { $sql = 'UPDATE `' . $this->prefix . 'entry` e ' . 'SET e.is_favorite = ? ' . 'WHERE e.id=?'; $values = array ($is_favorite ? 1 : 0, $id); $stm = $this->bd->prepare ($sql); if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { $info = $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); return false; } } public function markRead ($id, $is_read = true) { $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' . 'SET e.is_read = ?,' . 'f.cache_nbUnreads=f.cache_nbUnreads' . ($is_read ? '-' : '+') . '1 ' . 'WHERE e.id=?'; $values = array ($is_read ? 1 : 0, $id); $stm = $this->bd->prepare ($sql); if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { $info = $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); return false; } } public function markReadEntries ($idMax = 0, $favorites = false) { if ($idMax === 0) { $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' . 'SET e.is_read = 1, f.cache_nbUnreads=0 ' . 'WHERE e.is_read = 0 AND '; if ($favorites) { $sql .= 'e.is_favorite = 1'; } else { $sql .= 'f.priority > 0'; } $stm = $this->bd->prepare ($sql); if ($stm && $stm->execute ()) { return $stm->rowCount(); } else { $info = $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); return false; } } else { $this->bd->beginTransaction (); $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' . 'SET e.is_read = 1 ' . 'WHERE e.is_read = 0 AND e.id <= ? AND '; if ($favorites) { $sql .= 'e.is_favorite = 1'; } else { $sql .= 'f.priority > 0'; } $values = array ($idMax); $stm = $this->bd->prepare ($sql); if (!($stm && $stm->execute ($values))) { $info = $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack (); return false; } $affected = $stm->rowCount(); if ($affected > 0) { $sql = 'UPDATE `' . $this->prefix . 'feed` f ' . 'LEFT OUTER JOIN (' . 'SELECT e.id_feed, ' . 'COUNT(*) AS nbUnreads ' . 'FROM `' . $this->prefix . 'entry` e ' . 'WHERE e.is_read = 0 ' . 'GROUP BY e.id_feed' . ') x ON x.id_feed=f.id ' . 'SET f.cache_nbUnreads=COALESCE(x.nbUnreads, 0)'; $stm = $this->bd->prepare ($sql); if (!($stm && $stm->execute ())) { $info = $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack (); return false; } } $this->bd->commit (); return $affected; } } public function markReadCat ($id, $idMax = 0) { if ($idMax === 0) { $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' . 'SET e.is_read = 1, f.cache_nbUnreads=0 ' . 'WHERE f.category = ? AND e.is_read = 0'; $values = array ($id); $stm = $this->bd->prepare ($sql); if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { $info = $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); return false; } } else { $this->bd->beginTransaction (); $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' . 'SET e.is_read = 1 ' . 'WHERE f.category = ? AND e.is_read = 0 AND e.id <= ?'; $values = array ($id, $idMax); $stm = $this->bd->prepare ($sql); if (!($stm && $stm->execute ($values))) { $info = $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack (); return false; } $affected = $stm->rowCount(); if ($affected > 0) { $sql = 'UPDATE `' . $this->prefix . 'feed` f ' . 'LEFT OUTER JOIN (' . 'SELECT e.id_feed, ' . 'COUNT(*) AS nbUnreads ' . 'FROM `' . $this->prefix . 'entry` e ' . 'WHERE e.is_read = 0 ' . 'GROUP BY e.id_feed' . ') x ON x.id_feed=f.id ' . 'SET f.cache_nbUnreads=COALESCE(x.nbUnreads, 0) ' . 'WHERE f.category = ?'; $values = array ($id); $stm = $this->bd->prepare ($sql); if (!($stm && $stm->execute ($values))) { $info = $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack (); return false; } } $this->bd->commit (); return $affected; } } public function markReadFeed ($id, $idMax = 0) { if ($idMax === 0) { $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' . 'SET e.is_read = 1, f.cache_nbUnreads=0 ' . 'WHERE f.id=? AND e.is_read = 0'; $values = array ($id); $stm = $this->bd->prepare ($sql); if ($stm && $stm->execute ($values)) { return $stm->rowCount(); } else { $info = $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); return false; } } else { $this->bd->beginTransaction (); $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id ' . 'SET e.is_read = 1 ' . 'WHERE f.id=? AND e.is_read = 0 AND e.id <= ?'; $values = array ($id, $idMax); $stm = $this->bd->prepare ($sql); if (!($stm && $stm->execute ($values))) { $info = $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack (); return false; } $affected = $stm->rowCount(); if ($affected > 0) { $sql = 'UPDATE `' . $this->prefix . 'feed` f ' . 'SET f.cache_nbUnreads=f.cache_nbUnreads-' . $affected . ' WHERE f.id=?'; $values = array ($id); $stm = $this->bd->prepare ($sql); if (!($stm && $stm->execute ($values))) { $info = $stm->errorInfo(); Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR); $this->bd->rollBack (); return false; } } $this->bd->commit (); return $affected; } } public function searchByGuid ($feed_id, $id) { // un guid est unique pour un flux donné $sql = 'SELECT id, guid, title, author, UNCOMPRESS(content_bin) AS content, link, date, is_read, is_favorite, id_feed, tags ' . 'FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND guid=?'; $stm = $this->bd->prepare ($sql); $values = array ( $feed_id, $id ); $stm->execute ($values); $res = $stm->fetchAll (PDO::FETCH_ASSOC); $entries = HelperEntry::daoToEntry ($res); return isset ($entries[0]) ? $entries[0] : false; } public function searchById ($id) { $sql = 'SELECT id, guid, title, author, UNCOMPRESS(content_bin) AS content, link, date, is_read, is_favorite, id_feed, tags ' . 'FROM `' . $this->prefix . 'entry` WHERE id=?'; $stm = $this->bd->prepare ($sql); $values = array ($id); $stm->execute ($values); $res = $stm->fetchAll (PDO::FETCH_ASSOC); $entries = HelperEntry::daoToEntry ($res); return isset ($entries[0]) ? $entries[0] : false; } public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { $where = ''; $values = array(); switch ($type) { case 'a': $where .= 'priority > 0 '; break; case 's': $where .= 'is_favorite = 1 '; break; case 'c': $where .= 'category = ? '; $values[] = intval($id); break; case 'f': $where .= 'id_feed = ? '; $values[] = intval($id); break; default: throw new FreshRSS_EntriesGetter_Exception ('Bad type in Entry->listByType: [' . $type . ']!'); } switch ($state) { case 'all': break; case 'not_read': $where .= 'AND is_read = 0 '; break; case 'read': $where .= 'AND is_read = 1 '; break; default: throw new FreshRSS_EntriesGetter_Exception ('Bad state in Entry->listByType: [' . $state . ']!'); } switch ($order) { case 'DESC': case 'ASC': break; default: throw new FreshRSS_EntriesGetter_Exception ('Bad order in Entry->listByType: [' . $order . ']!'); } if ($firstId !== '') { $where .= 'AND e.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; } if ($date_min > 0) { $where .= 'AND (e.id >= ' . $date_min . '000000 OR e.is_favorite = 1 OR f.keep_history = 1) '; } $terms = array_unique(explode(' ', trim($filter))); sort($terms); //Put #tags first $having = ''; foreach ($terms as $word) { if (!empty($word)) { if ($word[0] === '#' && isset($word[1])) { $having .= 'AND tags LIKE ? '; $values[] = '%' . $word .'%'; } elseif (!empty($word)) { $having .= 'AND (e.title LIKE ? OR content LIKE ?) '; $values[] = '%' . $word .'%'; $values[] = '%' . $word .'%'; } } } $sql = 'SELECT e.id, e.guid, e.title, e.author, UNCOMPRESS(e.content_bin) AS content, e.link, e.date, e.is_read, e.is_favorite, e.id_feed, e.tags ' . 'FROM `' . $this->prefix . 'entry` e ' . 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id WHERE ' . $where . (empty($having) ? '' : 'HAVING' . substr($having, 3)) . 'ORDER BY e.id ' . $order; if ($limit > 0) { $sql .= ' LIMIT ' . $limit; //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ } $stm = $this->bd->prepare ($sql); $stm->execute ($values); return HelperEntry::daoToEntry ($stm->fetchAll (PDO::FETCH_ASSOC)); } public function listLastGuidsByFeed($id, $n) { $sql = 'SELECT guid FROM `' . $this->prefix . 'entry` WHERE id_feed=? ORDER BY id DESC LIMIT ' . intval($n); $stm = $this->bd->prepare ($sql); $values = array ($id); $stm->execute ($values); return $stm->fetchAll (PDO::FETCH_COLUMN, 0); } public function countUnreadRead () { $sql = 'SELECT COUNT(e.id) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id WHERE priority > 0' . ' UNION SELECT COUNT(e.id) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id WHERE priority > 0 AND is_read = 0'; $stm = $this->bd->prepare ($sql); $stm->execute (); $res = $stm->fetchAll (PDO::FETCH_COLUMN, 0); $all = empty($res[0]) ? 0 : $res[0]; $unread = empty($res[1]) ? 0 : $res[1]; return array('all' => $all, 'unread' => $unread, 'read' => $all - $unread); } public function count ($minPriority = null) { $sql = 'SELECT COUNT(e.id) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id'; if ($minPriority !== null) { $sql = ' WHERE priority > ' . intval($minPriority); } $stm = $this->bd->prepare ($sql); $stm->execute (); $res = $stm->fetchAll (PDO::FETCH_COLUMN, 0); return $res[0]; } public function countNotRead ($minPriority = null) { $sql = 'SELECT COUNT(e.id) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id WHERE is_read = 0'; if ($minPriority !== null) { $sql = ' AND priority > ' . intval($minPriority); } $stm = $this->bd->prepare ($sql); $stm->execute (); $res = $stm->fetchAll (PDO::FETCH_COLUMN, 0); return $res[0]; } public function countUnreadReadFavorites () { $sql = 'SELECT COUNT(id) FROM `' . $this->prefix . 'entry` WHERE is_favorite=1' . ' UNION SELECT COUNT(id) FROM `' . $this->prefix . 'entry` WHERE is_favorite=1 AND is_read = 0'; $stm = $this->bd->prepare ($sql); $stm->execute (); $res = $stm->fetchAll (PDO::FETCH_COLUMN, 0); $all = empty($res[0]) ? 0 : $res[0]; $unread = empty($res[1]) ? 0 : $res[1]; return array('all' => $all, 'unread' => $unread, 'read' => $all - $unread); } public function optimizeTable() { $sql = 'OPTIMIZE TABLE `' . $this->prefix . 'entry`'; $stm = $this->bd->prepare ($sql); $stm->execute (); } } class HelperEntry { public static function daoToEntry ($listDAO) { $list = array (); if (!is_array ($listDAO)) { $listDAO = array ($listDAO); } foreach ($listDAO as $key => $dao) { $entry = new FreshRSS_Entry ( $dao['id_feed'], $dao['guid'], $dao['title'], $dao['author'], $dao['content'], $dao['link'], $dao['date'], $dao['is_read'], $dao['is_favorite'], $dao['tags'] ); if (isset ($dao['id'])) { $entry->_id ($dao['id']); } $list[] = $entry; } unset ($listDAO); return $list; } }