aboutsummaryrefslogtreecommitdiff
path: root/lib/models/Forum/Topic.php
blob: a6b298f7955ee319a36d68911df4939e637b1904 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<?php
namespace Forum;

use DBManager;
use Range;
use SimpleORMap;
use User;

/**
 * @property string $topic_id
 * @property string $category_id
 * @property string $range_id
 * @property string $name
 * @property string $description
 * @property int $position
 * @property int $mkdate
 * @property int $chdate
 *
 * @property Range $range
 * @property Category $category
 * @property Discussion[] $discussions
 * @property User[] $users
 * @property array $metadata
 */

class Topic extends SimpleORMap
{
    protected static function configure($config = [])
    {
        $config['db_table'] = 'forum_topics';

        $config['belongs_to']['category'] = [
            'class_name' => Category::class,
            'foreign_key' => 'category_id',
            'assoc_foreign_key' => 'category_id'
        ];

        $config['has_many']['discussions'] = [
            'class_name' => Discussion::class,
            'foreign_key' => 'topic_id',
            'assoc_func' => 'getDiscussions',
            'assoc_foreign_key' => 'topic_id',
        ];

        $config['additional_fields']['range'] = [
            'set' => function (Topic $topic, string $field, Range $range) {
                $topic->range_id = $range->getRangeId();
            },
            'get' => function (Topic $topic): Range {
                return get_object_by_range_id($topic->range_id);
            },
        ];

        $config['additional_fields']['users']['get'] = 'getUsers';
        $config['additional_fields']['metadata']['get'] = 'getMetaData';
        $config['registered_callbacks']['after_delete'][] = 'onDelete';

        parent::configure($config);
    }

    /**
     * @return self[]
     */
    public static function getCourseTopics(string $range_id): array
    {
        return self::findBySQL(
            "range_id = :range_id
                GROUP BY CASE WHEN category_id IS NULL THEN topic_id ELSE category_id END
                ORDER BY position ASC, mkdate DESC",
            ["range_id" => $range_id]
        );
    }

    public static function getCourseTopic(string $range_id, string $topic_id): self
    {
        return self::findOneBySQL("range_id = ? AND topic_id = ?", [$range_id, $topic_id]);
    }

    public function getUsers($last_visit = null): array
    {
        $query = [
            "JOIN forum_postings USING(user_id)
            JOIN forum_discussions USING(discussion_id)
            WHERE forum_discussions.topic_id = :topic_id ",
            ['topic_id' => $this->topic_id]
        ];

        if ($last_visit) {
            $query[0] .= " AND forum_postings.mkdate > :last_visit";
            $query[1]["last_visit"] = $last_visit;
        }

        $users = User::findBySQL($query[0]." ORDER BY forum_postings.mkdate DESC", $query[1]);

        $unique_users = [];
        foreach ($users as $user) {
            $unique_users[$user->user_id] = $user;
        }

        return array_values($unique_users);
    }

    /**
     * @return Discussion[]
     */
    public function getDiscussions(): array
    {
        return DBManager::get()->fetchAll(
            "SELECT
                    discussions.*,
                    MAX(postings.mkdate) AS latest_post_date
                FROM forum_discussions AS discussions
                JOIN forum_postings as postings USING (discussion_id)
                WHERE discussions.topic_id = :topic_id
                GROUP BY discussions.discussion_id
                ORDER BY discussions.sticky DESC, latest_post_date DESC",
            ['topic_id' => $this->topic_id],
            Discussion::buildExisting(...)
        );
    }

    public function getMetaData(): array
    {
        return DBManager::get()->fetchOne(
            "SELECT
                        COUNT(DISTINCT `forum_discussions`.`discussion_id`) AS 'discussions_count',
                        COUNT(DISTINCT `forum_postings`.`posting_id`) AS 'postings_count',
                        COUNT(DISTINCT `forum_postings`.`user_id`) AS 'users_count',
                        MAX(`forum_postings`.`mkdate`) AS 'recent_activity',
                        (
                            SELECT
                                SUM(fpr.read_index)
                            FROM forum_discussions fd2
                            JOIN forum_posting_reads fpr
                                ON fpr.discussion_id = fd2.discussion_id
                               AND fpr.user_id = :user_id
                            WHERE fd2.topic_id = :topic_id
                        ) AS 'user_read_index'
                    FROM `forum_discussions`
                    LEFT JOIN `forum_postings` USING (`discussion_id`)
                    WHERE `forum_discussions`.`topic_id` = :topic_id",
            [
                'topic_id' => $this->topic_id,
                'user_id' => User::findCurrent()->user_id
            ]
        );
    }

    public function transformData(): array
    {
        return [
            'topic_id' => $this->topic_id,
            'category_id' => $this->category_id,
            'range_id' => $this->range_id,
            'name' => $this->name,
            'description' => $this->description,
            'position' => $this->position,
            'chdate' => date('c', $this->chdate),
            'mkdate' => date('c', $this->mkdate)
        ];
    }

    public function onDelete(): void
    {
        Subscription::deleteBySQL("subject_id = ?", [$this->topic_id]);
        Discussion::deleteBySQL("topic_id = ?", [$this->topic_id]);
    }
}