// the binding types are just a repetition of the supplied type
$out[1] = array_fill(0,sizeof($values),$type);
return $out;
}
public function settingGet(string $key) {
$row = $this->db->prepare("SELECT value, type from arsse_settings where key = ?", "str")->run($key)->getRow();
if(!$row) return null;
@ -431,12 +443,14 @@ class Database {
if($feed->resource->isModified()) {
$feed->parse();
} else {
// if the feed hasn't changed, just compute the next fetch time and record it
$next = $this->feedNextFetch($feedID);
$this->db->prepare('UPDATE arsse_feeds SET updated = CURRENT_TIMESTAMP, next_fetch = ? WHERE id is ?', 'datetime', 'int')->run($next, $feedID);
$this->db->commit();
return false;
}
} catch (Feed\Exception $e) {
// update the database with the resultant error and the next fetch time, incrementing the error count
$next = $this->feedNextFetch($feedID);
$this->db->prepare('UPDATE arsse_feeds SET updated = CURRENT_TIMESTAMP, next_fetch = ?, err_count = err_count + 1, err_msg = ? WHERE id is ?', 'datetime', 'str', 'int')->run($next, $e->getMessage(),$feedID);
$this->db->commit();
@ -445,79 +459,112 @@ class Database {
$this->db->rollback();
throw $e;
}
// FIXME: first perform deduplication on the feed itself
// array if items in the fetched feed
$items = $feed->data->items;
// get as many of the latest articles in the database as there are in the feed
$articles = $this->db->prepare(
'SELECT id, DATEFORMAT("http", edited) AS edited_date, guid, url_title_hash, url_content_hash, title_content_hash FROM arsse_articles WHERE feed is ? ORDER BY edited desc limit ?',
'SELECT id, DATEFORMAT("unix", edited) AS edited_date, guid, url_title_hash, url_content_hash, title_content_hash FROM arsse_articles WHERE feed is ? ORDER BY edited desc limit ?',
'int', 'int'
)->run(
$feedID,
sizeof($items)
$feedID, sizeof($items)
)->getAll();
// arrays holding new, edited, and tentatively new items
// items may be tentatively new because we perform two passes
$new = $tentative = $edited = [];
// iterate through the articles and for each determine whether it is existing, edited, or entirely new
foreach($items as $index => $i) {
// Iterate through the articles in the database to determine a match for the one
// in the just-parsed feed.
$match = null;
foreach($articles as $a) {
// If the id exists and is equal to one in the database then this is the post.
if($i->id && $i->id === $a['guid']) {
$match = $a;
}
// Otherwise if the id doesn't exist and any of the hashes match then this is
$this->db->prepare('DELETE FROM arsse_categories WHERE article is ?', 'int')->run($match['id']);
$this->categoriesAdd($i, $match['id']);
}
}
// Lastly update the feed database itself with updated information.
// FIXME: fetch full content when appropriate
// finally actually perform updates
foreach($new as $index) {
$this->articleAdd($feedID, $items[$index]);
}
foreach($edited as $index => $id) {
$this->articleAdd($feedID, $items[$index], $id);
}
// lastly update the feed database itself with updated information.
$next = $this->feedNextFetch($feedID, $feed);
$this->db->prepare('UPDATE arsse_feeds SET url = ?, title = ?, favicon = ?, source = ?, updated = CURRENT_TIMESTAMP, modified = ?, etag = ?, err_count = 0, err_msg = "", next_fetch = ? WHERE id is ?', 'str', 'str', 'str', 'str', 'datetime', 'str', 'datetime', 'int')->run(
$feed->data->feedUrl,
@ -542,27 +589,49 @@ class Database {
return new \DateTime("now + 3 hours", new \DateTimeZone("UTC"));
}
public function articleAdd(int $feedID, \PicoFeed\Parser\Item $article): int {
public function articleAdd(int $feedID, \PicoFeed\Parser\Item $article, int $articleID = null): int {
$this->db->begin();
try {
$articleID = $this->db->prepare(
'INSERT INTO arsse_articles(feed,url,title,author,published,edited,guid,content,url_title_hash,url_content_hash,title_content_hash) values(?,?,?,?,?,?,?,?,?,?,?)',
'INSERT INTO arsse_articles(feed,url,title,author,published,edited,guid,content,url_title_hash,url_content_hash,title_content_hash) values(?,?,?,?,?,?,?,?,?,?,?)',