EntryDAO.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. <?php
  2. class FreshRSS_EntryDAO extends Minz_ModelPdo {
  3. public function addEntry ($valuesTmp) {
  4. $sql = 'INSERT INTO `' . $this->prefix . 'entry`(id, guid, title, author, content_bin, link, date, is_read, is_favorite, id_feed, tags) '
  5. . 'VALUES(?, ?, ?, ?, COMPRESS(?), ?, ?, ?, ?, ?, ?)';
  6. $stm = $this->bd->prepare ($sql);
  7. $values = array (
  8. $valuesTmp['id'],
  9. substr($valuesTmp['guid'], 0, 760),
  10. substr($valuesTmp['title'], 0, 255),
  11. substr($valuesTmp['author'], 0, 255),
  12. $valuesTmp['content'],
  13. substr($valuesTmp['link'], 0, 1023),
  14. $valuesTmp['date'],
  15. $valuesTmp['is_read'] ? 1 : 0,
  16. $valuesTmp['is_favorite'] ? 1 : 0,
  17. $valuesTmp['id_feed'],
  18. substr($valuesTmp['tags'], 0, 1023),
  19. );
  20. if ($stm && $stm->execute ($values)) {
  21. return $this->bd->lastInsertId();
  22. } else {
  23. $info = $stm->errorInfo();
  24. if ((int)($info[0] / 1000) !== 23) { //Filter out "SQLSTATE Class code 23: Constraint Violation" because of expected duplicate entries
  25. Minz_Log::record ('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
  26. . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title'], Minz_Log::ERROR);
  27. } /*else {
  28. Minz_Log::record ('SQL error ' . $info[0] . ': ' . $info[1] . ' ' . $info[2]
  29. . ' while adding entry in feed ' . $valuesTmp['id_feed'] . ' with title: ' . $valuesTmp['title'], Minz_Log::DEBUG);
  30. }*/
  31. return false;
  32. }
  33. }
  34. public function addEntryObject($entry, $conf, $feedHistory) {
  35. $existingGuids = array_fill_keys(
  36. $this->listLastGuidsByFeed($entry->feed(), 20), 1
  37. );
  38. $nb_month_old = max($conf->old_entries, 1);
  39. $date_min = time() - (3600 * 24 * 30 * $nb_month_old);
  40. $eDate = $entry->date(true);
  41. if ($feedHistory == -2) {
  42. $feedHistory = $conf->keep_history_default;
  43. }
  44. if (!isset($existingGuids[$entry->guid()]) &&
  45. ($feedHistory != 0 || $eDate >= $date_min)) {
  46. $values = $entry->toArray();
  47. $useDeclaredDate = empty($existingGuids);
  48. $values['id'] = ($useDeclaredDate || $eDate < $date_min) ?
  49. min(time(), $eDate) . uSecString() :
  50. uTimeString();
  51. return $this->addEntry($values);
  52. }
  53. // We don't return Entry object to avoid a research in DB
  54. return -1;
  55. }
  56. public function markFavorite($ids, $is_favorite = true) {
  57. if (!is_array($ids)) {
  58. $ids = array($ids);
  59. }
  60. $sql = 'UPDATE `' . $this->prefix . 'entry` e '
  61. . 'SET e.is_favorite = ? '
  62. . 'WHERE e.id IN (' . str_repeat('?,', count($ids) - 1). '?)';
  63. $values = array ($is_favorite ? 1 : 0);
  64. $values = array_merge($values, $ids);
  65. $stm = $this->bd->prepare ($sql);
  66. if ($stm && $stm->execute ($values)) {
  67. return $stm->rowCount();
  68. } else {
  69. $info = $stm->errorInfo();
  70. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  71. return false;
  72. }
  73. }
  74. public function markRead($ids, $is_read = true) {
  75. if (is_array($ids)) {
  76. if (count($ids) < 6) { //Speed heuristics
  77. $affected = 0;
  78. foreach ($ids as $id) {
  79. $affected += $this->markRead($id, $is_read);
  80. }
  81. return $affected;
  82. }
  83. $this->bd->beginTransaction();
  84. $sql = 'UPDATE `' . $this->prefix . 'entry` e '
  85. . 'SET e.is_read = ? '
  86. . 'WHERE e.id IN (' . str_repeat('?,', count($ids) - 1). '?)';
  87. $values = array($is_read ? 1 : 0);
  88. $values = array_merge($values, $ids);
  89. $stm = $this->bd->prepare($sql);
  90. if (!($stm && $stm->execute($values))) {
  91. $info = $stm->errorInfo();
  92. Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
  93. $this->bd->rollBack();
  94. return false;
  95. }
  96. $affected = $stm->rowCount();
  97. if ($affected > 0) {
  98. $sql = 'UPDATE `' . $this->prefix . 'feed` f '
  99. . 'INNER JOIN ('
  100. . 'SELECT e.id_feed, '
  101. . 'COUNT(CASE WHEN e.is_read = 0 THEN 1 END) AS nbUnreads, '
  102. . 'COUNT(e.id) AS nbEntries '
  103. . 'FROM `' . $this->prefix . 'entry` e '
  104. . 'GROUP BY e.id_feed'
  105. . ') x ON x.id_feed=f.id '
  106. . 'SET f.cache_nbEntries=x.nbEntries, f.cache_nbUnreads=x.nbUnreads';
  107. $stm = $this->bd->prepare($sql);
  108. if (!($stm && $stm->execute())) {
  109. $info = $stm->errorInfo();
  110. Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
  111. $this->bd->rollBack();
  112. return false;
  113. }
  114. }
  115. $this->bd->commit();
  116. return $affected;
  117. } else {
  118. $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
  119. . 'SET e.is_read = ?,'
  120. . 'f.cache_nbUnreads=f.cache_nbUnreads' . ($is_read ? '-' : '+') . '1 '
  121. . 'WHERE e.id=?';
  122. $values = array($is_read ? 1 : 0, $ids);
  123. $stm = $this->bd->prepare($sql);
  124. if ($stm && $stm->execute($values)) {
  125. return $stm->rowCount();
  126. } else {
  127. $info = $stm->errorInfo();
  128. Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
  129. return false;
  130. }
  131. }
  132. }
  133. public function markReadEntries ($idMax = 0, $onlyFavorites = false, $priorityMin = 0) {
  134. if ($idMax == 0) {
  135. $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
  136. . 'SET e.is_read = 1, f.cache_nbUnreads=0 '
  137. . 'WHERE e.is_read = 0';
  138. if ($onlyFavorites) {
  139. $sql .= ' AND e.is_favorite = 1';
  140. } elseif ($priorityMin >= 0) {
  141. $sql .= ' AND f.priority > ' . intval($priorityMin);
  142. }
  143. $stm = $this->bd->prepare ($sql);
  144. if ($stm && $stm->execute ()) {
  145. return $stm->rowCount();
  146. } else {
  147. $info = $stm->errorInfo();
  148. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  149. return false;
  150. }
  151. } else {
  152. $this->bd->beginTransaction ();
  153. $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
  154. . 'SET e.is_read = 1 '
  155. . 'WHERE e.is_read = 0 AND e.id <= ?';
  156. if ($onlyFavorites) {
  157. $sql .= ' AND e.is_favorite = 1';
  158. } elseif ($priorityMin >= 0) {
  159. $sql .= ' AND f.priority > ' . intval($priorityMin);
  160. }
  161. $values = array ($idMax);
  162. $stm = $this->bd->prepare ($sql);
  163. if (!($stm && $stm->execute ($values))) {
  164. $info = $stm->errorInfo();
  165. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  166. $this->bd->rollBack ();
  167. return false;
  168. }
  169. $affected = $stm->rowCount();
  170. if ($affected > 0) {
  171. $sql = 'UPDATE `' . $this->prefix . 'feed` f '
  172. . 'LEFT OUTER JOIN ('
  173. . 'SELECT e.id_feed, '
  174. . 'COUNT(*) AS nbUnreads '
  175. . 'FROM `' . $this->prefix . 'entry` e '
  176. . 'WHERE e.is_read = 0 '
  177. . 'GROUP BY e.id_feed'
  178. . ') x ON x.id_feed=f.id '
  179. . 'SET f.cache_nbUnreads=COALESCE(x.nbUnreads, 0)';
  180. $stm = $this->bd->prepare ($sql);
  181. if (!($stm && $stm->execute ())) {
  182. $info = $stm->errorInfo();
  183. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  184. $this->bd->rollBack ();
  185. return false;
  186. }
  187. }
  188. $this->bd->commit ();
  189. return $affected;
  190. }
  191. }
  192. public function markReadCat ($id, $idMax = 0) {
  193. if ($idMax == 0) {
  194. $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
  195. . 'SET e.is_read = 1, f.cache_nbUnreads=0 '
  196. . 'WHERE f.category = ? AND e.is_read = 0';
  197. $values = array ($id);
  198. $stm = $this->bd->prepare ($sql);
  199. if ($stm && $stm->execute ($values)) {
  200. return $stm->rowCount();
  201. } else {
  202. $info = $stm->errorInfo();
  203. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  204. return false;
  205. }
  206. } else {
  207. $this->bd->beginTransaction ();
  208. $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
  209. . 'SET e.is_read = 1 '
  210. . 'WHERE f.category = ? AND e.is_read = 0 AND e.id <= ?';
  211. $values = array ($id, $idMax);
  212. $stm = $this->bd->prepare ($sql);
  213. if (!($stm && $stm->execute ($values))) {
  214. $info = $stm->errorInfo();
  215. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  216. $this->bd->rollBack ();
  217. return false;
  218. }
  219. $affected = $stm->rowCount();
  220. if ($affected > 0) {
  221. $sql = 'UPDATE `' . $this->prefix . 'feed` f '
  222. . 'LEFT OUTER JOIN ('
  223. . 'SELECT e.id_feed, '
  224. . 'COUNT(*) AS nbUnreads '
  225. . 'FROM `' . $this->prefix . 'entry` e '
  226. . 'WHERE e.is_read = 0 '
  227. . 'GROUP BY e.id_feed'
  228. . ') x ON x.id_feed=f.id '
  229. . 'SET f.cache_nbUnreads=COALESCE(x.nbUnreads, 0) '
  230. . 'WHERE f.category = ?';
  231. $values = array ($id);
  232. $stm = $this->bd->prepare ($sql);
  233. if (!($stm && $stm->execute ($values))) {
  234. $info = $stm->errorInfo();
  235. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  236. $this->bd->rollBack ();
  237. return false;
  238. }
  239. }
  240. $this->bd->commit ();
  241. return $affected;
  242. }
  243. }
  244. public function markReadCatName($name, $idMax = 0) {
  245. if ($idMax == 0) {
  246. $sql = 'UPDATE `' . $this->prefix . 'entry` e '
  247. . 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
  248. . 'INNER JOIN `' . $this->prefix . 'category` c ON c.id = f.category '
  249. . 'SET e.is_read = 1, f.cache_nbUnreads=0 '
  250. . 'WHERE c.name = ?';
  251. $values = array($name);
  252. $stm = $this->bd->prepare($sql);
  253. if ($stm && $stm->execute($values)) {
  254. return $stm->rowCount();
  255. } else {
  256. $info = $stm->errorInfo();
  257. Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
  258. return false;
  259. }
  260. } else {
  261. $this->bd->beginTransaction();
  262. $sql = 'UPDATE `' . $this->prefix . 'entry` e '
  263. . 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
  264. . 'INNER JOIN `' . $this->prefix . 'category` c ON c.id = f.category '
  265. . 'SET e.is_read = 1 '
  266. . 'WHERE c.name = ? AND e.id <= ?';
  267. $values = array($name, $idMax);
  268. $stm = $this->bd->prepare($sql);
  269. if (!($stm && $stm->execute($values))) {
  270. $info = $stm->errorInfo();
  271. Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
  272. $this->bd->rollBack();
  273. return false;
  274. }
  275. $affected = $stm->rowCount();
  276. if ($affected > 0) {
  277. $sql = 'UPDATE `' . $this->prefix . 'feed` f '
  278. . 'LEFT OUTER JOIN ('
  279. . 'SELECT e.id_feed, '
  280. . 'COUNT(*) AS nbUnreads '
  281. . 'FROM `' . $this->prefix . 'entry` e '
  282. . 'WHERE e.is_read = 0 '
  283. . 'GROUP BY e.id_feed'
  284. . ') x ON x.id_feed=f.id '
  285. . 'INNER JOIN `' . $this->prefix . 'category` c ON c.id = f.category '
  286. . 'SET f.cache_nbUnreads=COALESCE(x.nbUnreads, 0) '
  287. . 'WHERE c.name = ?';
  288. $values = array($name);
  289. $stm = $this->bd->prepare($sql);
  290. if (!($stm && $stm->execute($values))) {
  291. $info = $stm->errorInfo();
  292. Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
  293. $this->bd->rollBack();
  294. return false;
  295. }
  296. }
  297. $this->bd->commit();
  298. return $affected;
  299. }
  300. }
  301. public function markReadFeed ($id, $idMax = 0) {
  302. if ($idMax == 0) {
  303. $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
  304. . 'SET e.is_read = 1, f.cache_nbUnreads=0 '
  305. . 'WHERE f.id=? AND e.is_read = 0';
  306. $values = array ($id);
  307. $stm = $this->bd->prepare ($sql);
  308. if ($stm && $stm->execute ($values)) {
  309. return $stm->rowCount();
  310. } else {
  311. $info = $stm->errorInfo();
  312. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  313. return false;
  314. }
  315. } else {
  316. $this->bd->beginTransaction ();
  317. $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
  318. . 'SET e.is_read = 1 '
  319. . 'WHERE f.id=? AND e.is_read = 0 AND e.id <= ?';
  320. $values = array ($id, $idMax);
  321. $stm = $this->bd->prepare ($sql);
  322. if (!($stm && $stm->execute ($values))) {
  323. $info = $stm->errorInfo();
  324. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  325. $this->bd->rollBack ();
  326. return false;
  327. }
  328. $affected = $stm->rowCount();
  329. if ($affected > 0) {
  330. $sql = 'UPDATE `' . $this->prefix . 'feed` f '
  331. . 'SET f.cache_nbUnreads=f.cache_nbUnreads-' . $affected
  332. . ' WHERE f.id=?';
  333. $values = array ($id);
  334. $stm = $this->bd->prepare ($sql);
  335. if (!($stm && $stm->execute ($values))) {
  336. $info = $stm->errorInfo();
  337. Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
  338. $this->bd->rollBack ();
  339. return false;
  340. }
  341. }
  342. $this->bd->commit ();
  343. return $affected;
  344. }
  345. }
  346. public function searchByGuid ($feed_id, $id) {
  347. // un guid est unique pour un flux donné
  348. $sql = 'SELECT id, guid, title, author, UNCOMPRESS(content_bin) AS content, link, date, is_read, is_favorite, id_feed, tags '
  349. . 'FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND guid=?';
  350. $stm = $this->bd->prepare ($sql);
  351. $values = array (
  352. $feed_id,
  353. $id
  354. );
  355. $stm->execute ($values);
  356. $res = $stm->fetchAll (PDO::FETCH_ASSOC);
  357. $entries = self::daoToEntry ($res);
  358. return isset ($entries[0]) ? $entries[0] : null;
  359. }
  360. public function searchById ($id) {
  361. $sql = 'SELECT id, guid, title, author, UNCOMPRESS(content_bin) AS content, link, date, is_read, is_favorite, id_feed, tags '
  362. . 'FROM `' . $this->prefix . 'entry` WHERE id=?';
  363. $stm = $this->bd->prepare ($sql);
  364. $values = array ($id);
  365. $stm->execute ($values);
  366. $res = $stm->fetchAll (PDO::FETCH_ASSOC);
  367. $entries = self::daoToEntry ($res);
  368. return isset ($entries[0]) ? $entries[0] : null;
  369. }
  370. private function sqlListWhere($type = 'a', $id = '', $state = null , $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) {
  371. if (!$state) {
  372. $state = FreshRSS_Configuration::STATE_ALL;
  373. }
  374. $where = '';
  375. $joinFeed = false;
  376. $values = array();
  377. switch ($type) {
  378. case 'a':
  379. $where .= 'f.priority > 0 ';
  380. $joinFeed = true;
  381. break;
  382. case 'c':
  383. $where .= 'f.category = ? ';
  384. $values[] = intval($id);
  385. $joinFeed = true;
  386. break;
  387. case 'f':
  388. $where .= 'e1.id_feed = ? ';
  389. $values[] = intval($id);
  390. break;
  391. case 'A':
  392. $where .= '1 ';
  393. break;
  394. default:
  395. throw new FreshRSS_EntriesGetter_Exception ('Bad type in Entry->listByType: [' . $type . ']!');
  396. }
  397. if ($state & FreshRSS_Configuration::STATE_NOT_READ) {
  398. if (!($state & FreshRSS_Configuration::STATE_READ)) {
  399. $where .= 'AND e1.is_read = 0 ';
  400. }
  401. }
  402. if ($state & FreshRSS_Configuration::STATE_READ) {
  403. if (!($state & FreshRSS_Configuration::STATE_NOT_READ)) {
  404. $where .= 'AND e1.is_read = 1 ';
  405. }
  406. }
  407. if ($state & FreshRSS_Configuration::STATE_NOT_FAVORITE) {
  408. if (!($state & FreshRSS_Configuration::STATE_FAVORITE)) {
  409. $where .= 'AND e1.is_favorite = 0 ';
  410. }
  411. }
  412. if ($state & FreshRSS_Configuration::STATE_FAVORITE) {
  413. if (!($state & FreshRSS_Configuration::STATE_NOT_FAVORITE)) {
  414. $where .= 'AND e1.is_favorite = 1 ';
  415. }
  416. }
  417. switch ($order) {
  418. case 'DESC':
  419. case 'ASC':
  420. break;
  421. default:
  422. throw new FreshRSS_EntriesGetter_Exception ('Bad order in Entry->listByType: [' . $order . ']!');
  423. }
  424. if ($firstId !== '') {
  425. $where .= 'AND e1.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' ';
  426. }
  427. if (($date_min > 0) && ($type !== 's')) {
  428. $where .= 'AND (e1.id >= ' . $date_min . '000000';
  429. if ($showOlderUnreadsorFavorites) { //Lax date constraint
  430. $where .= ' OR e1.is_read = 0 OR e1.is_favorite = 1 OR (f.keep_history <> 0';
  431. if (intval($keepHistoryDefault) === 0) {
  432. $where .= ' AND f.keep_history <> -2'; //default
  433. }
  434. $where .= ')';
  435. }
  436. $where .= ') ';
  437. $joinFeed = true;
  438. }
  439. $search = '';
  440. if ($filter !== '') {
  441. $filter = trim($filter);
  442. $filter = addcslashes($filter, '\\%_');
  443. if (stripos($filter, 'intitle:') === 0) {
  444. $filter = substr($filter, strlen('intitle:'));
  445. $intitle = true;
  446. } else {
  447. $intitle = false;
  448. }
  449. if (stripos($filter, 'inurl:') === 0) {
  450. $filter = substr($filter, strlen('inurl:'));
  451. $inurl = true;
  452. } else {
  453. $inurl = false;
  454. }
  455. if (stripos($filter, 'author:') === 0) {
  456. $filter = substr($filter, strlen('author:'));
  457. $author = true;
  458. } else {
  459. $author = false;
  460. }
  461. $terms = array_unique(explode(' ', $filter));
  462. sort($terms); //Put #tags first
  463. foreach ($terms as $word) {
  464. $word = trim($word);
  465. if (strlen($word) > 0) {
  466. if ($intitle) {
  467. $search .= 'AND e1.title LIKE ? ';
  468. $values[] = '%' . $word .'%';
  469. } elseif ($inurl) {
  470. $search .= 'AND CONCAT(e1.link, e1.guid) LIKE ? ';
  471. $values[] = '%' . $word .'%';
  472. } elseif ($author) {
  473. $search .= 'AND e1.author LIKE ? ';
  474. $values[] = '%' . $word .'%';
  475. } else {
  476. if ($word[0] === '#' && isset($word[1])) {
  477. $search .= 'AND e1.tags LIKE ? ';
  478. $values[] = '%' . $word .'%';
  479. } else {
  480. $search .= 'AND CONCAT(e1.title, UNCOMPRESS(e1.content_bin)) LIKE ? ';
  481. $values[] = '%' . $word .'%';
  482. }
  483. }
  484. }
  485. }
  486. }
  487. return array($values,
  488. 'SELECT e1.id FROM `' . $this->prefix . 'entry` e1 '
  489. . ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e1.id_feed = f.id ' : '')
  490. . 'WHERE ' . $where
  491. . $search
  492. . 'ORDER BY e1.id ' . $order
  493. . ($limit > 0 ? ' LIMIT ' . $limit : '')); //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/
  494. }
  495. public function listWhere($type = 'a', $id = '', $state = null, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) {
  496. list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault);
  497. $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 '
  498. . 'FROM `' . $this->prefix . 'entry` e '
  499. . 'INNER JOIN ('
  500. . $sql
  501. . ') e2 ON e2.id = e.id '
  502. . 'ORDER BY e.id ' . $order;
  503. $stm = $this->bd->prepare ($sql);
  504. $stm->execute ($values);
  505. return self::daoToEntry ($stm->fetchAll (PDO::FETCH_ASSOC));
  506. }
  507. public function listIdsWhere($type = 'a', $id = '', $state = null, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { //For API
  508. list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault);
  509. $stm = $this->bd->prepare($sql);
  510. $stm->execute($values);
  511. return $stm->fetchAll(PDO::FETCH_COLUMN, 0);
  512. }
  513. public function listLastGuidsByFeed($id, $n) {
  514. $sql = 'SELECT guid FROM `' . $this->prefix . 'entry` WHERE id_feed=? ORDER BY id DESC LIMIT ' . intval($n);
  515. $stm = $this->bd->prepare ($sql);
  516. $values = array ($id);
  517. $stm->execute ($values);
  518. return $stm->fetchAll (PDO::FETCH_COLUMN, 0);
  519. }
  520. public function countUnreadRead () {
  521. $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'
  522. . ' 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';
  523. $stm = $this->bd->prepare ($sql);
  524. $stm->execute ();
  525. $res = $stm->fetchAll (PDO::FETCH_COLUMN, 0);
  526. $all = empty($res[0]) ? 0 : $res[0];
  527. $unread = empty($res[1]) ? 0 : $res[1];
  528. return array('all' => $all, 'unread' => $unread, 'read' => $all - $unread);
  529. }
  530. public function count ($minPriority = null) {
  531. $sql = 'SELECT COUNT(e.id) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id';
  532. if ($minPriority !== null) {
  533. $sql = ' WHERE priority > ' . intval($minPriority);
  534. }
  535. $stm = $this->bd->prepare ($sql);
  536. $stm->execute ();
  537. $res = $stm->fetchAll (PDO::FETCH_COLUMN, 0);
  538. return $res[0];
  539. }
  540. public function countNotRead ($minPriority = null) {
  541. $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';
  542. if ($minPriority !== null) {
  543. $sql = ' AND priority > ' . intval($minPriority);
  544. }
  545. $stm = $this->bd->prepare ($sql);
  546. $stm->execute ();
  547. $res = $stm->fetchAll (PDO::FETCH_COLUMN, 0);
  548. return $res[0];
  549. }
  550. public function countUnreadReadFavorites () {
  551. $sql = 'SELECT COUNT(id) FROM `' . $this->prefix . 'entry` WHERE is_favorite=1'
  552. . ' UNION SELECT COUNT(id) FROM `' . $this->prefix . 'entry` WHERE is_favorite=1 AND is_read = 0';
  553. $stm = $this->bd->prepare ($sql);
  554. $stm->execute ();
  555. $res = $stm->fetchAll (PDO::FETCH_COLUMN, 0);
  556. $all = empty($res[0]) ? 0 : $res[0];
  557. $unread = empty($res[1]) ? 0 : $res[1];
  558. return array('all' => $all, 'unread' => $unread, 'read' => $all - $unread);
  559. }
  560. public function optimizeTable() {
  561. $sql = 'OPTIMIZE TABLE `' . $this->prefix . 'entry`';
  562. $stm = $this->bd->prepare ($sql);
  563. $stm->execute ();
  564. }
  565. public static function daoToEntry ($listDAO) {
  566. $list = array ();
  567. if (!is_array ($listDAO)) {
  568. $listDAO = array ($listDAO);
  569. }
  570. foreach ($listDAO as $key => $dao) {
  571. $entry = new FreshRSS_Entry (
  572. $dao['id_feed'],
  573. $dao['guid'],
  574. $dao['title'],
  575. $dao['author'],
  576. $dao['content'],
  577. $dao['link'],
  578. $dao['date'],
  579. $dao['is_read'],
  580. $dao['is_favorite'],
  581. $dao['tags']
  582. );
  583. if (isset ($dao['id'])) {
  584. $entry->_id ($dao['id']);
  585. }
  586. $list[] = $entry;
  587. }
  588. unset ($listDAO);
  589. return $list;
  590. }
  591. }