table(TABLE) ->eq('user_id', $user_id) ->eq('id', $item_id) ->save(array('status' => $status)); } function change_items_status($user_id, $current_status, $new_status) { if (! in_array($new_status, array(STATUS_READ, STATUS_UNREAD, STATUS_REMOVED))) { return false; } return Database::getInstance('db') ->table(TABLE) ->eq('user_id', $user_id) ->eq('status', $current_status) ->save(array('status' => $new_status)); } function change_item_ids_status($user_id, array $item_ids, $status) { if (! in_array($status, array(STATUS_READ, STATUS_UNREAD, STATUS_REMOVED))) { return false; } if (empty($item_ids)) { return false; } return Database::getInstance('db') ->table(TABLE) ->eq('user_id', $user_id) ->in('id', $item_ids) ->save(array('status' => $status)); } function update_feed_items($user_id, $feed_id, array $items, $rtl = false) { $items_in_feed = array(); $db = Database::getInstance('db'); $db->startTransaction(); foreach ($items as $item) { if ($item->getId() && $item->getUrl()) { $item_id = get_item_id_from_checksum($feed_id, $item->getId()); $values = array( 'title' => $item->getTitle(), 'url' => $item->getUrl(), 'updated' => $item->getDate()->getTimestamp(), 'author' => $item->getAuthor(), 'content' => Helper\bool_config('nocontent') ? '' : $item->getContent(), 'enclosure_url' => $item->getEnclosureUrl(), 'enclosure_type' => $item->getEnclosureType(), 'language' => $item->getLanguage(), 'rtl' => $rtl || Parser::isLanguageRTL($item->getLanguage()) ? 1 : 0, ); if ($item_id > 0) { $db ->table(TABLE) ->eq('user_id', $user_id) ->eq('feed_id', $feed_id) ->eq('id', $item_id) ->update($values); } else { $values['checksum'] = $item->getId(); $values['user_id'] = $user_id; $values['feed_id'] = $feed_id; $values['status'] = STATUS_UNREAD; $item_id = $db->table(TABLE)->persist($values); } $items_in_feed[] = $item_id; } } cleanup_feed_items($feed_id, $items_in_feed); $db->closeTransaction(); } function cleanup_feed_items($feed_id, array $items_in_feed) { if (! empty($items_in_feed)) { $db = Database::getInstance('db'); $removed_items = $db ->table(TABLE) ->columns('id') ->notIn('id', $items_in_feed) ->eq('status', STATUS_REMOVED) ->eq('feed_id', $feed_id) ->desc('updated') ->findAllByColumn('id'); // Keep a buffer of 2 items // It's workaround for buggy feeds (cache issue with some Wordpress plugins) if (is_array($removed_items)) { $items_to_remove = array_slice($removed_items, 2); if (! empty($items_to_remove)) { // Handle the case when there is a huge number of items to remove // Sqlite have a limit of 1000 sql variables by default // Avoid the error message "too many SQL variables" // We remove old items by batch of 500 items $chunks = array_chunk($items_to_remove, 500); foreach ($chunks as $chunk) { $db->table(TABLE) ->in('id', $chunk) ->eq('status', STATUS_REMOVED) ->eq('feed_id', $feed_id) ->remove(); } } } } } function get_item_id_from_checksum($feed_id, $checksum) { return (int) Database::getInstance('db') ->table(TABLE) ->eq('feed_id', $feed_id) ->eq('checksum', $checksum) ->findOneColumn('id'); } function get_item($user_id, $item_id) { return Database::getInstance('db') ->table('items') ->eq('user_id', $user_id) ->eq('id', $item_id) ->findOne(); } function get_item_nav($user_id, array $item, $status = array(STATUS_UNREAD), $bookmark = array(1, 0), $feed_id = null, $group_id = null) { $query = Database::getInstance('db') ->table(TABLE) ->columns('id', 'status', 'title', 'bookmark') ->neq('status', STATUS_REMOVED) ->eq('user_id', $user_id) ->orderBy('updated', Helper\config('items_sorting_direction')) ->desc('id') ; if ($feed_id) { $query->eq('feed_id', $feed_id); } if ($group_id) { $query->in('feed_id', Group\get_feed_ids_by_group($group_id)); } $items = $query->findAll(); $next_item = null; $previous_item = null; for ($i = 0, $ilen = count($items); $i < $ilen; ++$i) { if ($items[$i]['id'] == $item['id']) { if ($i > 0) { $j = $i - 1; while ($j >= 0) { if (in_array($items[$j]['status'], $status) && in_array($items[$j]['bookmark'], $bookmark)) { $previous_item = $items[$j]; break; } --$j; } } if ($i < ($ilen - 1)) { $j = $i + 1; while ($j < $ilen) { if (in_array($items[$j]['status'], $status) && in_array($items[$j]['bookmark'], $bookmark)) { $next_item = $items[$j]; break; } ++$j; } } break; } } return array( 'next' => $next_item, 'previous' => $previous_item ); } function get_items_by_status($user_id, $status, $feed_ids = array(), $offset = null, $limit = null, $order_column = 'updated', $order_direction = 'desc') { return Database::getInstance('db') ->table('items') ->columns( 'items.id', 'items.checksum', 'items.title', 'items.updated', 'items.url', 'items.enclosure_url', 'items.enclosure_type', 'items.bookmark', 'items.feed_id', 'items.status', 'items.content', 'items.language', 'items.rtl', 'items.author', 'feeds.site_url', 'feeds.title AS feed_title' ) ->join('feeds', 'id', 'feed_id') ->eq('items.user_id', $user_id) ->eq('items.status', $status) ->in('items.feed_id', $feed_ids) ->orderBy($order_column, $order_direction) ->offset($offset) ->limit($limit) ->findAll(); } function get_items($user_id, $since_id = null, array $item_ids = array(), $limit = 50) { $query = Database::getInstance('db') ->table('items') ->columns( 'items.id', 'items.checksum', 'items.title', 'items.updated', 'items.url', 'items.enclosure_url', 'items.enclosure_type', 'items.bookmark', 'items.feed_id', 'items.status', 'items.content', 'items.language', 'items.rtl', 'items.author', 'feeds.site_url', 'feeds.title AS feed_title' ) ->join('feeds', 'id', 'feed_id') ->eq('items.user_id', $user_id) ->neq('items.status', STATUS_REMOVED) ->limit($limit) ->asc('items.id'); if ($since_id !== null) { $query->gt('items.id', $since_id); } elseif (! empty($item_ids)) { $query->in('items.id', $item_ids); } return $query->findAll(); } function get_item_ids_by_status($user_id, $status) { return Database::getInstance('db') ->table('items') ->eq('user_id', $user_id) ->eq('status', $status) ->findAllByColumn('id'); } function get_latest_unread_items_timestamps($user_id) { return Database::getInstance('db') ->table(TABLE) ->columns( 'feed_id', 'MAX(updated) as updated' ) ->eq('user_id', $user_id) ->eq('status', STATUS_UNREAD) ->groupBy('feed_id') ->desc('updated') ->findAll(); } function count_by_status($user_id, $status, $feed_ids = array()) { $query = Database::getInstance('db') ->table('items') ->eq('user_id', $user_id) ->in('feed_id', $feed_ids); if (is_array($status)) { $query->in('status', $status); } else { $query->eq('status', $status); } return $query->count(); } function autoflush_read($user_id) { $autoflush = Helper\int_config('autoflush'); if ($autoflush > 0) { Database::getInstance('db') ->table(TABLE) ->eq('user_id', $user_id) ->eq('bookmark', 0) ->eq('status', STATUS_READ) ->lt('updated', strtotime('-'.$autoflush.'day')) ->save(array('status' => STATUS_REMOVED, 'content' => '')); } elseif ($autoflush === -1) { Database::getInstance('db') ->table(TABLE) ->eq('user_id', $user_id) ->eq('bookmark', 0) ->eq('status', STATUS_READ) ->save(array('status' => STATUS_REMOVED, 'content' => '')); } } function autoflush_unread($user_id) { $autoflush = Helper\int_config('autoflush_unread'); if ($autoflush > 0) { Database::getInstance('db') ->table(TABLE) ->eq('user_id', $user_id) ->eq('bookmark', 0) ->eq('status', STATUS_UNREAD) ->lt('updated', strtotime('-'.$autoflush.'day')) ->save(array('status' => STATUS_REMOVED, 'content' => '')); } }