Change to PDODocument library
This commit is contained in:
@@ -2,16 +2,16 @@
|
||||
|
||||
namespace FeedReaderCentral;
|
||||
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\Field;
|
||||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use BitBadger\Documents\SQLite\Custom;
|
||||
use BitBadger\Documents\SQLite\Definition;
|
||||
use BitBadger\Documents\StringMapper;
|
||||
use BitBadger\PDODocument\Configuration;
|
||||
use BitBadger\PDODocument\Custom;
|
||||
use BitBadger\PDODocument\Definition;
|
||||
use BitBadger\PDODocument\DocumentException;
|
||||
use BitBadger\PDODocument\Field;
|
||||
use BitBadger\PDODocument\Mapper\StringMapper;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Exception;
|
||||
use SQLite3;
|
||||
use PDO;
|
||||
|
||||
/**
|
||||
* A centralized place for data access for the application
|
||||
@@ -21,18 +21,18 @@ class Data
|
||||
/**
|
||||
* Create the search index and synchronization triggers for the item table
|
||||
*
|
||||
* @param SQLite3 $db The database connection on which these will be created
|
||||
* @param PDO $pdo The database connection on which these will be created
|
||||
* @throws DocumentException If any is encountered
|
||||
*/
|
||||
public static function createSearchIndex(SQLite3 $db): void
|
||||
public static function createSearchIndex(PDO $pdo): void
|
||||
{
|
||||
Custom::nonQuery("CREATE VIRTUAL TABLE item_search USING fts5(content, content='item', content_rowid='id')",
|
||||
[], $db);
|
||||
[], $pdo);
|
||||
Custom::nonQuery(<<<'SQL'
|
||||
CREATE TRIGGER item_ai AFTER INSERT ON item BEGIN
|
||||
INSERT INTO item_search (rowid, content) VALUES (new.data->>'id', new.data->>'content');
|
||||
END;
|
||||
SQL, [], $db);
|
||||
SQL, [], $pdo);
|
||||
Custom::nonQuery(<<<'SQL'
|
||||
CREATE TRIGGER item_au AFTER UPDATE ON item BEGIN
|
||||
INSERT INTO item_search (
|
||||
@@ -42,7 +42,7 @@ class Data
|
||||
);
|
||||
INSERT INTO item_search (rowid, content) VALUES (new.data->>'id', new.data->>'content');
|
||||
END;
|
||||
SQL, [], $db);
|
||||
SQL, [], $pdo);
|
||||
Custom::nonQuery(<<<'SQL'
|
||||
CREATE TRIGGER item_ad AFTER DELETE ON item BEGIN
|
||||
INSERT INTO item_search (
|
||||
@@ -51,7 +51,7 @@ class Data
|
||||
'delete', old.data->>'id', old.data->>'content'
|
||||
);
|
||||
END;
|
||||
SQL, [], $db);
|
||||
SQL, [], $pdo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,23 +62,22 @@ class Data
|
||||
public static function ensureDb(): void
|
||||
{
|
||||
$tables = Custom::array("SELECT name FROM sqlite_master WHERE type = 'table'", [], new StringMapper('name'));
|
||||
$db = Configuration::dbConn();
|
||||
$pdo = Configuration::dbConn();
|
||||
if (!in_array(Table::USER, $tables)) {
|
||||
Definition::ensureTable(Table::USER, $db);
|
||||
Definition::ensureFieldIndex(Table::USER, 'email', ['email'], $db);
|
||||
Definition::ensureTable(Table::USER, $pdo);
|
||||
Definition::ensureFieldIndex(Table::USER, 'email', ['email'], $pdo);
|
||||
}
|
||||
if (!in_array(Table::FEED, $tables)) {
|
||||
Definition::ensureTable(Table::FEED, $db);
|
||||
Definition::ensureFieldIndex(Table::FEED, 'user', ['user_id'], $db);
|
||||
Definition::ensureTable(Table::FEED, $pdo);
|
||||
Definition::ensureFieldIndex(Table::FEED, 'user', ['user_id'], $pdo);
|
||||
}
|
||||
if (!in_array(Table::ITEM, $tables)) {
|
||||
Definition::ensureTable(Table::ITEM, $db);
|
||||
Definition::ensureFieldIndex(Table::ITEM, 'feed', ['feed_id', 'item_link'], $db);
|
||||
self::createSearchIndex($db);
|
||||
Definition::ensureTable(Table::ITEM, $pdo);
|
||||
Definition::ensureFieldIndex(Table::ITEM, 'feed', ['feed_id', 'item_link'], $pdo);
|
||||
self::createSearchIndex($pdo);
|
||||
}
|
||||
$journalMode = Custom::scalar("PRAGMA journal_mode", [], fn($it) => $it[0]);
|
||||
$journalMode = Custom::scalar("PRAGMA journal_mode", [], new StringMapper('journal_mode'));
|
||||
if ($journalMode <> 'wal') Custom::nonQuery("PRAGMA journal_mode = 'wal'", []);
|
||||
$db->close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +102,7 @@ class Data
|
||||
*/
|
||||
public static function feedField(int $feedId, string $qualifier = ''): Field
|
||||
{
|
||||
$feedField = Field::EQ(Configuration::idField(), $feedId, '@feed');
|
||||
$feedField = Field::EQ(Configuration::$idField, $feedId, '@feed');
|
||||
$feedField->qualifier = $qualifier;
|
||||
return $feedField;
|
||||
}
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
|
||||
namespace FeedReaderCentral;
|
||||
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\DocumentList;
|
||||
use BitBadger\Documents\Field;
|
||||
use BitBadger\Documents\Query;
|
||||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use BitBadger\Documents\SQLite\Custom;
|
||||
use BitBadger\Documents\SQLite\Document;
|
||||
use BitBadger\Documents\SQLite\Exists;
|
||||
use BitBadger\Documents\SQLite\Find;
|
||||
use BitBadger\Documents\SQLite\Parameters;
|
||||
use BitBadger\Documents\SQLite\Patch;
|
||||
use BitBadger\PDODocument\Configuration;
|
||||
use BitBadger\PDODocument\Custom;
|
||||
use BitBadger\PDODocument\Document;
|
||||
use BitBadger\PDODocument\DocumentException;
|
||||
use BitBadger\PDODocument\DocumentList;
|
||||
use BitBadger\PDODocument\Exists;
|
||||
use BitBadger\PDODocument\Field;
|
||||
use BitBadger\PDODocument\Find;
|
||||
use BitBadger\PDODocument\Parameters;
|
||||
use BitBadger\PDODocument\Patch;
|
||||
use BitBadger\PDODocument\Query;
|
||||
use DateTimeInterface;
|
||||
use SQLite3;
|
||||
use PDO;
|
||||
|
||||
/**
|
||||
* An RSS or Atom feed
|
||||
@@ -75,23 +75,23 @@ class Feed
|
||||
* @param int $feedId The ID of the feed to which these items belong
|
||||
* @param ParsedFeed $parsed The extracted Atom or RSS feed items
|
||||
* @param DateTimeInterface $lastChecked When this feed was last checked (only new items will be added)
|
||||
* @param PDO $pdo The database connection over which items should be updated
|
||||
* @return array ['ok' => true] if successful, ['error' => message] if not
|
||||
*/
|
||||
public static function updateItems(int $feedId, ParsedFeed $parsed, DateTimeInterface $lastChecked,
|
||||
SQLite3 $db): array
|
||||
public static function updateItems(int $feedId, ParsedFeed $parsed, DateTimeInterface $lastChecked, PDO $pdo): array
|
||||
{
|
||||
$results =
|
||||
array_map(function ($item) use ($db, $feedId) {
|
||||
array_map(function ($item) use ($pdo, $feedId) {
|
||||
try {
|
||||
$existing = Find::firstByFields(Table::ITEM,
|
||||
[Field::EQ('feed_id', $feedId), Field::EQ('item_guid', $item->guid)], Item::class);
|
||||
if ($existing) {
|
||||
if ($existing->published_on != $item->publishedOn
|
||||
|| ($existing->updated_on != ($item->updatedOn ?? ''))) {
|
||||
Patch::byId(Table::ITEM, $existing->id, $item->patchFields(), $db);
|
||||
Patch::byId(Table::ITEM, $existing->id, $item->patchFields(), $pdo);
|
||||
}
|
||||
} else {
|
||||
Document::insert(Table::ITEM, Item::fromFeedItem($feedId, $item), $db);
|
||||
Document::insert(Table::ITEM, Item::fromFeedItem($feedId, $item), $pdo);
|
||||
}
|
||||
return ['ok' => true];
|
||||
} catch (DocumentException $ex) {
|
||||
@@ -107,10 +107,10 @@ class Feed
|
||||
* Purge items for a feed
|
||||
*
|
||||
* @param int $feedId The ID of the feed to be purged
|
||||
* @param SQLite3 $db The database connection on which items should be purged
|
||||
* @param PDO $pdo The database connection on which items should be purged
|
||||
* @return array|string[]|true[] ['ok' => true] if purging was successful, ['error' => message] if not
|
||||
*/
|
||||
private static function purgeItems(int $feedId, SQLite3 $db): array
|
||||
private static function purgeItems(int $feedId, PDO $pdo): array
|
||||
{
|
||||
if (!array_search(PURGE_TYPE, [self::PURGE_READ, self::PURGE_BY_DAYS, self::PURGE_BY_COUNT])) {
|
||||
return ['error' => 'Unrecognized purge type ' . PURGE_TYPE];
|
||||
@@ -127,7 +127,7 @@ class Feed
|
||||
$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();
|
||||
$id = Configuration::$idField;
|
||||
$table = Table::ITEM;
|
||||
$sql .= ' ' . <<<SQL
|
||||
AND data->>'$id' IN (
|
||||
@@ -139,7 +139,7 @@ class Feed
|
||||
SQL;
|
||||
}
|
||||
try {
|
||||
Custom::nonQuery($sql, Parameters::addFields($fields, []), $db);
|
||||
Custom::nonQuery($sql, Parameters::addFields($fields, []), $pdo);
|
||||
return ['ok' => true];
|
||||
} catch (DocumentException $ex) {
|
||||
return ['error' => "$ex"];
|
||||
@@ -151,10 +151,11 @@ class Feed
|
||||
*
|
||||
* @param int $feedId The ID of the feed to be refreshed
|
||||
* @param string $url The URL of the feed to be refreshed
|
||||
* @param SQLite3 $db A database connection to use to refresh the feed
|
||||
* @param PDO $pdo A database connection to use to refresh the feed
|
||||
* @return array|string[]|true[] ['ok' => true] if successful, ['error' => message] if not
|
||||
*/
|
||||
public static function refreshFeed(int $feedId, string $url, SQLite3 $db): array {
|
||||
public static function refreshFeed(int $feedId, string $url, PDO $pdo): array
|
||||
{
|
||||
$feedRetrieval = ParsedFeed::retrieve($url);
|
||||
if (key_exists('error', $feedRetrieval)) return $feedRetrieval;
|
||||
$feed = $feedRetrieval['ok'];
|
||||
@@ -164,7 +165,7 @@ class Feed
|
||||
if (!$feedDoc) return ['error' => 'Could not derive date last checked for feed'];
|
||||
$lastChecked = date_create_immutable($feedDoc->checked_on ?? WWW_EPOCH);
|
||||
|
||||
$itemUpdate = self::updateItems($feedId, $feed, $lastChecked, $db);
|
||||
$itemUpdate = self::updateItems($feedId, $feed, $lastChecked, $pdo);
|
||||
if (key_exists('error', $itemUpdate)) return $itemUpdate;
|
||||
|
||||
$patch = [
|
||||
@@ -173,12 +174,12 @@ class Feed
|
||||
'checked_on' => Data::formatDate('now')
|
||||
];
|
||||
if ($url == $feed->url) $patch['url'] = $feed->url;
|
||||
Patch::byId(Table::FEED, $feedId, $patch, $db);
|
||||
Patch::byId(Table::FEED, $feedId, $patch, $pdo);
|
||||
} catch (DocumentException $ex) {
|
||||
return ['error' => "$ex"];
|
||||
}
|
||||
|
||||
return PURGE_TYPE == self::PURGE_NONE ? ['ok' => true] : self::purgeItems($feedId, $db);
|
||||
return PURGE_TYPE == self::PURGE_NONE ? ['ok' => true] : self::purgeItems($feedId, $pdo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,30 +188,32 @@ class Feed
|
||||
* @param string $url The URL of the RSS feed to add
|
||||
* @return array ['ok' => feedId] if successful, ['error' => message] if not
|
||||
*/
|
||||
public static function add(string $url, SQLite3 $db): array {
|
||||
public static function add(string $url): array
|
||||
{
|
||||
$feedExtract = ParsedFeed::retrieve($url);
|
||||
if (key_exists('error', $feedExtract)) return $feedExtract;
|
||||
|
||||
$feed = $feedExtract['ok'];
|
||||
|
||||
try {
|
||||
$pdo = Configuration::dbConn();
|
||||
$fields = [Field::EQ('user_id', $_SESSION[Key::USER_ID]), Field::EQ('url', $feed->url)];
|
||||
if (Exists::byFields(Table::FEED, $fields, $db)) {
|
||||
if (Exists::byFields(Table::FEED, $fields, $pdo)) {
|
||||
return ['error' => "Already subscribed to feed $feed->url"];
|
||||
}
|
||||
|
||||
Document::insert(Table::FEED, self::fromParsed($feed), $db);
|
||||
Document::insert(Table::FEED, self::fromParsed($feed), $pdo);
|
||||
|
||||
$doc = Find::firstByFields(Table::FEED, $fields, self::class);
|
||||
if (!$doc) return ['error' => 'Could not retrieve inserted feed'];
|
||||
|
||||
$result = self::updateItems($doc->id, $feed, date_create_immutable(WWW_EPOCH), $pdo);
|
||||
if (key_exists('error', $result)) return $result;
|
||||
|
||||
return ['ok' => $doc->id];
|
||||
} catch (DocumentException $ex) {
|
||||
return ['error' => "$ex"];
|
||||
}
|
||||
|
||||
$result = self::updateItems($doc->id, $feed, date_create_immutable(WWW_EPOCH), $db);
|
||||
if (key_exists('error', $result)) return $result;
|
||||
|
||||
return ['ok' => $doc->id];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,19 +221,20 @@ class Feed
|
||||
*
|
||||
* @param Feed $existing The existing feed
|
||||
* @param string $url The URL with which the existing feed should be modified
|
||||
* @param SQLite3 $db The database connection on which to execute the update
|
||||
* @return bool[]|string[] [ 'ok' => true ] if successful, [ 'error' => message ] if not
|
||||
*/
|
||||
public static function update(Feed $existing, string $url, SQLite3 $db): array {
|
||||
public static function update(Feed $existing, string $url): array
|
||||
{
|
||||
try {
|
||||
$pdo = Configuration::dbConn();
|
||||
Patch::byFields(Table::FEED,
|
||||
[Field::EQ(Configuration::idField(), $existing->id), Field::EQ('user_id', $_SESSION[Key::USER_ID])],
|
||||
['url' => $url], $db);
|
||||
[Field::EQ(Configuration::$idField, $existing->id), Field::EQ('user_id', $_SESSION[Key::USER_ID])],
|
||||
['url' => $url], $pdo);
|
||||
|
||||
return self::refreshFeed($existing->id, $url, $pdo);
|
||||
} catch (DocumentException $ex) {
|
||||
return ['error' => "$ex"];
|
||||
}
|
||||
|
||||
return self::refreshFeed($existing->id, $url, $db);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,18 +254,18 @@ class Feed
|
||||
/**
|
||||
* Refresh all feeds
|
||||
*
|
||||
* @param SQLite3 $db The database connection to use for refreshing feeds
|
||||
* @return array|true[]|string[] ['ok' => true] if successful,
|
||||
* ['error' => message] if not (may have multiple error lines)
|
||||
*/
|
||||
public static function refreshAll(SQLite3 $db): array
|
||||
public static function refreshAll(): array
|
||||
{
|
||||
try {
|
||||
$feeds = self::retrieveAll($_SESSION[Key::USER_ID]);
|
||||
|
||||
$pdo = Configuration::dbConn();
|
||||
$errors = [];
|
||||
foreach ($feeds->items() as $feed) {
|
||||
$result = self::refreshFeed($feed->id, $feed->url, $db);
|
||||
$result = self::refreshFeed($feed->id, $feed->url, $pdo);
|
||||
if (key_exists('error', $result)) $errors[] = $result['error'];
|
||||
}
|
||||
} catch (DocumentException $ex) {
|
||||
@@ -278,8 +282,9 @@ class Feed
|
||||
* @return static|false The data for the feed if found, false if not found
|
||||
* @throws DocumentException If any is encountered
|
||||
*/
|
||||
public static function retrieveById(int $feedId): static|false {
|
||||
$doc = Find::byId(Table::FEED, $feedId, self::class);
|
||||
public static function retrieveById(int $feedId): static|false
|
||||
{
|
||||
$doc = Find::byId(Table::FEED, $feedId, static::class);
|
||||
return $doc && $doc->user_id == $_SESSION[Key::USER_ID] ? $doc : false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
|
||||
namespace FeedReaderCentral;
|
||||
|
||||
use BitBadger\Documents\Configuration;
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\DocumentList;
|
||||
use BitBadger\Documents\Field;
|
||||
use BitBadger\Documents\JsonMapper;
|
||||
use BitBadger\Documents\Query;
|
||||
use BitBadger\Documents\SQLite\Custom;
|
||||
use BitBadger\Documents\SQLite\Parameters;
|
||||
use Iterator;
|
||||
use BitBadger\PDODocument\Configuration;
|
||||
use BitBadger\PDODocument\Custom;
|
||||
use BitBadger\PDODocument\DocumentException;
|
||||
use BitBadger\PDODocument\DocumentList;
|
||||
use BitBadger\PDODocument\Field;
|
||||
use BitBadger\PDODocument\Parameters;
|
||||
use BitBadger\PDODocument\Query;
|
||||
use BitBadger\PDODocument\Mapper\DocumentMapper;
|
||||
|
||||
/**
|
||||
* A list of items to be displayed
|
||||
@@ -61,7 +60,7 @@ class ItemList
|
||||
ItemWithFeed::SELECT_WITH_FEED . ' WHERE '
|
||||
. Query::whereByFields(array_filter($allFields, fn($it) => $it->paramName <> '@search'))
|
||||
. $searchWhere,
|
||||
Parameters::addFields($allFields, []), new JsonMapper(ItemWithFeed::class));
|
||||
Parameters::addFields($allFields, []), new DocumentMapper(ItemWithFeed::class));
|
||||
} catch (DocumentException $ex) {
|
||||
$this->error = "$ex";
|
||||
}
|
||||
@@ -141,7 +140,7 @@ class ItemList
|
||||
if ($isBookmarked) $fields[] = Data::bookmarkField(Table::ITEM);
|
||||
$list = new static('Matching' . ($isBookmarked ? ' Bookmarked' : ''),
|
||||
"/search?search=$search&items=" . ($isBookmarked ? 'bookmarked' : 'all'), $fields,
|
||||
' AND ' . Table::ITEM . ".data->>'" . Configuration::idField() . "' IN "
|
||||
' AND ' . Table::ITEM . ".data->>'" . Configuration::$idField . "' IN "
|
||||
. '(SELECT ROWID FROM item_search WHERE content MATCH @search)');
|
||||
$list->showIndicators = true;
|
||||
$list->displayFeed = true;
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace FeedReaderCentral;
|
||||
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\Field;
|
||||
use BitBadger\Documents\JsonMapper;
|
||||
use BitBadger\Documents\Query;
|
||||
use BitBadger\Documents\SQLite\Configuration;
|
||||
use BitBadger\Documents\SQLite\Custom;
|
||||
use BitBadger\Documents\SQLite\Parameters;
|
||||
use BitBadger\Documents\SQLite\Results;
|
||||
use BitBadger\PDODocument\Configuration;
|
||||
use BitBadger\PDODocument\Custom;
|
||||
use BitBadger\PDODocument\DocumentException;
|
||||
use BitBadger\PDODocument\Field;
|
||||
use BitBadger\PDODocument\Parameters;
|
||||
use BitBadger\PDODocument\Query;
|
||||
use BitBadger\PDODocument\Mapper\DocumentMapper;
|
||||
use BitBadger\PDODocument\Mapper\ExistsMapper;
|
||||
|
||||
/**
|
||||
* A combined item and feed (used for lists)
|
||||
@@ -36,7 +36,7 @@ class ItemWithFeed extends Item
|
||||
*/
|
||||
private static function idAndUserFields(int $id): array
|
||||
{
|
||||
$idField = Field::EQ(Configuration::idField(), $id, '@id');
|
||||
$idField = Field::EQ(Configuration::$idField, $id, '@id');
|
||||
$idField->qualifier = Table::ITEM;
|
||||
$userField = Field::EQ('user_id', $_SESSION[Key::USER_ID], '@user');
|
||||
$userField->qualifier = Table::FEED;
|
||||
@@ -54,7 +54,7 @@ class ItemWithFeed extends Item
|
||||
{
|
||||
$fields = self::idAndUserFields($id);
|
||||
return Custom::scalar(Query\Exists::query(self::FROM_WITH_JOIN, Query::whereByFields($fields)),
|
||||
Parameters::addFields($fields, []), Results::toExists(...));
|
||||
Parameters::addFields($fields, []), new ExistsMapper());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,6 +68,6 @@ class ItemWithFeed extends Item
|
||||
{
|
||||
$fields = self::idAndUserFields($id);
|
||||
return Custom::single(self::SELECT_WITH_FEED . ' WHERE ' . Query::whereByFields($fields),
|
||||
Parameters::addFields($fields, []), new JsonMapper(self::class));
|
||||
Parameters::addFields($fields, []), new DocumentMapper(self::class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace FeedReaderCentral;
|
||||
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\Field;
|
||||
use BitBadger\Documents\SQLite\Patch;
|
||||
use BitBadger\PDODocument\DocumentException;
|
||||
use BitBadger\PDODocument\Field;
|
||||
use BitBadger\PDODocument\Patch;
|
||||
|
||||
/**
|
||||
* Security functions
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace FeedReaderCentral;
|
||||
|
||||
use BitBadger\Documents\DocumentException;
|
||||
use BitBadger\Documents\Field;
|
||||
use BitBadger\Documents\Query;
|
||||
use BitBadger\Documents\SQLite\Custom;
|
||||
use BitBadger\Documents\SQLite\Document;
|
||||
use BitBadger\Documents\SQLite\Find;
|
||||
use BitBadger\Documents\SQLite\Parameters;
|
||||
use BitBadger\Documents\SQLite\Results;
|
||||
use BitBadger\PDODocument\Custom;
|
||||
use BitBadger\PDODocument\Document;
|
||||
use BitBadger\PDODocument\DocumentException;
|
||||
use BitBadger\PDODocument\Field;
|
||||
use BitBadger\PDODocument\Find;
|
||||
use BitBadger\PDODocument\Mapper\ExistsMapper;
|
||||
use BitBadger\PDODocument\Parameters;
|
||||
use BitBadger\PDODocument\Query;
|
||||
|
||||
/**
|
||||
* A user of Feed Reader Central
|
||||
@@ -59,6 +59,6 @@ class User
|
||||
{
|
||||
$fields = [Data::userIdField(Table::FEED), Data::bookmarkField(Table::ITEM)];
|
||||
return Custom::scalar(Query\Exists::query(ItemWithFeed::FROM_WITH_JOIN, Query::whereByFields($fields)),
|
||||
Parameters::addFields($fields, []), Results::toExists(...));
|
||||
Parameters::addFields($fields, []), new ExistsMapper());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user