forked from leftypol/leftypol
UserPostQueries.php: add user post queries class
This commit is contained in:
parent
1d41ffbe4f
commit
71416afc75
2 changed files with 130 additions and 0 deletions
15
inc/Data/PageFetchResult.php
Normal file
15
inc/Data/PageFetchResult.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
namespace Vichan\Data;
|
||||
|
||||
|
||||
/**
|
||||
* A page of user posts.
|
||||
*/
|
||||
class PageFetchResult {
|
||||
/**
|
||||
* @var array[array] Posts grouped by board uri.
|
||||
*/
|
||||
public array $by_uri;
|
||||
public ?string $cursor_prev;
|
||||
public ?string $cursor_next;
|
||||
}
|
115
inc/Data/UserPostQueries.php
Normal file
115
inc/Data/UserPostQueries.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
namespace Vichan\Data;
|
||||
|
||||
use Vichan\Functions\Net;
|
||||
|
||||
|
||||
/**
|
||||
* Browse user posts
|
||||
*/
|
||||
class UserPostQueries {
|
||||
private const CURSOR_TYPE_PREV = 'p';
|
||||
private const CURSOR_TYPE_NEXT = 'n';
|
||||
|
||||
private \PDO $pdo;
|
||||
|
||||
public function __construct(\PDO $pdo) {
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a page of user posts.
|
||||
*
|
||||
* @param array $board_uris The uris of the boards that should be included.
|
||||
* @param string $ip The IP of the target user.
|
||||
* @param integer $page_size The Number of posts that should be fetched.
|
||||
* @param string|null $cursor The directional cursor to fetch the next or previous page. Null to start from the beginning.
|
||||
* @return PageFetchResult
|
||||
*/
|
||||
public function fetchPaginatedByIp(array $board_uris, string $ip, int $page_size, ?string $cursor = null): PageFetchResult {
|
||||
// Decode the cursor.
|
||||
if ($cursor !== null) {
|
||||
list($cursor_type, $uri_id_cursor_map) = Net\decode_cursor($cursor);
|
||||
} else {
|
||||
// Defaults if $cursor is an invalid string.
|
||||
$cursor_type = null;
|
||||
$uri_id_cursor_map = [];
|
||||
}
|
||||
$next_cursor_map = [];
|
||||
$prev_cursor_map = [];
|
||||
$rows = [];
|
||||
|
||||
foreach ($board_uris as $uri) {
|
||||
// Extract the cursor relative to the board.
|
||||
$id_cursor = false;
|
||||
if (isset($uri_id_cursor_map[$uri])) {
|
||||
$value = $uri_id_cursor_map[$uri];
|
||||
if (\is_numeric($value)) {
|
||||
$id_cursor = (int)$value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($id_cursor === false) {
|
||||
$query = $this->pdo->prepare(sprintf('SELECT * FROM `posts_%s` WHERE `ip` = :ip ORDER BY `sticky` DESC, `id` DESC LIMIT :limit', $uri));
|
||||
$query->bindValue(':ip', $ip);
|
||||
$query->bindValue(':limit', $page_size + 1, \PDO::PARAM_INT); // Always fetch more.
|
||||
$query->execute();
|
||||
$posts = $query->fetchAll(\PDO::FETCH_ASSOC);
|
||||
} elseif ($cursor_type === self::CURSOR_TYPE_NEXT) {
|
||||
$query = $this->pdo->prepare(sprintf('SELECT * FROM `posts_%s` WHERE `ip` = :ip AND `id` <= :start_id ORDER BY `sticky` DESC, `id` DESC LIMIT :limit', $uri));
|
||||
$query->bindValue(':ip', $ip);
|
||||
$query->bindValue(':start_id', $id_cursor, \PDO::PARAM_INT);
|
||||
$query->bindValue(':limit', $page_size + 2, \PDO::PARAM_INT); // Always fetch more.
|
||||
$query->execute();
|
||||
$posts = $query->fetchAll(\PDO::FETCH_ASSOC);
|
||||
} elseif ($cursor_type === self::CURSOR_TYPE_PREV) {
|
||||
$query = $this->pdo->prepare(sprintf('SELECT * FROM `posts_%s` WHERE `ip` = :ip AND `id` >= :start_id ORDER BY `sticky` ASC, `id` ASC LIMIT :limit', $uri));
|
||||
$query->bindValue(':ip', $ip);
|
||||
$query->bindValue(':start_id', $id_cursor, \PDO::PARAM_INT);
|
||||
$query->bindValue(':limit', $page_size + 2, \PDO::PARAM_INT); // Always fetch more.
|
||||
$query->execute();
|
||||
$posts = \array_reverse($query->fetchAll(\PDO::FETCH_ASSOC));
|
||||
} else {
|
||||
throw new \RuntimeException("Unknown cursor type '$cursor_type'");
|
||||
}
|
||||
|
||||
$posts_count = \count($posts);
|
||||
|
||||
if ($posts_count === $page_size + 2) {
|
||||
$has_extra_prev_post = true;
|
||||
$has_extra_end_post = true;
|
||||
} elseif ($posts_count === $page_size + 1) {
|
||||
$has_extra_prev_post = $id_cursor !== false && $id_cursor === (int)$posts[0]['id'];
|
||||
$has_extra_end_post = !$has_extra_prev_post;
|
||||
} else {
|
||||
$has_extra_prev_post = false;
|
||||
$has_extra_end_post = false;
|
||||
}
|
||||
|
||||
// Since we fetched one post bellow and/or above the limit, we always know if there are any posts after the current page.
|
||||
|
||||
// Get the previous cursor, if any.
|
||||
if ($has_extra_prev_post) {
|
||||
\array_shift($posts);
|
||||
$posts_count--;
|
||||
// Select the most recent post.
|
||||
$prev_cursor_map[$uri] = $posts[0]['id'];
|
||||
}
|
||||
// Get the next cursor, if any.
|
||||
if ($has_extra_end_post) {
|
||||
\array_pop($posts);
|
||||
// Select the oldest post.
|
||||
$next_cursor_map[$uri] = $posts[$posts_count - 2]['id'];
|
||||
}
|
||||
|
||||
$rows[$uri] = $posts;
|
||||
}
|
||||
|
||||
$res = new PageFetchResult();
|
||||
$res->by_uri = $rows;
|
||||
$res->cursor_prev = !empty($prev_cursor_map) ? Net\encode_cursor(self::CURSOR_TYPE_PREV, $prev_cursor_map) : null;
|
||||
$res->cursor_next = !empty($next_cursor_map) ? Net\encode_cursor(self::CURSOR_TYPE_NEXT, $next_cursor_map) : null;
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue