Fix insert statements; other minor tweaks

This commit is contained in:
Daniel J. Summers 2024-06-09 18:01:04 -04:00
parent edc9a218b7
commit 3dc314b2e3
9 changed files with 117 additions and 102 deletions

View File

@ -1,14 +1,8 @@
{
"name": "bit-badger/feed-reader-central",
"minimum-stability": "dev",
"repositories": [
{
"type": "vcs",
"url": "https://git.bitbadger.solutions/bit-badger/pdo-document"
}
],
"require": {
"bit-badger/pdo-document": "dev-develop",
"bit-badger/pdo-document": "^1",
"ext-curl": "*",
"ext-dom": "*",
"ext-pdo": "*",

46
src/composer.lock generated
View File

@ -4,19 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "e76207a80fdea0c9dc753a55e6f66bf0",
"content-hash": "f074a197e429ac24507becc14e0d99c3",
"packages": [
{
"name": "bit-badger/pdo-document",
"version": "dev-develop",
"version": "v1.0.0-alpha1",
"source": {
"type": "git",
"url": "https://git.bitbadger.solutions/bit-badger/pdo-document",
"reference": "a10ecbb1cdfdf6dd8ab3c1884b09d9ba987b7ff5"
"reference": "f784f3e52cc1e4691fa347eefc82a2e4587c7f38"
},
"require": {
"ext-pdo": "*",
"netresearch/jsonmapper": "^4"
"netresearch/jsonmapper": "^4",
"php": ">=8.3"
},
"require-dev": {
"phpunit/phpunit": "^11"
@ -25,18 +26,35 @@
"autoload": {
"psr-4": {
"BitBadger\\PDODocument\\": "./src",
"BitBadger\\PDODocument\\Mapper\\": "./src/Mapper",
"BitBadger\\PDODocument\\Query\\": "./src/Query"
"BitBadger\\PDODocument\\Query\\": "./src/Query",
"BitBadger\\PDODocument\\Mapper\\": "./src/Mapper"
}
},
"autoload-dev": {
"psr-4": {
"Test\\Unit\\": "./tests/unit",
"Test\\Integration\\": "./tests/integration",
"Test\\Integration\\SQLite\\": "./tests/integration/sqlite"
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Daniel J. Summers",
"email": "daniel@bitbadger.solutions",
"homepage": "https://bitbadger.solutions",
"role": "Developer"
}
],
"description": "Treat SQLite (and soon PostgreSQL) as a document store",
"keywords": [
"database",
"document",
"pdo",
"sqlite"
],
"support": {
"email": "daniel@bitbadger.solutions",
"rss": "https://git.bitbadger.solutions/bit-badger/pdo-document.rss",
"source": "https://git.bitbadger.solutions/bit-badger/pdo-document"
},
"time": "2024-06-08T16:57:13+00:00"
"time": "2024-06-08T23:58:45+00:00"
},
{
"name": "netresearch/jsonmapper",
@ -93,9 +111,7 @@
"packages-dev": [],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": {
"bit-badger/pdo-document": 20
},
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {

View File

@ -3,7 +3,7 @@
namespace FeedReaderCentral;
use BitBadger\PDODocument\{
Configuration, Custom, Document, DocumentException, DocumentList, Exists, Field, Find, Parameters, Patch, Query
Configuration, Custom, DocumentException, DocumentList, Exists, Field, Find, Parameters, Patch, Query
};
use DateTimeInterface;
@ -50,14 +50,12 @@ class Feed
*/
public static function fromParsed(ParsedFeed $parsed): static
{
$it = new static();
$it->user_id = $_SESSION[Key::USER_ID];
$it->url = $parsed->url;
$it->title = $parsed->title;
$it->updated_on = $parsed->updatedOn;
$it->checked_on = Data::formatDate('now');
return $it;
return new static(
user_id: $_SESSION[Key::USER_ID],
url: $parsed->url,
title: $parsed->title,
updated_on: $parsed->updatedOn,
checked_on: Data::formatDate('now'));
}
/**
@ -78,10 +76,10 @@ class Feed
if ($existing) {
if ($existing->published_on != $item->publishedOn
|| ($existing->updated_on != ($item->updatedOn ?? ''))) {
Patch::byId(Table::ITEM, $existing->id, $item->patchFields());
Item::update($existing->id, $item);
}
} else {
Document::insert(Table::ITEM, Item::fromFeedItem($feedId, $item));
Item::add($feedId, $item);
}
return ['ok' => true];
} catch (DocumentException $ex) {
@ -113,7 +111,7 @@ class Feed
$sql .= ' AND ' . Query::whereByFields([$readField]);
} elseif (PURGE_TYPE == self::PURGE_BY_DAYS) {
$fields[] = Field::EQ('', Data::formatDate('-' . PURGE_NUMBER . ' day'), ':oldest');
$sql .= " AND date(coalesce(data->>'updated_on', data->>'published_on)) < date(:oldest)";
$sql .= " AND date(coalesce(data->>'updated_on', data->>'published_on')) < date(:oldest)";
} elseif (PURGE_TYPE == self::PURGE_BY_COUNT) {
$fields[] = Field::EQ('', PURGE_NUMBER, ':keep');
$id = Configuration::$idField;
@ -189,7 +187,10 @@ class Feed
return ['error' => "Already subscribed to feed $feed->url"];
}
Document::insert(Table::FEED, self::fromParsed($feed));
Custom::nonQuery(<<<'SQL'
INSERT INTO feed (data)
VALUES (json_set(:data, '$.id', (SELECT coalesce(max(data->>'id'), 0) + 1 FROM feed)))
SQL, Parameters::json(':data', self::fromParsed($feed)));
$doc = Find::firstByFields(Table::FEED, $fields, static::class);
if (!$doc) return ['error' => 'Could not retrieve inserted feed'];

View File

@ -2,6 +2,8 @@
namespace FeedReaderCentral;
use BitBadger\PDODocument\{Custom, DocumentException, Parameters, Patch};
/**
* An item from a feed
*/
@ -47,21 +49,42 @@ class Item
}
/**
* Create an item document from a parsed feed item
* Add an item
*
* @param int $feedId The ID of the feed to which this item belongs
* @param ParsedItem $item The parsed feed item
* @return static The item document
* @param int $feedId The ID of the feed to which the item belongs
* @param ParsedItem $parsed The parsed item from the feed XML
* @throws DocumentException If any is encountered
*/
public static function fromFeedItem(int $feedId, ParsedItem $item): static
public static function add(int $feedId, ParsedItem $parsed): void
{
return new static(
feed_id: $feedId,
title: $item->title,
item_guid: $item->guid,
item_link: $item->link,
published_on: $item->publishedOn,
updated_on: $item->updatedOn,
content: $item->content);
Custom::nonQuery(<<<'SQL'
INSERT INTO item (data)
VALUES (json_set(:data, '$.id', (SELECT coalesce(max(data->>'id'), 0) + 1 FROM item)))
SQL, Parameters::json(':data', new static(
feed_id: $feedId,
title: $parsed->title,
item_guid: $parsed->guid,
item_link: $parsed->link,
published_on: $parsed->publishedOn,
updated_on: $parsed->updatedOn,
content: $parsed->content)));
}
/**
* Update an item
*
* @param int $id The ID of the item to be updated
* @param ParsedItem $parsed The parsed item from the feed XML
* @throws DocumentException If any is encountered
*/
public static function update(int $id, ParsedItem $parsed): void
{
Patch::byId(Table::ITEM, $id, [
'title' => $parsed->title,
'published_on' => $parsed->publishedOn,
'updated_on' => $parsed->updatedOn,
'content' => $parsed->content,
'is_read' => 0
]);
}
}

View File

@ -9,39 +9,19 @@ use DOMNode;
*/
class ParsedItem
{
/** @var string The title of the feed item */
public string $title = '';
/** @var string The unique ID for the feed item */
public string $guid = '';
/** @var string The link to the original content */
public string $link = '';
/** @var string When this item was published */
public string $publishedOn = '';
/** @var ?string When this item was last updated */
public ?string $updatedOn = null;
/** @var string The content for the item */
public string $content = '';
/**
* Get the fields needed to update the item in the database
* Constructor
*
* @return array The fields needed tu update an item
* @param string $guid The unique ID for the feed item
* @param string $title The title of the feed item
* @param string $link The link to the original content
* @param string $publishedOn When this item was published
* @param string|null $updatedOn When this item was last updated
* @param string $content The content for the item
*/
public function patchFields(): array
{
return [
'title' => $this->title,
'published_on' => $this->publishedOn,
'updated_on' => $this->updatedOn,
'content' => $this->content,
'is_read' => 0
];
}
private function __construct(public string $guid = '', public string $title = '', public string $link = '',
public string $publishedOn = '', public ?string $updatedOn = null,
public string $content = '') { }
/**
* Construct a feed item from an Atom feed's `<entry>` tag
@ -64,15 +44,13 @@ class ParsedItem
}
if ($link == '' && str_starts_with($guid, 'http')) $link = $guid;
$item = new static();
$item->guid = $guid;
$item->title = ParsedFeed::atomValue($node, 'title');
$item->link = $link;
$item->publishedOn = Data::formatDate(ParsedFeed::atomValue($node, 'published'));
$item->updatedOn = Data::formatDate(ParsedFeed::atomValue($node, 'updated'));
$item->content = ParsedFeed::atomValue($node, 'content');
return $item;
return new static(
guid: $guid,
title: ParsedFeed::atomValue($node, 'title'),
link: $link,
publishedOn: Data::formatDate(ParsedFeed::atomValue($node, 'published')),
updatedOn: Data::formatDate(ParsedFeed::atomValue($node, 'updated')),
content: ParsedFeed::atomValue($node, 'content'));
}
/**
@ -87,16 +65,14 @@ class ParsedItem
$updNodes = $node->getElementsByTagNameNS(ParsedFeed::ATOM_NS, 'updated');
$encNodes = $node->getElementsByTagNameNS(ParsedFeed::CONTENT_NS, 'encoded');
$item = new static();
$item->guid = $itemGuid == 'guid not found' ? ParsedFeed::rssValue($node, 'link') : $itemGuid;
$item->title = ParsedFeed::rssValue($node, 'title');
$item->link = ParsedFeed::rssValue($node, 'link');
$item->publishedOn = Data::formatDate(ParsedFeed::rssValue($node, 'pubDate'));
$item->updatedOn = Data::formatDate($updNodes->length > 0 ? $updNodes->item(0)->textContent : null);
$item->content = $encNodes->length > 0
? $encNodes->item(0)->textContent
: ParsedFeed::rssValue($node, 'description');
return $item;
return new static(
guid: $itemGuid == 'guid not found' ? ParsedFeed::rssValue($node, 'link') : $itemGuid,
title: ParsedFeed::rssValue($node, 'title'),
link: ParsedFeed::rssValue($node, 'link'),
publishedOn: Data::formatDate(ParsedFeed::rssValue($node, 'pubDate')),
updatedOn: Data::formatDate($updNodes->length > 0 ? $updNodes->item(0)->textContent : null),
content: $encNodes->length > 0
? $encNodes->item(0)->textContent
: ParsedFeed::rssValue($node, 'description'));
}
}

View File

@ -2,7 +2,7 @@
namespace FeedReaderCentral;
use BitBadger\PDODocument\{Custom, Document, DocumentException, Field, Find, Parameters, Query};
use BitBadger\PDODocument\{Custom, DocumentException, Field, Find, Parameters, Query};
use BitBadger\PDODocument\Mapper\ExistsMapper;
/**
@ -40,7 +40,10 @@ class User
*/
public static function add(string $email, string $password): void
{
Document::insert(Table::USER, new User(email: $email, password: $password));
Custom::nonQuery(<<<'SQL'
INSERT INTO user (data)
VALUES (json_set(:data, '$.id', (SELECT coalesce(max(data->>'id'), 0) + 1 FROM user)))
SQL, Parameters::json(':data', new User(email: $email, password: $password)));
}
/**

View File

@ -29,7 +29,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
try {
$isNew = $_POST['id'] == 'new';
$isNew = $_POST['id'] == '-1';
if ($isNew) {
$result = Feed::add($_POST['url']);
} else {

View File

@ -19,7 +19,7 @@ $feeds = Custom::list(Query\Find::byFields(Table::FEED, [$field]) . " ORDER BY l
$field->appendParameter([]), new DocumentMapper(Feed::class));
page_head('Your Feeds');
echo '<h1>Your Feeds</h1><article><p class=action_buttons>' . hx_get('/feed/?id=new', 'Add Feed') . '</p>';
echo '<h1>Your Feeds</h1><article><p class=action_buttons>' . hx_get('/feed/?id=-1', 'Add Feed') . '</p>';
foreach ($feeds->items() as /** @var Feed $feed */ $feed) {
$item = Table::ITEM;
$counts = Custom::single(<<<SQL

View File

@ -1,5 +1,6 @@
<?php declare(strict_types=1);
use BitBadger\PDODocument\Configuration;
use FeedReaderCentral\{Key, Security, User};
require 'app-config.php';
@ -134,6 +135,7 @@ function frc_redirect(string $value): never
}
session_commit();
header("Location: $value", true, 303);
Configuration::resetPDO();
die();
}