self::TYPE_DISCUSSION, 'sticky' => self::TYPE_STICKY, 'announce' => self::TYPE_ANNOUNCE, 'global' => self::TYPE_GLOBAL, ]; public function __construct( private string $id, private string $categoryId, private ?string $userId, private int $type, private string $title, private int $postsCount, private int $deletedPostsCount, private int $viewsCount, private int $created, private int $bumped, private ?int $deleted, private ?int $locked, ) {} public static function fromResult(IDbResult $result): ForumTopicInfo { return new ForumTopicInfo( id: $result->getString(0), categoryId: $result->getString(1), userId: $result->getStringOrNull(2), type: $result->getInteger(3), title: $result->getString(4), viewsCount: $result->getInteger(5), created: $result->getInteger(6), bumped: $result->getInteger(7), deleted: $result->getIntegerOrNull(8), locked: $result->getIntegerOrNull(9), postsCount: $result->getInteger(10), deletedPostsCount: $result->getInteger(11), ); } public function getId(): string { return $this->id; } public function getCategoryId(): string { return $this->categoryId; } public function hasUserId(): bool { return $this->userId !== null; } public function getUserId(): ?string { return $this->userId; } public function getType(): int { return $this->type; } public function getTypeString(): string { return match($this->type) { self::TYPE_GLOBAL => 'global', self::TYPE_ANNOUNCE => 'announce', self::TYPE_STICKY => 'sticky', default => 'discussion', }; } public function isDiscussion(): bool { return $this->type === self::TYPE_DISCUSSION; } public function isSticky(): bool { return $this->type === self::TYPE_STICKY; } public function isAnnouncement(): bool { return $this->type === self::TYPE_ANNOUNCE; } public function isGlobalAnnouncement(): bool { return $this->type === self::TYPE_GLOBAL; } public function isImportant(): bool { return $this->isSticky() || $this->isAnnouncement() || $this->isGlobalAnnouncement(); } public function getIconForDisplay(bool $unread = false): string { if($this->isDeleted()) return 'fas fa-trash-alt fa-fw'; if($this->isAnnouncement() || $this->isGlobalAnnouncement()) return 'fas fa-bullhorn fa-fw'; if($this->isSticky()) return 'fas fa-thumbtack fa-fw'; if($this->isLocked()) return 'fas fa-lock fa-fw'; return sprintf('%s fa-comment fa-fw', $unread ? 'fas' : 'far'); } public function getTitle(): string { return $this->title; } public function getPostsCount(): int { return $this->postsCount; } public function getDeletedPostsCount(): int { return $this->deletedPostsCount; } public function getTotalPostsCount(): int { return $this->postsCount + $this->deletedPostsCount; } public function getViewsCount(): int { return $this->viewsCount; } public function getCreatedTime(): int { return $this->created; } public function getCreatedAt(): DateTime { return DateTime::fromUnixTimeSeconds($this->created); } private static ?DateTime $lastActiveAt = null; public function isActive(): bool { if(self::$lastActiveAt === null) self::$lastActiveAt = DateTime::now()->modify('-1 month'); return $this->getBumpedAt()->isMoreThanOrEqual(self::$lastActiveAt); } public function getBumpedTime(): int { return $this->bumped; } public function getBumpedAt(): DateTime { return DateTime::fromUnixTimeSeconds($this->bumped); } public function isDeleted(): bool { return $this->deleted !== null; } public function getDeletedTime(): ?int { return $this->deleted; } public function getDeletedAt(): ?DateTime { return $this->deleted === null ? null : DateTime::fromUnixTimeSeconds($this->deleted); } public function isLocked(): bool { return $this->locked !== null; } public function getLockedTime(): ?int { return $this->locked; } public function getLockedAt(): ?DateTime { return $this->locked === null ? null : DateTime::fromUnixTimeSeconds($this->locked); } }