Add Models\PM\PTopic
This commit is contained in:
parent
1da4df45ab
commit
8fd97d4140
1 changed files with 455 additions and 0 deletions
455
app/Models/PM/PTopic.php
Normal file
455
app/Models/PM/PTopic.php
Normal 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);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue