FeedDAO.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. <?php
  2. class FreshRSS_FeedDAO extends Minz_ModelPdo {
  3. public function addFeed ($valuesTmp) {
  4. $sql = 'INSERT INTO `' . $this->prefix . 'feed` (url, category, name, website, description, lastUpdate, priority, httpAuth, error, keep_history) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, -2)';
  5. $stm = $this->bd->prepare ($sql);
  6. $values = array (
  7. substr($valuesTmp['url'], 0, 511),
  8. $valuesTmp['category'],
  9. substr($valuesTmp['name'], 0, 255),
  10. substr($valuesTmp['website'], 0, 255),
  11. substr($valuesTmp['description'], 0, 1023),
  12. $valuesTmp['lastUpdate'],
  13. base64_encode ($valuesTmp['httpAuth']),
  14. );
  15. if ($stm && $stm->execute ($values)) {
  16. return $this->bd->lastInsertId();
  17. } else {
  18. $info = $stm->errorInfo();
  19. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  20. return false;
  21. }
  22. }
  23. public function updateFeed ($id, $valuesTmp) {
  24. $set = '';
  25. foreach ($valuesTmp as $key => $v) {
  26. $set .= $key . '=?, ';
  27. if ($key == 'httpAuth') {
  28. $valuesTmp[$key] = base64_encode ($v);
  29. }
  30. }
  31. $set = substr ($set, 0, -2);
  32. $sql = 'UPDATE `' . $this->prefix . 'feed` SET ' . $set . ' WHERE id=?';
  33. $stm = $this->bd->prepare ($sql);
  34. foreach ($valuesTmp as $v) {
  35. $values[] = $v;
  36. }
  37. $values[] = $id;
  38. if ($stm && $stm->execute ($values)) {
  39. return $stm->rowCount();
  40. } else {
  41. $info = $stm->errorInfo();
  42. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  43. return false;
  44. }
  45. }
  46. public function updateLastUpdate ($id, $inError = 0) {
  47. $sql = 'UPDATE `' . $this->prefix . 'feed` f ' //2 sub-requests with FOREIGN KEY(e.id_feed), INDEX(e.is_read) faster than 1 request with GROUP BY or CASE
  48. . 'SET f.cache_nbEntries=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=f.id),'
  49. . 'f.cache_nbUnreads=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=f.id AND e2.is_read=0),'
  50. . 'lastUpdate=?, error=? '
  51. . 'WHERE f.id=?';
  52. $stm = $this->bd->prepare ($sql);
  53. $values = array (
  54. time (),
  55. $inError,
  56. $id,
  57. );
  58. if ($stm && $stm->execute ($values)) {
  59. return $stm->rowCount();
  60. } else {
  61. $info = $stm->errorInfo();
  62. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  63. return false;
  64. }
  65. }
  66. public function changeCategory ($idOldCat, $idNewCat) {
  67. $catDAO = new FreshRSS_CategoryDAO ();
  68. $newCat = $catDAO->searchById ($idNewCat);
  69. if (!$newCat) {
  70. $newCat = $catDAO->getDefault ();
  71. }
  72. $sql = 'UPDATE `' . $this->prefix . 'feed` SET category=? WHERE category=?';
  73. $stm = $this->bd->prepare ($sql);
  74. $values = array (
  75. $newCat->id (),
  76. $idOldCat
  77. );
  78. if ($stm && $stm->execute ($values)) {
  79. return $stm->rowCount();
  80. } else {
  81. $info = $stm->errorInfo();
  82. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  83. return false;
  84. }
  85. }
  86. public function deleteFeed ($id) {
  87. /*//For MYISAM (MySQL 5.5-) without FOREIGN KEY
  88. $sql = 'DELETE FROM `' . $this->prefix . 'entry` WHERE id_feed=?';
  89. $stm = $this->bd->prepare ($sql);
  90. $values = array ($id);
  91. if (!($stm && $stm->execute ($values))) {
  92. $info = $stm->errorInfo();
  93. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  94. return false;
  95. }*/
  96. $sql = 'DELETE FROM `' . $this->prefix . 'feed` WHERE id=?';
  97. $stm = $this->bd->prepare ($sql);
  98. $values = array ($id);
  99. if ($stm && $stm->execute ($values)) {
  100. return $stm->rowCount();
  101. } else {
  102. $info = $stm->errorInfo();
  103. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  104. return false;
  105. }
  106. }
  107. public function deleteFeedByCategory ($id) {
  108. /*//For MYISAM (MySQL 5.5-) without FOREIGN KEY
  109. $sql = 'DELETE FROM `' . $this->prefix . 'entry` e '
  110. . 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
  111. . 'WHERE f.category=?';
  112. $stm = $this->bd->prepare ($sql);
  113. $values = array ($id);
  114. if (!($stm && $stm->execute ($values))) {
  115. $info = $stm->errorInfo();
  116. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  117. return false;
  118. }*/
  119. $sql = 'DELETE FROM `' . $this->prefix . 'feed` WHERE category=?';
  120. $stm = $this->bd->prepare ($sql);
  121. $values = array ($id);
  122. if ($stm && $stm->execute ($values)) {
  123. return $stm->rowCount();
  124. } else {
  125. $info = $stm->errorInfo();
  126. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  127. return false;
  128. }
  129. }
  130. public function searchById ($id) {
  131. $sql = 'SELECT * FROM `' . $this->prefix . 'feed` WHERE id=?';
  132. $stm = $this->bd->prepare ($sql);
  133. $values = array ($id);
  134. $stm->execute ($values);
  135. $res = $stm->fetchAll (PDO::FETCH_ASSOC);
  136. $feed = self::daoToFeed ($res);
  137. if (isset ($feed[$id])) {
  138. return $feed[$id];
  139. } else {
  140. return false;
  141. }
  142. }
  143. public function searchByUrl ($url) {
  144. $sql = 'SELECT * FROM `' . $this->prefix . 'feed` WHERE url=?';
  145. $stm = $this->bd->prepare ($sql);
  146. $values = array ($url);
  147. $stm->execute ($values);
  148. $res = $stm->fetchAll (PDO::FETCH_ASSOC);
  149. $feed = current (self::daoToFeed ($res));
  150. if (isset ($feed)) {
  151. return $feed;
  152. } else {
  153. return false;
  154. }
  155. }
  156. public function listFeeds () {
  157. $sql = 'SELECT * FROM `' . $this->prefix . 'feed` ORDER BY name';
  158. $stm = $this->bd->prepare ($sql);
  159. $stm->execute ();
  160. return self::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC));
  161. }
  162. public function listFeedsOrderUpdate () {
  163. $sql = 'SELECT id, name, url, pathEntries, httpAuth, keep_history FROM `' . $this->prefix . 'feed` ORDER BY lastUpdate';
  164. $stm = $this->bd->prepare ($sql);
  165. $stm->execute ();
  166. return self::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC));
  167. }
  168. public function listByCategory ($cat) {
  169. $sql = 'SELECT * FROM `' . $this->prefix . 'feed` WHERE category=? ORDER BY name';
  170. $stm = $this->bd->prepare ($sql);
  171. $values = array ($cat);
  172. $stm->execute ($values);
  173. return self::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC));
  174. }
  175. public function countEntries ($id) {
  176. $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'entry` WHERE id_feed=?';
  177. $stm = $this->bd->prepare ($sql);
  178. $values = array ($id);
  179. $stm->execute ($values);
  180. $res = $stm->fetchAll (PDO::FETCH_ASSOC);
  181. return $res[0]['count'];
  182. }
  183. public function countNotRead ($id) {
  184. $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND is_read=0';
  185. $stm = $this->bd->prepare ($sql);
  186. $values = array ($id);
  187. $stm->execute ($values);
  188. $res = $stm->fetchAll (PDO::FETCH_ASSOC);
  189. return $res[0]['count'];
  190. }
  191. public function updateCachedValues () { //For one single feed, call updateLastUpdate($id)
  192. $sql = 'UPDATE `' . $this->prefix . 'feed` f '
  193. . 'INNER JOIN ('
  194. . 'SELECT e.id_feed, '
  195. . 'COUNT(CASE WHEN e.is_read = 0 THEN 1 END) AS nbUnreads, '
  196. . 'COUNT(e.id) AS nbEntries '
  197. . 'FROM `' . $this->prefix . 'entry` e '
  198. . 'GROUP BY e.id_feed'
  199. . ') x ON x.id_feed=f.id '
  200. . 'SET f.cache_nbEntries=x.nbEntries, f.cache_nbUnreads=x.nbUnreads';
  201. $stm = $this->bd->prepare ($sql);
  202. $values = array ($feed_id);
  203. if ($stm && $stm->execute ($values)) {
  204. return $stm->rowCount();
  205. } else {
  206. $info = $stm->errorInfo();
  207. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  208. return false;
  209. }
  210. }
  211. public function truncate ($id) {
  212. $sql = 'DELETE e.* FROM `' . $this->prefix . 'entry` e WHERE e.id_feed=?';
  213. $stm = $this->bd->prepare($sql);
  214. $values = array($id);
  215. $this->bd->beginTransaction ();
  216. if (!($stm && $stm->execute ($values))) {
  217. $info = $stm->errorInfo();
  218. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  219. $this->bd->rollBack ();
  220. return false;
  221. }
  222. $affected = $stm->rowCount();
  223. $sql = 'UPDATE `' . $this->prefix . 'feed` f '
  224. . 'SET f.cache_nbEntries=0, f.cache_nbUnreads=0 WHERE f.id=?';
  225. $values = array ($id);
  226. $stm = $this->bd->prepare ($sql);
  227. if (!($stm && $stm->execute ($values))) {
  228. $info = $stm->errorInfo();
  229. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  230. $this->bd->rollBack ();
  231. return false;
  232. }
  233. $this->bd->commit ();
  234. return $affected;
  235. }
  236. public function cleanOldEntries ($id, $date_min, $keep = 15) { //Remember to call updateLastUpdate($id) just after
  237. $sql = 'DELETE e.* FROM `' . $this->prefix . 'entry` e '
  238. . 'WHERE e.id_feed = :id_feed AND e.id <= :id_max AND e.is_favorite = 0 AND e.id NOT IN '
  239. . '(SELECT id FROM (SELECT e2.id FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed = :id_feed ORDER BY id DESC LIMIT :keep) keep)'; //Double select because of: MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
  240. $stm = $this->bd->prepare ($sql);
  241. $id_max = intval($date_min) . '000000';
  242. $stm->bindParam(':id_feed', $id, PDO::PARAM_INT);
  243. $stm->bindParam(':id_max', $id_max, PDO::PARAM_INT);
  244. $stm->bindParam(':keep', $keep, PDO::PARAM_INT);
  245. if ($stm && $stm->execute ()) {
  246. return $stm->rowCount();
  247. } else {
  248. $info = $stm->errorInfo();
  249. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  250. return false;
  251. }
  252. }
  253. public static function daoToFeed ($listDAO, $catID = null) {
  254. $list = array ();
  255. if (!is_array ($listDAO)) {
  256. $listDAO = array ($listDAO);
  257. }
  258. foreach ($listDAO as $key => $dao) {
  259. if (!isset ($dao['name'])) {
  260. continue;
  261. }
  262. if (isset ($dao['id'])) {
  263. $key = $dao['id'];
  264. }
  265. if ($catID === null) {
  266. $category = isset($dao['category']) ? $dao['category'] : 0;
  267. } else {
  268. $category = $catID ;
  269. }
  270. $myFeed = new FreshRSS_Feed(isset($dao['url']) ? $dao['url'] : '', false);
  271. $myFeed->_category($category);
  272. $myFeed->_name($dao['name']);
  273. $myFeed->_website(isset($dao['website']) ? $dao['website'] : '', false);
  274. $myFeed->_description(isset($dao['description']) ? $dao['description'] : '');
  275. $myFeed->_lastUpdate(isset($dao['lastUpdate']) ? $dao['lastUpdate'] : 0);
  276. $myFeed->_priority(isset($dao['priority']) ? $dao['priority'] : 10);
  277. $myFeed->_pathEntries(isset($dao['pathEntries']) ? $dao['pathEntries'] : '');
  278. $myFeed->_httpAuth(isset($dao['httpAuth']) ? base64_decode ($dao['httpAuth']) : '');
  279. $myFeed->_error(isset($dao['error']) ? $dao['error'] : 0);
  280. $myFeed->_keepHistory(isset($dao['keep_history']) ? $dao['keep_history'] : -2);
  281. $myFeed->_nbNotRead(isset($dao['cache_nbUnreads']) ? $dao['cache_nbUnreads'] : 0);
  282. $myFeed->_nbEntries(isset($dao['cache_nbEntries']) ? $dao['cache_nbEntries'] : 0);
  283. if (isset ($dao['id'])) {
  284. $myFeed->_id ($dao['id']);
  285. }
  286. $list[$key] = $myFeed;
  287. }
  288. return $list;
  289. }
  290. }