Skip to main content
The Topic model represents a discussion topic in ForkBB. It extends DataModel and provides properties and methods for managing topics, posts, subscriptions, and table of contents.

Location

app/Models/Topic/Topic.php

Properties

id
int
Unique topic identifier
subject
string
Topic subject/title
forum_id
int
ID of the parent forum
poster_id
int
ID of the user who created the topic
posted
int
Timestamp when topic was created
last_post
int
Timestamp of the last post
last_post_id
int
ID of the last post
first_post_id
int
ID of the first post
num_replies
int
Number of replies (posts minus one)
num_views
int
Total view count
closed
int
Topic closed status (0=open, 1=closed)
sticky
int
Sticky/pinned status (0=normal, 1=sticky)
moved_to
int|null
ID of topic this was moved to (for move stubs)
poll_type
int
Poll type (0=no poll, >0=has poll)
solution
int
Post ID marked as solution (0=no solution)
stick_fp
int
Whether to stick first post on all pages
toc
string|null
JSON-encoded table of contents data
page
int
Current page number
subject_color
int
Color number for colored subjects

Computed Properties

parent
Forum|null
Parent forum object
name
string
Censored topic subject
friendly
string
URL-friendly topic name
poll
Poll|null
Poll object if topic has a poll, otherwise null
numPages
int
Total number of pages in the topic
pagination
array
Pagination array for topic pages
showViews
bool
Whether view counts are enabled
tableOfContent
array
Formatted table of contents for the topic
colorNum
int
Color number if colored subjects are enabled

Permission Properties

canReply
bool
Returns true if current user can reply to this topic
canSubscription
bool
Returns true if current user can subscribe to topic updates
canChSolution
bool
Returns true if current user can change the solution post

New/Unread Properties

hasNew
int|false
Timestamp of last visit if topic has new posts, otherwise false
hasUnread
int|false
Timestamp if topic has unread posts, otherwise false
firstNew
int
Post ID of first new post (0 if none)
firstUnread
int
Post ID of first unread post (0 if none)
URL to the topic page
URL to reply to the topic
URL to jump to the last post
URL to jump to first new post
URL to jump to first unread post
URL to subscribe to topic
URL to unsubscribe from topic
Extended breadcrumb link (for scrolling to topic in forum)
URL to jump to the solution post

Methods

hasPage()

Checks if the current page number is valid for this topic.
public function hasPage(): bool
Returns: bool - true if page is valid Example:
$topic = $container->topics->load(123);
$topic->page = 2;

if ($topic->hasPage()) {
    $posts = $topic->pageData();
}

pageData()

Returns an array of posts for the current page.
public function pageData(): array
Returns: Array of post objects Throws: InvalidArgumentException if page number is invalid Example:
$topic = $container->topics->load(123);
$topic->page = 1;

$posts = $topic->pageData();
foreach ($posts as $post) {
    echo $post->html();
}

review()

Returns posts for topic review (latest posts in reverse order).
public function review(): array
Returns: Array of recent posts (limited by config) Example:
$topic = $container->topics->load(123);
$recentPosts = $topic->review();

calcPage()

Calculates which page a specific post is on.
public function calcPage(int $pid): void
pid
int
Post ID to find
Example:
$topic = $container->topics->load(123);
$topic->calcPage(456); // Find page for post 456

if ($topic->page !== null) {
    echo "Post is on page {$topic->page}";
}

incViews()

Increments the view count for the topic.
public function incViews(): void
Example:
$topic = $container->topics->load(123);
$topic->incViews();

updateVisits()

Updates the current user’s last visit and last read markers for this topic.
public function updateVisits(): void
Example:
$topic = $container->topics->load(123);
$topic->updateVisits(); // Mark as visited

addPostToToc()

Adds or updates a post in the topic’s table of contents.
public function addPostToToc(Post $post, bool $merge = false): Topic
post
Post
The post to add (must be parsed by Parser first)
merge
bool
Whether to merge with existing TOC entries
Returns: Self for method chaining Example:
$topic = $container->topics->load(123);
$post = $container->posts->load(456);

// Parse post first
$container->Parser->parseMessage($post->message);

// Add to TOC
$topic->addPostToToc($post);
$container->topics->update($topic);

deleteFromToc()

Removes specific posts from the table of contents.
public function deleteFromToc(int ...$ids): Topic
ids
int...
Variable number of post IDs to remove
Returns: Self for method chaining Example:
$topic = $container->topics->load(123);
$topic->deleteFromToc(456, 457, 458);
$container->topics->update($topic);

Usage Example

// Load a topic
$topic = $container->topics->load(123);

// Display topic info
echo "<h1>{$topic->name}</h1>";
echo "<p>Posted: " . date('Y-m-d', $topic->posted) . "</p>";
echo "<p>Replies: {$topic->num_replies}, Views: {$topic->num_views}</p>";

// Check status
if ($topic->closed) {
    echo "<p>This topic is closed.</p>";
}

if ($topic->sticky) {
    echo "<p><strong>Pinned</strong></p>";
}

// Check permissions
if ($topic->canReply) {
    echo "<a href=\"{$topic->linkReply}\">Reply</a>";
}

// Display new/unread indicators
if ($topic->hasNew !== false) {
    echo "<a href=\"{$topic->linkNew}\">Jump to new posts</a>";
}

if ($topic->hasUnread !== false) {
    echo "<a href=\"{$topic->linkUnread}\">Unread posts</a>";
}

// Get posts for page 1
$topic->page = 1;
if ($topic->hasPage()) {
    $posts = $topic->pageData();
    foreach ($posts as $post) {
        echo "<div class='post'>";
        echo "<strong>{$post->user->username}</strong><br>";
        echo $post->html();
        echo "</div>";
    }
}

// Display table of contents
$toc = $topic->tableOfContent;
if (!empty($toc)) {
    echo "<nav><h3>Table of Contents</h3><ul>";
    foreach ($toc as $item) {
        echo "<li style='margin-left: {$item['level']}em;'>";
        echo "<a href=\"{$item['url']}\">{$item['value']}</a>";
        echo "</li>";
    }
    echo "</ul></nav>";
}

// Display solution link if exists
if ($topic->solution > 0 && $topic->linkGoToSolution) {
    echo "<a href=\"{$topic->linkGoToSolution}\">View Solution</a>";
}

// Get poll if exists
if ($topic->poll) {
    echo "<h3>Poll</h3>";
    // Display poll data
}