Add Models\PM\PTopic

This commit is contained in:
Visman 2021-03-30 22:12:15 +07:00
parent 1da4df45ab
commit 8fd97d4140

455
app/Models/PM/PTopic.php Normal file
View file

@ -0,0 +1,455 @@
<?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\PM;
use ForkBB\Core\Container;
use ForkBB\Models\DataModel;
use ForkBB\Models\PM\Cnst;
use ForkBB\Models\User\Model as User;
use PDO;
use RuntimeException;
class PTopic extends DataModel
{
public function __construct(Container $container)
{
parent::__construct($container);
$this->zDepend = [
'id' => ['link', 'hasNew', 'linkNew', 'firstNew', 'pagination', 'dataReply', 'linkReply'],
'last_number' => ['last_poster'],
'last_post_id' => ['linkLast'],
'num_replies' => ['numPages', 'pagination'],
'poster' => ['last_poster', 'byOrFor', 'zpUser', 'ztUser'],
'poster_id' => ['closed', 'firstNew', 'zp', 'zt', 'zpUser', 'ztUser'],
'poster_status' => ['closed'],
'poster_visit' => ['firstNew'],
'subject' => ['name'],
'target' => ['last_poster', 'byOrFor', 'zpUser', 'ztUser'],
'target_id' => ['closed', 'firstNew', 'zp', 'zt', 'zpUser', 'ztUser'],
'target_status' => ['closed'],
'target_visit' => ['firstNew'],
];
}
/**
* Префикс текущего пользователя
*/
protected function getzp(): string
{
if ($this->poster_id === $this->c->user->id) {
return 'poster';
} elseif ($this->target_id === $this->c->user->id) {
return 'target';
} else {
throw new RuntimeException('Bad current user');
}
}
/**
* Префикс второго пользователя
*/
protected function getzt(): string
{
if ($this->poster_id === $this->c->user->id) {
return 'target';
} elseif ($this->target_id === $this->c->user->id) {
return 'poster';
} else {
throw new RuntimeException('Bad current user');
}
}
/**
* Возвращает отцензурированное название темы
*/
protected function getname(): ?string
{
return $this->censorSubject;
}
/**
* Ссылка на тему
*/
protected function getlink(): string
{
return $this->c->Router->link(
'PMAction',
[
'second' => $this->c->pms->second,
'action' => Cnst::ACTION_TOPIC,
'more1' => $this->id,
]
);
}
/**
* Ссылка для перехода на последнее сообщение темы
*/
protected function getlinkLast(): string
{
if ($this->last_post_id < 1) {
return '';
} else {
return $this->c->Router->link(
'PMAction',
[
'second' => $this->c->pms->second,
'action' => Cnst::ACTION_POST,
'more1' => $this->last_post_id,
'numPost' => $this->last_post_id,
]
);
}
}
/**
* Ссылка для перехода на первое новое сообщение в теме
*/
protected function getlinkNew(): string
{
return $this->c->Router->link(
'PMAction',
[
'second' => $this->c->pms->second,
'action' => Cnst::ACTION_TOPIC,
'more1' => $this->id,
'more2' => 'new',
]
);
}
/**
* Номер первого нового сообщения в теме
*/
protected function getfirstNew(): int
{
if (! $this->hasNew) {
return 0;
}
$vars = [
':tid' => $this->id,
':visit' => $this->{"{$this->zp}_visit"},
];
$query = 'SELECT MIN(pp.id)
FROM ::pm_posts AS pp
WHERE pp.topic_id=?i:tid AND pp.posted>?i:visit';
$pid = $this->c->DB->query($query, $vars)->fetchColumn();
return $pid ?: 0;
}
protected function setsender(User $user): void
{
$this->poster = $user->username;
$this->poster_id = $user->id;
}
protected function setrecipient(User $user): void
{
$this->target = $user->username;
$this->target_id = $user->id;
}
protected function user(string $prx): User
{
$user = $this->c->users->load($this->{"{$prx}_id"});
if (! $user instanceof User) {
throw new RuntimeException('User model could not be loaded ');
} elseif ($user->isGuest) {
$user = clone $user;
$user->__username = $this->{$prx};
}
return $user;
}
protected function getzpUser(): User
{
return $this->user($this->zp);
}
protected function getztUser(): User
{
return $this->user($this->zt);
}
protected function setstatus(int $status): void
{
if ('poster' === $this->zp) {
$tStatus = $status;
switch ($status) {
case Cnst::PT_ARCHIVE:
$tStatus = Cnst::PT_NOTSENT;
case Cnst::PT_DELETED:
case Cnst::PT_NORMAL:
$this->poster_status = $status;
if (null === $this->target_status) {
$this->target_status = $tStatus;
}
return;
}
} else {
switch ($status) {
case Cnst::PT_ARCHIVE:
case Cnst::PT_DELETED:
$this->target_status = $status;
return;
}
}
throw new RuntimeException("Bad status: {$status}");
}
/**
* Возвращает имя автора последнего поста или пустую строку
*/
protected function getlast_poster(): string
{
if (0 === $this->last_number) {
return $this->poster;
} elseif (1 === $this->last_number) {
return $this->target;
} else {
return '';
}
}
/**
* Статус наличия новых сообщений в теме
*/
protected function gethasNew(): bool
{
return isset($this->c->pms->idsNew[$this->id]);
}
/**
* Статус закрытия темы
*/
protected function getclosed(): bool
{
$p = $this->{"{$this->zp}_status"};
$t = $this->{"{$this->zt}_status"};
return Cnst::PT_DELETED === $t
|| Cnst::PT_ARCHIVE === $t
|| (
Cnst::PT_ARCHIVE === $p
&& Cnst::PT_NOTSENT !== $t
);
}
protected function getbyOrFor(): array
{
if ('poster' === $this->zp) {
return ['for %s', $this->target];
} else {
return ['by %s', $this->poster];
}
}
/**
* Количество страниц в теме
*/
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);
}
/**
* Статус наличия установленной страницы в теме
*/
public function hasPage(): bool
{
return $this->page > 0 && $this->page <= $this->numPages;
}
/**
* Массив страниц темы
*/
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,
'PMAction',
[
'second' => $this->c->pms->second,
'action' => Cnst::ACTION_TOPIC,
'more1' => $this->id,
'page' => 'more2', // нестандарная переменная для page
]
);
}
}
/**
* Вычисляет страницу темы на которой находится данное сообщение
*/
public function calcPage(int $pid): void
{
$vars = [
':tid' => $this->id,
':pid' => $pid,
];
$query = 'SELECT COUNT(pp.id) AS pnum, MAX(pp.id) as pmax
FROM ::pm_posts AS pp
WHERE pp.topic_id=?i:tid AND pp.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);
}
}
/**
* Возвращает массив сообщений с установленной страницы
*/
public function pageData(): array
{
if (! $this->hasPage()) {
throw new InvalidArgumentException('Bad number of displayed page');
}
$count = ($this->page - 1) * $this->c->user->disp_posts;
$vars = [
':tid' => $this->id,
':offset' => $count,
':rows' => $this->c->user->disp_posts,
];
$query = 'SELECT pp.id
FROM ::pm_posts AS pp
WHERE pp.topic_id=?i:tid
ORDER BY pp.id
LIMIT ?i:offset, ?i:rows';
$list = $this->c->DB->query($query, $vars)->fetchAll(PDO::FETCH_COLUMN);
$posts = $this->c->pms->loadByIds(Cnst::PPOST, $list);
foreach ($posts as $post) {
++$count;
if ($post instanceof PPost) {
$post->__postNumber = $count;
}
}
return $posts;
}
/**
* Обновляет метку визита
*/
public function updateVisit(): void
{
$visit = $this->{"{$this->zp}_visit"};
if ($visit >= $this->last_post) {
return;
}
$this->{"{$this->zp}_visit"} = $this->last_post;
$this->c->pms->update(Cnst::PTOPIC, $this);
$this->c->pms->updateFromPTopics(false, $this);
}
/**
* Возвращает массив сообщений обзора темы
*/
public function review(): array
{
if ($this->c->config->i_topic_review < 1) {
return [];
}
$count = $this->num_replies + 1;
$vars = [
':tid' => $this->id,
':rows' => $this->c->config->i_topic_review,
];
$query = 'SELECT pp.id
FROM ::pm_posts AS pp
WHERE pp.topic_id=?i:tid
ORDER BY pp.id DESC
LIMIT 0, ?i:rows';
$list = $this->c->DB->query($query, $vars)->fetchAll(PDO::FETCH_COLUMN);
$posts = $this->c->pms->loadByIds(Cnst::PPOST, $list);
foreach ($posts as $post) {
if ($post instanceof PPost) {
$post->__postNumber = $count;
}
--$count;
}
return $posts;
}
/**
* Статус возможности ответа в теме
*/
protected function getcanReply(): bool
{
return ! $this->closed;
// + куча условий!!!!!!!!!!
}
/**
* Аргументы для ссылки для ответа в теме
*/
protected function getdataReply(): array
{
return [
'second' => $this->c->pms->second,
'action' => Cnst::ACTION_SEND,
'more1' => $this->id,
];
}
/**
* Ссылка для ответа в теме
*/
protected function getlinkReply(): string
{
return $this->c->Router->link('PMAction', $this->dataReply);
}
}