321 lines
9.0 KiB
PHP
321 lines
9.0 KiB
PHP
<?php
|
|
|
|
class Post extends model {
|
|
|
|
const DB_TABLE = 'posts';
|
|
|
|
public int $id;
|
|
public string $title;
|
|
public string $md;
|
|
public string $html;
|
|
public string $tocHtml;
|
|
public string $text;
|
|
public int $ts;
|
|
public int $updateTs;
|
|
public bool $visible;
|
|
public bool $toc;
|
|
public string $shortName;
|
|
|
|
function edit(array $fields) {
|
|
$cur_ts = time();
|
|
if (!$this->visible && $fields['visible'])
|
|
$fields['ts'] = $cur_ts;
|
|
|
|
$fields['update_ts'] = $cur_ts;
|
|
|
|
if ($fields['md'] != $this->md) {
|
|
$fields['html'] = markup::markdownToHtml($fields['md']);
|
|
$fields['text'] = markup::htmlToText($fields['html']);
|
|
}
|
|
|
|
if ((isset($fields['toc']) && $fields['toc']) || $this->toc) {
|
|
$fields['toc_html'] = markup::toc($fields['md']);
|
|
}
|
|
|
|
parent::edit($fields);
|
|
$this->updateImagePreviews();
|
|
}
|
|
|
|
function updateHtml() {
|
|
$html = markup::markdownToHtml($this->md);
|
|
$this->html = $html;
|
|
|
|
DB()->query("UPDATE posts SET html=? WHERE id=?", $html, $this->id);
|
|
}
|
|
|
|
function updateText() {
|
|
$html = markup::markdownToHtml($this->md);
|
|
$text = markup::htmlToText($html);
|
|
$this->text = $text;
|
|
|
|
DB()->query("UPDATE posts SET text=? WHERE id=?", $text, $this->id);
|
|
}
|
|
|
|
function getDescriptionPreview(int $len): string {
|
|
if (mb_strlen($this->text) >= $len)
|
|
return mb_substr($this->text, 0, $len-3).'...';
|
|
return $this->text;
|
|
}
|
|
|
|
function getFirstImage(): ?Upload {
|
|
if (!preg_match('/\{image:([\w]{8})/', $this->md, $match))
|
|
return null;
|
|
return uploads::getUploadByRandomId($match[1]);
|
|
}
|
|
|
|
function getUrl(): string {
|
|
return $this->shortName != '' ? "/{$this->shortName}/" : "/{$this->id}/";
|
|
}
|
|
|
|
function getDate(): string {
|
|
return date('j M', $this->ts);
|
|
}
|
|
|
|
function getYear(): int {
|
|
return (int)date('Y', $this->ts);
|
|
}
|
|
|
|
function getFullDate(): string {
|
|
return date('j F Y', $this->ts);
|
|
}
|
|
|
|
function getUpdateDate(): string {
|
|
return date('j M', $this->updateTs);
|
|
}
|
|
|
|
function getFullUpdateDate(): string {
|
|
return date('j F Y', $this->updateTs);
|
|
}
|
|
|
|
function getHtml(bool $is_retina, string $theme): string {
|
|
$html = $this->html;
|
|
$html = markup::htmlImagesFix($html, $is_retina, $theme);
|
|
return $html;
|
|
}
|
|
|
|
function getToc(): ?string {
|
|
return $this->toc ? $this->tocHtml : null;
|
|
}
|
|
|
|
function isUpdated(): bool {
|
|
return $this->updateTs && $this->updateTs != $this->ts;
|
|
}
|
|
|
|
/**
|
|
* @return Tag[]
|
|
*/
|
|
function getTags(): array {
|
|
$db = DB();
|
|
$q = $db->query("SELECT tags.* FROM posts_tags
|
|
LEFT JOIN tags ON tags.id=posts_tags.tag_id
|
|
WHERE posts_tags.post_id=?
|
|
ORDER BY posts_tags.tag_id", $this->id);
|
|
return array_map('Tag::create_instance', $db->fetchAll($q));
|
|
}
|
|
|
|
/**
|
|
* @return int[]
|
|
*/
|
|
function getTagIds(): array {
|
|
$ids = [];
|
|
$db = DB();
|
|
$q = $db->query("SELECT tag_id FROM posts_tags WHERE post_id=? ORDER BY tag_id", $this->id);
|
|
while ($row = $db->fetch($q)) {
|
|
$ids[] = (int)$row['tag_id'];
|
|
}
|
|
return $ids;
|
|
}
|
|
|
|
function setTagIds(array $new_tag_ids) {
|
|
$cur_tag_ids = $this->getTagIds();
|
|
$add_tag_ids = array_diff($new_tag_ids, $cur_tag_ids);
|
|
$rm_tag_ids = array_diff($cur_tag_ids, $new_tag_ids);
|
|
|
|
$db = DB();
|
|
if (!empty($add_tag_ids)) {
|
|
$rows = [];
|
|
foreach ($add_tag_ids as $id)
|
|
$rows[] = ['post_id' => $this->id, 'tag_id' => $id];
|
|
$db->multipleInsert('posts_tags', $rows);
|
|
}
|
|
|
|
if (!empty($rm_tag_ids))
|
|
$db->query("DELETE FROM posts_tags WHERE post_id=? AND tag_id IN(".implode(',', $rm_tag_ids).")", $this->id);
|
|
|
|
$upd_tag_ids = array_merge($new_tag_ids, $rm_tag_ids);
|
|
$upd_tag_ids = array_unique($upd_tag_ids);
|
|
foreach ($upd_tag_ids as $id)
|
|
tags::recountTagPosts($id);
|
|
}
|
|
|
|
/**
|
|
* @param bool $update Whether to overwrite preview if already exists
|
|
* @return int
|
|
* @throws Exception
|
|
*/
|
|
function updateImagePreviews(bool $update = false): int {
|
|
$images = [];
|
|
if (!preg_match_all('/\{image:([\w]{8}),(.*?)}/', $this->md, $matches))
|
|
return 0;
|
|
|
|
for ($i = 0; $i < count($matches[0]); $i++) {
|
|
$id = $matches[1][$i];
|
|
$w = $h = null;
|
|
$opts = explode(',', $matches[2][$i]);
|
|
foreach ($opts as $opt) {
|
|
if (str_contains($opt, '=')) {
|
|
list($k, $v) = explode('=', $opt);
|
|
if ($k == 'w')
|
|
$w = (int)$v;
|
|
else if ($k == 'h')
|
|
$h = (int)$v;
|
|
}
|
|
}
|
|
$images[$id][] = [$w, $h];
|
|
}
|
|
|
|
if (empty($images))
|
|
return 0;
|
|
|
|
$images_affected = 0;
|
|
$uploads = uploads::getUploadsByRandomId(array_keys($images), true);
|
|
foreach ($uploads as $u) {
|
|
foreach ($images[$u->randomId] as $s) {
|
|
list($w, $h) = $s;
|
|
list($w, $h) = $u->getImagePreviewSize($w, $h);
|
|
if ($u->createImagePreview($w, $h, $update, $u->imageMayHaveAlphaChannel()))
|
|
$images_affected++;
|
|
}
|
|
}
|
|
|
|
return $images_affected;
|
|
}
|
|
|
|
}
|
|
|
|
class posts {
|
|
|
|
static function getCount(bool $include_hidden = false): int {
|
|
$db = DB();
|
|
$sql = "SELECT COUNT(*) FROM posts";
|
|
if (!$include_hidden) {
|
|
$sql .= " WHERE visible=1";
|
|
}
|
|
return (int)$db->result($db->query($sql));
|
|
}
|
|
|
|
static function getCountByTagId(int $tag_id, bool $include_hidden = false): int {
|
|
$db = DB();
|
|
if ($include_hidden) {
|
|
$sql = "SELECT COUNT(*) FROM posts_tags WHERE tag_id=?";
|
|
} else {
|
|
$sql = "SELECT COUNT(*) FROM posts_tags
|
|
LEFT JOIN posts ON posts.id=posts_tags.post_id
|
|
WHERE posts_tags.tag_id=? AND posts.visible=1";
|
|
}
|
|
return (int)$db->result($db->query($sql, $tag_id));
|
|
}
|
|
|
|
/**
|
|
* @return Post[]
|
|
*/
|
|
static function getList(int $offset = 0, int $count = -1, bool $include_hidden = false): array {
|
|
$db = DB();
|
|
$sql = "SELECT * FROM posts";
|
|
if (!$include_hidden)
|
|
$sql .= " WHERE visible=1";
|
|
$sql .= " ORDER BY ts DESC";
|
|
if ($offset != 0 && $count != -1)
|
|
$sql .= "LIMIT $offset, $count";
|
|
$q = $db->query($sql);
|
|
return array_map('Post::create_instance', $db->fetchAll($q));
|
|
}
|
|
|
|
/**
|
|
* @return Post[]
|
|
*/
|
|
static function getPostsByTagId(int $tag_id, bool $include_hidden = false): array {
|
|
$db = DB();
|
|
$sql = "SELECT posts.* FROM posts_tags
|
|
LEFT JOIN posts ON posts.id=posts_tags.post_id
|
|
WHERE posts_tags.tag_id=?";
|
|
if (!$include_hidden)
|
|
$sql .= " AND posts.visible=1";
|
|
$sql .= " ORDER BY posts.ts DESC";
|
|
$q = $db->query($sql, $tag_id);
|
|
return array_map('Post::create_instance', $db->fetchAll($q));
|
|
}
|
|
|
|
static function add(array $data = []): int|bool {
|
|
$db = DB();
|
|
|
|
$html = \markup::markdownToHtml($data['md']);
|
|
$text = \markup::htmlToText($html);
|
|
|
|
$data += [
|
|
'ts' => time(),
|
|
'html' => $html,
|
|
'text' => $text,
|
|
];
|
|
|
|
if (!$db->insert('posts', $data))
|
|
return false;
|
|
|
|
$id = $db->insertId();
|
|
|
|
$post = self::get($id);
|
|
$post->updateImagePreviews();
|
|
|
|
return $id;
|
|
}
|
|
|
|
static function delete(Post $post): void {
|
|
$tags = $post->getTags();
|
|
|
|
$db = DB();
|
|
$db->query("DELETE FROM posts WHERE id=?", $post->id);
|
|
$db->query("DELETE FROM posts_tags WHERE post_id=?", $post->id);
|
|
|
|
foreach ($tags as $tag)
|
|
tags::recountTagPosts($tag->id);
|
|
}
|
|
|
|
static function get(int $id): ?Post {
|
|
$db = DB();
|
|
$q = $db->query("SELECT * FROM posts WHERE id=?", $id);
|
|
return $db->numRows($q) ? new Post($db->fetch($q)) : null;
|
|
}
|
|
|
|
static function getByName(string $short_name): ?Post {
|
|
$db = DB();
|
|
$q = $db->query("SELECT * FROM posts WHERE short_name=?", $short_name);
|
|
return $db->numRows($q) ? new Post($db->fetch($q)) : null;
|
|
}
|
|
|
|
static function getPostsById(array $ids, bool $flat = false): array {
|
|
if (empty($ids)) {
|
|
return [];
|
|
}
|
|
|
|
$db = DB();
|
|
$posts = array_fill_keys($ids, null);
|
|
|
|
$q = $db->query("SELECT * FROM posts WHERE id IN(".implode(',', $ids).")");
|
|
|
|
while ($row = $db->fetch($q)) {
|
|
$posts[(int)$row['id']] = new Post($row);
|
|
}
|
|
|
|
if ($flat) {
|
|
$list = [];
|
|
foreach ($ids as $id) {
|
|
$list[] = $posts[$id];
|
|
}
|
|
unset($posts);
|
|
return $list;
|
|
}
|
|
|
|
return $posts;
|
|
}
|
|
|
|
} |