123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- <?php
- /**
- * This file is part of the ForkBB <https://github.com/forkbb>.
- *
- * @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
- * @license The MIT License (MIT)
- */
- declare(strict_types=1);
- namespace ForkBB\Models\Topic;
- use ForkBB\Core\Container;
- use ForkBB\Models\DataModel;
- use ForkBB\Models\Forum\Forum;
- use ForkBB\Models\Poll\Poll;
- use PDO;
- use RuntimeException;
- class Topic extends DataModel
- {
- /**
- * Ключ модели для контейнера
- * @var string
- */
- protected $cKey = 'Topic';
- /**
- * Получение родительского раздела
- */
- protected function getparent(): ?Forum
- {
- if ($this->forum_id < 1) {
- throw new RuntimeException('Parent is not defined');
- }
- $forum = $this->c->forums->get($this->forum_id);
- if (
- ! $forum instanceof Forum
- || $forum->redirect_url
- ) {
- return null;
- } else {
- return $forum;
- }
- }
- /**
- * Возвращает отцензурированное название темы
- */
- protected function getname(): ?string
- {
- return $this->censorSubject;
- }
- /**
- * Статус возможности ответа в теме
- */
- protected function getcanReply(): bool
- {
- if ($this->moved_to) {
- return false;
- } elseif ($this->c->user->isAdmin) {
- return true;
- } elseif (
- $this->closed
- || $this->c->user->isBot
- ) {
- return false;
- } elseif (
- 1 === $this->parent->post_replies
- || (
- null === $this->parent->post_replies
- && 1 === $this->c->user->g_post_replies
- )
- || $this->c->user->isModerator($this)
- ) {
- return true;
- } else {
- return false;
- }
- }
- /**
- * Статус возможности использования подписок
- */
- protected function getcanSubscription(): bool
- {
- return 1 === $this->c->config->b_topic_subscriptions
- && $this->id > 0
- && ! $this->c->user->isGuest
- && ! $this->c->user->isUnverified;
- }
- /**
- * Ссылка на тему
- */
- protected function getlink(): string
- {
- return $this->c->Router->link(
- 'Topic',
- [
- 'id' => $this->moved_to ?: $this->id,
- 'name' => $this->name,
- ]
- );
- }
- /**
- * Ссылка для ответа в теме
- */
- protected function getlinkReply(): string
- {
- return $this->c->Router->link(
- 'NewReply',
- [
- 'id' => $this->id,
- ]
- );
- }
- /**
- * Ссылка для перехода на последнее сообщение темы
- */
- protected function getlinkLast(): string
- {
- if (
- $this->moved_to
- || $this->last_post_id < 1
- ) {
- return '';
- } else {
- return $this->c->Router->link(
- 'ViewPost',
- [
- 'id' => $this->last_post_id,
- ]
- );
- }
- }
- /**
- * Ссылка для перехода на первое новое сообщение в теме
- */
- protected function getlinkNew(): string
- {
- return $this->c->Router->link(
- 'TopicViewNew',
- [
- 'id' => $this->id,
- ]
- );
- }
- /**
- * Ссылка для перехода на первое не прочитанное сообщение в теме
- */
- protected function getlinkUnread(): string
- {
- return $this->c->Router->link(
- 'TopicViewUnread',
- [
- 'id' => $this->id,
- ]
- );
- }
- /**
- * Ссылка на подписку
- */
- protected function getlinkSubscribe(): string
- {
- return $this->c->Router->link(
- 'TopicSubscription',
- [
- 'tid' => $this->id,
- 'type' => 'subscribe',
- ]
- );
- }
- /**
- * Ссылка на отписку
- */
- protected function getlinkUnsubscribe(): string
- {
- return $this->c->Router->link(
- 'TopicSubscription',
- [
- 'tid' => $this->id,
- 'type' => 'unsubscribe',
- ]
- );
- }
- /**
- * Статус наличия новых сообщений в теме
- */
- protected function gethasNew() /* : int|false */
- {
- if (
- $this->c->user->isGuest
- || $this->moved_to
- ) {
- return false;
- }
- $time = \max(
- (int) $this->c->user->u_mark_all_read,
- (int) $this->parent->mf_mark_all_read,
- (int) $this->c->user->last_visit,
- (int) $this->mt_last_visit
- );
- return $this->last_post > $time ? $time : false;
- }
- /**
- * Статус наличия непрочитанных сообщений в теме
- */
- protected function gethasUnread() /* int|false */
- {
- if (
- $this->c->user->isGuest
- || $this->moved_to
- ) {
- return false;
- }
- $time = \max(
- (int) $this->c->user->u_mark_all_read,
- (int) $this->parent->mf_mark_all_read,
- (int) $this->mt_last_read
- );
- return $this->last_post > $time ? $time : false;
- }
- /**
- * Номер первого нового сообщения в теме
- */
- protected function getfirstNew(): int
- {
- if (false === $this->hasNew) {
- return 0;
- } elseif ($this->posted > $this->hasNew) {
- return $this->first_post_id;
- }
- $vars = [
- ':tid' => $this->id,
- ':visit' => $this->hasNew,
- ];
- $query = 'SELECT MIN(p.id)
- FROM ::posts AS p
- WHERE p.topic_id=?i:tid AND p.posted>?i:visit';
- return (int) $this->c->DB->query($query, $vars)->fetchColumn();
- }
- /**
- * Номер первого не прочитанного сообщения в теме
- */
- protected function getfirstUnread(): int
- {
- if (false === $this->hasUnread) {
- return 0;
- } elseif ($this->posted > $this->hasUnread) {
- return $this->first_post_id;
- }
- $vars = [
- ':tid' => $this->id,
- ':visit' => $this->hasUnread,
- ];
- $query = 'SELECT MIN(p.id)
- FROM ::posts AS p
- WHERE p.topic_id=?i:tid AND p.posted>?i:visit';
- return (int) $this->c->DB->query($query, $vars)->fetchColumn();
- }
- /**
- * Количество страниц в теме
- */
- protected function getnumPages(): int
- {
- if (null === $this->num_replies) {
- throw new RuntimeException('The model does not have the required data');
- }
- return (int) \ceil(($this->num_replies + 1) / $this->c->user->disp_posts);
- }
- /**
- * Массив страниц темы
- */
- protected function getpagination(): array
- {
- $page = (int) $this->page;
- if (
- $page < 1
- && 1 === $this->numPages
- ) {
- // 1 страницу в списке тем раздела не отображаем
- return [];
- } else { //????
- return $this->c->Func->paginate(
- $this->numPages,
- $page,
- 'Topic',
- [
- 'id' => $this->id,
- 'name' => $this->name,
- ]
- );
- }
- }
- /**
- * Статус наличия установленной страницы в теме
- */
- public function hasPage(): bool
- {
- return $this->page > 0 && $this->page <= $this->numPages;
- }
- /**
- * Возвращает массив сообщений с установленной страницы
- */
- public function pageData(): array
- {
- if (! $this->hasPage()) {
- throw new InvalidArgumentException('Bad number of displayed page');
- }
- $vars = [
- ':tid' => $this->id,
- ':offset' => ($this->page - 1) * $this->c->user->disp_posts,
- ':rows' => $this->c->user->disp_posts,
- ];
- $query = 'SELECT p.id
- FROM ::posts AS p
- WHERE p.topic_id=?i:tid
- ORDER BY p.id
- LIMIT ?i:rows OFFSET ?i:offset';
- $list = $this->c->DB->query($query, $vars)->fetchAll(PDO::FETCH_COLUMN);
- if (
- ! empty($list)
- && (
- $this->stick_fp
- || (
- $this->poll_type > 0
- && 1 === $this->c->config->b_poll_enabled
- )
- )
- && ! \in_array($this->first_post_id, $list)
- ) {
- \array_unshift($list, $this->first_post_id);
- }
- $this->idsList = $list;
- return empty($this->idsList) ? [] : $this->c->posts->view($this);
- }
- /**
- * Возвращает массив сообщений обзора темы
- */
- public function review(): array
- {
- if ($this->c->config->i_topic_review < 1) {
- return [];
- }
- $this->page = 1;
- $vars = [
- ':tid' => $this->id,
- ':rows' => $this->c->config->i_topic_review,
- ];
- $query = 'SELECT p.id
- FROM ::posts AS p
- WHERE p.topic_id=?i:tid
- ORDER BY p.id DESC
- LIMIT ?i:rows';
- $this->idsList = $this->c->DB->query($query, $vars)->fetchAll(PDO::FETCH_COLUMN);
- return empty($this->idsList) ? [] : $this->c->posts->view($this, true);
- }
- /**
- * Вычисляет страницу темы на которой находится данное сообщение
- */
- public function calcPage(int $pid): void
- {
- $vars = [
- ':tid' => $this->id,
- ':pid' => $pid,
- ];
- $query = 'SELECT COUNT(p.id) AS pnum, MAX(p.id) as pmax
- FROM ::posts AS p
- WHERE p.topic_id=?i:tid AND p.id<=?i:pid';
- $result = $this->c->DB->query($query, $vars)->fetch();
- if (
- empty($result['pmax'])
- || $result['pmax'] !== $pid
- ) {
- $this->page = null;
- } else {
- $this->page = (int) \ceil($result['pnum'] / $this->c->user->disp_posts);
- }
- }
- /**
- * Статус показа/подсчета просмотров темы
- */
- protected function getshowViews(): bool
- {
- return 1 === $this->c->config->b_topic_views;
- }
- /**
- * Увеличивает на 1 количество просмотров темы
- */
- public function incViews(): void
- {
- $vars = [
- ':tid' => $this->id,
- ];
- $query = 'UPDATE ::topics
- SET num_views=num_views+1
- WHERE id=?i:tid';
- $this->c->DB->exec($query, $vars);
- }
- /**
- * Обновление меток последнего визита и последнего прочитанного сообщения
- */
- public function updateVisits(): void
- {
- if ($this->c->user->isGuest) {
- return;
- }
- $vars = [
- ':uid' => $this->c->user->id,
- ':tid' => $this->id,
- ':read' => (int) $this->mt_last_read,
- ':visit' => (int) $this->mt_last_visit,
- ];
- $flag = false;
- if (false !== $this->hasNew) {
- $flag = true;
- $vars[':visit'] = $this->last_post;
- }
- if (
- false !== $this->hasUnread
- && $this->timeMax > $this->hasUnread
- ) {
- $flag = true;
- $vars[':read'] = $this->timeMax;
- $vars[':visit'] = $this->last_post;
- }
- if ($flag) {
- if (
- empty($this->mt_last_read)
- && empty($this->mt_last_visit)
- ) {
- $query = 'INSERT INTO ::mark_of_topic (uid, tid, mt_last_visit, mt_last_read)
- SELECT ?i:uid, ?i:tid, ?i:visit, ?i:read
- FROM ::groups
- WHERE NOT EXISTS (
- SELECT 1
- FROM ::mark_of_topic
- WHERE uid=?i:uid AND tid=?i:tid
- )
- LIMIT 1';
- } else {
- $query = 'UPDATE ::mark_of_topic
- SET mt_last_visit=?i:visit, mt_last_read=?i:read
- WHERE uid=?i:uid AND tid=?i:tid';
- }
- $this->c->DB->exec($query, $vars);
- }
- }
- /**
- * Возвращает опрос при его наличии
- */
- protected function getpoll(): ?Poll
- {
- return $this->poll_type > 0 ? $this->c->polls->load($this->id) : null;
- }
- }
|