Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
CodeSignoff
0.00% covered (danger)
0.00%
0 / 35
0.00% covered (danger)
0.00%
0 / 8
156
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 isStruck
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTimestampStruck
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 strike
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 getID
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 newFromRow
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 newFromData
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 newFromID
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace MediaWiki\Extension\CodeReview\Backend;
4
5use stdClass;
6
7/**
8 * Class representing a sign-off. A sign-off in this context is the record of a
9 * certain user having signed off on a certain revision with a certain flag.
10 * Signing off with multiple flags at once creates multiple sign-offs.
11 */
12class CodeSignoff {
13    /**
14     * CodeRevision object for the revision that was signed off on
15     * @var CodeRevision
16     */
17    public $rev;
18
19    /**
20     * User ID (on the wiki, not in SVN) of the user that signed off
21     * @var int
22     */
23    public $user;
24
25    /**
26     * User name of the user that signed off
27     * @var string
28     */
29    public $userText;
30
31    /**
32     * Sign-off flag. See CodeRevision::getPossibleFlags() for possible values
33     * @var string
34     */
35    public $flag;
36
37    /**
38     * Timestamp of the sign-off, in TS_MW format
39     * @var string
40     */
41    public $timestamp;
42
43    /**
44     * @var string
45     */
46    private $timestampStruck;
47
48    /**
49     * This constructor is only used by newFrom*(). You should not create your own
50     * CodeSignoff objects, they'll be useless if they don't correspond to existing entries
51     * in the database.
52     *
53     * For more detailed explanations of what each of the parameters mean, see public members.
54     * @param CodeRevision $rev CodeRevision object
55     * @param int $user User ID
56     * @param string $userText User name
57     * @param string $flag Flag
58     * @param string $timestamp TS_MW timestamp
59     * @param string $timestampStruck Raw (unformatted!) timestamp from the cs_timestamp_struck
60     *   DB field
61     */
62    public function __construct( $rev, $user, $userText, $flag, $timestamp, $timestampStruck ) {
63        $this->rev = $rev;
64        $this->user = $user;
65        $this->userText = $userText;
66        $this->flag = $flag;
67        $this->timestamp = $timestamp;
68        $this->timestampStruck = $timestampStruck;
69    }
70
71    /**
72     * @return bool Whether this sign-off has been struck
73     */
74    public function isStruck() {
75        return $this->timestampStruck !== wfGetDB( DB_REPLICA )->getInfinity();
76    }
77
78    /**
79     * @return mixed Timestamp (TS_MW format) the revision was struck at, or false if it hasn't
80     *   been struck
81     */
82    public function getTimestampStruck() {
83        return $this->isStruck() ? wfTimestamp( TS_MW, $this->timestampStruck ) : false;
84    }
85
86    /**
87     * Strike this sign-off. Attempts to strike an already-struck signoff will be silently ignored.
88     */
89    public function strike() {
90        if ( $this->isStruck() ) {
91            return;
92        }
93        $dbw = wfGetDB( DB_PRIMARY );
94        $dbw->update(
95            'code_signoffs',
96            [ 'cs_timestamp_struck' => $dbw->timestamp() ],
97            [
98                'cs_repo_id' => $this->rev->getRepoId(),
99                'cs_rev_id' => $this->rev->getId(),
100                'cs_flag' => $this->flag,
101                'cs_user_text' => $this->userText,
102                'cs_timestamp_struck' => $this->timestampStruck
103            ],
104            __METHOD__
105        );
106    }
107
108    /**
109     * Get the ID of this signoff. This is not a numerical ID that exists in the database,
110     * but a representation that you can use in URLs and the like. It's also not unique:
111     * only the combination of a signoff ID and a revision is unique. You can obtain
112     * a CodeSignoff object from its ID and its revision with newFromID().
113     *
114     * @return string ID
115     */
116    public function getID() {
117        return implode( '|', [ $this->flag, $this->timestampStruck, $this->userText ] );
118    }
119
120    /**
121     * Create a CodeSignoff object from a revision and a database row object
122     * @param CodeRevision $rev CodeRevision object the signoff belongs to
123     * @param stdClass $row Database row with cs_* fields from code_signoffs
124     * @return CodeSignoff
125     */
126    public static function newFromRow( $rev, $row ) {
127        return self::newFromData( $rev, get_object_vars( $row ) );
128    }
129
130    /**
131     * Create a CodeSignoff object from a revision and a database row in array format
132     * @param CodeRevision $rev CodeRevision object the signoff belongs to
133     * @param array $data Database row with cs_* fields from code_signoffs
134     * @return CodeSignoff
135     */
136    public static function newFromData( $rev, $data ) {
137        return new self( $rev, $data['cs_user'], $data['cs_user_text'], $data['cs_flag'],
138            wfTimestamp( TS_MW, $data['cs_timestamp'] ), $data['cs_timestamp_struck']
139        );
140    }
141
142    /**
143     * Create a CodeSignoff object from a revision object and an ID previously obtained from getID()
144     * @param CodeRevision $rev CodeRevision object
145     * @param string $id ID generated by getID()
146     * @return CodeSignoff
147     */
148    public static function newFromID( $rev, $id ) {
149        $parts = explode( '|', $id, 3 );
150        if ( count( $parts ) != 3 ) {
151            return null;
152        }
153        $dbr = wfGetDB( DB_REPLICA );
154        $row = $dbr->selectRow(
155            'code_signoffs',
156            [
157                'cs_user', 'cs_user_text', 'cs_flag', 'cs_timestamp',
158                'cs_timestamp_struck'
159            ],
160            [
161                'cs_repo_id' => $rev->getRepoId(),
162                'cs_rev_id' => $rev->getId(),
163                'cs_flag' => $parts[0],
164                'cs_timestamp_struck' => $parts[1],
165                'cs_user_text' => $parts[2]
166            ], __METHOD__
167        );
168        if ( !$row ) {
169            return null;
170        }
171        return self::newFromRow( $rev, $row );
172    }
173}