Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 109
0.00% covered (danger)
0.00%
0 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 1
ThreadRevision
0.00% covered (danger)
0.00%
0 / 109
0.00% covered (danger)
0.00%
0 / 15
930
0.00% covered (danger)
0.00%
0 / 1
 loadFromId
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 loadFromRow
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 create
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
20
 insert
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 save
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 getRow
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 getTimestamp
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getUser
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getChangeType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getChangeObject
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
30
 getChangeComment
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getThreadObj
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 prev
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 next
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3use MediaWiki\MediaWikiServices;
4use MediaWiki\User\User;
5
6class ThreadRevision {
7    /** @var string[] */
8    public static $load =
9        [
10            'th_id'             => 'mId',
11            'th_thread'         => 'mThreadId',
12
13            'th_timestamp'      => 'mTimestamp',
14
15            'th_user'           => 'mUserId',
16            'th_user_text'      => 'mUserText',
17
18            'th_change_type'    => 'mChangeType',
19            'th_change_object'  => 'mChangeObjectId',
20            'th_change_comment' => 'mChangeComment',
21            'th_content'        => 'mObjSer',
22        ];
23
24    /** @var int */
25    protected $mId;
26    /** @var int */
27    protected $mThreadId;
28    /** @var string */
29    protected $mTimestamp;
30    /** @var User */
31    protected $mUser;
32    /** @var int */
33    protected $mUserId;
34    /** @var string */
35    protected $mUserText;
36    /** @var int */
37    protected $mChangeType;
38    /** @var int */
39    protected $mChangeObjectId;
40    /** @var Thread|null|false */
41    protected $mChangeObject;
42    /** @var string */
43    protected $mChangeComment;
44    /** @var string|null */
45    protected $mObjSer;
46    /** @var Thread|false|null */
47    protected $mThreadObj;
48
49    public static function loadFromId( $id ) {
50        $dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
51        $row = $dbr->newSelectQueryBuilder()
52            ->select( '*' )
53            ->from( 'thread_history' )
54            ->where( [ 'th_id' => $id ] )
55            ->caller( __METHOD__ )
56            ->fetchRow();
57
58        if ( !$row ) {
59            return null;
60        }
61
62        return self::loadFromRow( $row );
63    }
64
65    public static function loadFromRow( $row ) {
66        if ( !$row ) {
67            return null;
68        }
69
70        $rev = new ThreadRevision;
71
72        foreach ( self::$load as $col => $field ) {
73            $rev->$field = $row->$col;
74        }
75
76        $rev->mUser = User::newFromName( $rev->mUserText, /* Don't validate */ false );
77        $rev->mThreadObj = unserialize( $rev->mObjSer );
78
79        return $rev;
80    }
81
82    public static function create(
83        Thread $thread,
84        $change_type,
85        User $user,
86        $change_object = null,
87        $comment = ''
88    ) {
89        $timestamp = wfTimestampNow();
90
91        if ( $comment === null ) {
92            $comment = '';
93        }
94
95        $rev = new ThreadRevision;
96
97        $rev->mThreadId = $thread->topmostThread()->id();
98        $rev->mTimestamp = $timestamp;
99
100        $rev->mUser = $user;
101        $rev->mUserId = $user->getId();
102        $rev->mUserText = $user->getName();
103
104        $rev->mChangeType = $change_type;
105
106        if ( $change_object instanceof Thread ) {
107            $rev->mChangeObjectId = $change_object->id();
108            $rev->mChangeObject = $change_object;
109        } elseif ( $change_object === null ) {
110            $rev->mChangeObjectId = $thread->id();
111            $rev->mChangeObject = $thread;
112        } else {
113            $rev->mChangeObjectId = $change_object;
114        }
115
116        // This field is TINYTEXT so it can only fit 255 bytes.
117        $rev->mChangeComment = MediaWikiServices::getInstance()->getContentLanguage()
118            ->truncateForDatabase( $comment, 255 );
119
120        $rev->mThreadObj = $thread->topmostThread();
121        $rev->mObjSer = serialize( $rev->mThreadObj );
122
123        $rev->insert();
124
125        return $rev;
126    }
127
128    public function insert() {
129        $dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
130
131        $row = $this->getRow();
132
133        $dbw->newInsertQueryBuilder()
134            ->insertInto( 'thread_history' )
135            ->row( $row )
136            ->caller( __METHOD__ )
137            ->execute();
138
139        $this->mId = $dbw->insertId();
140    }
141
142    public function save() {
143        $row = $this->getRow();
144
145        $dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
146
147        $dbw->newReplaceQueryBuilder()
148            ->replaceInto( 'thread_history' )
149            ->uniqueIndexFields( 'th_thread' )
150            ->row( $row )
151            ->caller( __METHOD__ )
152            ->execute();
153    }
154
155    public function getRow() {
156        $row = [];
157
158        // First, prep the data for insertion
159        $dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
160        $this->mTimestamp = $dbw->timestamp( $this->mTimestamp );
161
162        foreach ( self::$load as $col => $field ) {
163            $row[$col] = $this->$field;
164        }
165
166        return $row;
167    }
168
169    public function getTimestamp() {
170        return wfTimestamp( TS_MW, $this->mTimestamp );
171    }
172
173    public function getUser() {
174        if ( $this->mUserId ) {
175            return User::newFromId( $this->mUserId );
176        }
177
178        return User::newFromName( $this->mUserText, /* No validation */ false );
179    }
180
181    public function getChangeType() {
182        return $this->mChangeType;
183    }
184
185    public function getChangeObject() {
186        if ( $this->mChangeObject === null && $this->mChangeObjectId ) {
187            $threadObj = $this->getThreadObj();
188
189            if ( $threadObj instanceof Thread ) {
190                $objectId = $this->mChangeObjectId;
191                $this->mChangeObject = $threadObj->replyWithId( $objectId );
192            }
193
194            if ( !$this->mChangeObject ) {
195                $this->mChangeObject = false;
196            }
197        }
198
199        return $this->mChangeObject;
200    }
201
202    public function getChangeComment() {
203        return $this->mChangeComment;
204    }
205
206    public function getId() {
207        return $this->mId;
208    }
209
210    public function getThreadObj() {
211        if ( $this->mThreadObj === null ) {
212            if ( $this->mObjSer !== null ) {
213                $this->mThreadObj = unserialize( $this->mObjSer );
214            } else {
215                throw new LogicException( "Missing mObjSer" );
216            }
217        }
218
219        if ( !( $this->mThreadObj instanceof Thread ) ) {
220            $this->mThreadObj = false;
221            return false;
222        }
223
224        $this->mThreadObj->threadRevision = $this;
225
226        return $this->mThreadObj;
227    }
228
229    public function prev() {
230        $dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
231
232        $row = $dbr->newSelectQueryBuilder()
233            ->select( '*' )
234            ->from( 'thread_history' )
235            ->where( [
236                $dbr->expr( 'th_id', '<', intval( $this->getId() ) ),
237                'th_thread' => $this->mThreadId
238            ] )
239            ->caller( __METHOD__ )
240            ->fetchRow();
241
242        return self::loadFromRow( $row );
243    }
244
245    public function next() {
246        $dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
247
248        $row = $dbr->newSelectQueryBuilder()
249            ->select( '*' )
250            ->from( 'thread_history' )
251            ->where( [
252                $dbr->expr( 'th_id', '>', intval( $this->getId() ) ),
253                'th_thread' => $this->mThreadId
254            ] )
255            ->caller( __METHOD__ )
256            ->fetchRow();
257
258        return self::loadFromRow( $row );
259    }
260}