Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 151
0.00% covered (danger)
0.00%
0 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
DBStore
0.00% covered (danger)
0.00%
0 / 151
0.00% covered (danger)
0.00%
0 / 12
992
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getMessages
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
6
 getLangList
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
6
 getProperties
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
6
 getElectionInfo
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
6
 getElectionInfoByTitle
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
6
 decodeElectionRow
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 getDB
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 setForcePrimary
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getQuestionInfo
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
30
 callbackValidVotes
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 getEntityType
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace MediaWiki\Extension\SecurePoll\Store;
4
5use MediaWiki\Status\Status;
6use Wikimedia\Rdbms\ILoadBalancer;
7
8/**
9 * Storage class for a DB backend. This is the one that's most often used.
10 */
11class DBStore implements Store {
12
13    /** @var bool */
14    private $forcePrimary = false;
15
16    /** @var ILoadBalancer */
17    private $loadBalancer;
18
19    /** @var string|bool */
20    private $wiki;
21
22    /**
23     * DBStore constructor.
24     * @param ILoadBalancer $loadBalancer The load balancer used to get connection objects
25     * @param string|bool $wiki The wiki ID or false to use the local wiki
26     */
27    public function __construct(
28        ILoadBalancer $loadBalancer,
29        $wiki = false
30    ) {
31        $this->loadBalancer = $loadBalancer;
32        $this->wiki = $wiki;
33    }
34
35    /** @inheritDoc */
36    public function getMessages( $lang, $ids ) {
37        $db = $this->getDB( DB_REPLICA );
38        $res = $db->newSelectQueryBuilder()
39            ->select( '*' )
40            ->from( 'securepoll_msgs' )
41            ->where( [
42                'msg_entity' => $ids,
43                'msg_lang' => $lang
44            ] )
45            ->caller( __METHOD__ )
46            ->fetchResultSet();
47        $messages = [];
48        foreach ( $res as $row ) {
49            $messages[$row->msg_entity][$row->msg_key] = $row->msg_text;
50        }
51
52        return $messages;
53    }
54
55    /** @inheritDoc */
56    public function getLangList( $ids ) {
57        $db = $this->getDB( DB_REPLICA );
58        $res = $db->newSelectQueryBuilder()
59            ->select( 'msg_lang' )
60            ->distinct()
61            ->from( 'securepoll_msgs' )
62            ->where( [
63                'msg_entity' => $ids
64            ] )
65            ->caller( __METHOD__ )
66            ->fetchResultSet();
67        $langs = [];
68        foreach ( $res as $row ) {
69            $langs[] = $row->msg_lang;
70        }
71
72        return $langs;
73    }
74
75    /** @inheritDoc */
76    public function getProperties( $ids ) {
77        $db = $this->getDB( DB_REPLICA );
78        $res = $db->newSelectQueryBuilder()
79            ->select( '*' )
80            ->from( 'securepoll_properties' )
81            ->where( [ 'pr_entity' => $ids ] )
82            ->caller( __METHOD__ )
83            ->fetchResultSet();
84        $properties = [];
85        foreach ( $res as $row ) {
86            $properties[$row->pr_entity][$row->pr_key] = $row->pr_value;
87        }
88
89        return $properties;
90    }
91
92    /** @inheritDoc */
93    public function getElectionInfo( $ids ) {
94        $ids = (array)$ids;
95        $db = $this->getDB( DB_REPLICA );
96        $res = $db->newSelectQueryBuilder()
97            ->select( '*' )
98            ->from( 'securepoll_elections' )
99            ->where( [ 'el_entity' => $ids ] )
100            ->caller( __METHOD__ )
101            ->fetchResultSet();
102        $infos = [];
103        foreach ( $res as $row ) {
104            $infos[$row->el_entity] = $this->decodeElectionRow( $row );
105        }
106
107        return $infos;
108    }
109
110    /** @inheritDoc */
111    public function getElectionInfoByTitle( $names ) {
112        $names = (array)$names;
113        $db = $this->getDB( DB_REPLICA );
114        $res = $db->newSelectQueryBuilder()
115            ->select( '*' )
116            ->from( 'securepoll_elections' )
117            ->where( [ 'el_title' => $names ] )
118            ->caller( __METHOD__ )
119            ->fetchResultSet();
120        $infos = [];
121        foreach ( $res as $row ) {
122            $infos[$row->el_title] = $this->decodeElectionRow( $row );
123        }
124
125        return $infos;
126    }
127
128    /** @inheritDoc */
129    public function decodeElectionRow( $row ) {
130        static $map = [
131            'id' => 'el_entity',
132            'title' => 'el_title',
133            'ballot' => 'el_ballot',
134            'tally' => 'el_tally',
135            'primaryLang' => 'el_primary_lang',
136            'startDate' => 'el_start_date',
137            'endDate' => 'el_end_date',
138            'auth' => 'el_auth_type',
139            'owner' => 'el_owner'
140        ];
141
142        $info = [];
143        foreach ( $map as $key => $field ) {
144            if ( $key == 'startDate' || $key == 'endDate' ) {
145                $info[$key] = wfTimestamp( TS_MW, $row->$field );
146            } elseif ( isset( $row->$field ) ) {
147                $info[$key] = $row->$field;
148            }
149        }
150
151        return $info;
152    }
153
154    /** @inheritDoc */
155    public function getDB( $index = DB_PRIMARY ) {
156        return $this->loadBalancer->getConnection(
157            $this->forcePrimary ? DB_PRIMARY : $index,
158            [],
159            $this->wiki
160        );
161    }
162
163    /** @inheritDoc */
164    public function setForcePrimary( $forcePrimary ) {
165        $this->forcePrimary = $forcePrimary;
166    }
167
168    /** @inheritDoc */
169    public function getQuestionInfo( $electionId ) {
170        $db = $this->getDB( DB_REPLICA );
171        $res = $db->newSelectQueryBuilder()
172            ->select( '*' )
173            ->from( 'securepoll_questions' )
174            ->join( 'securepoll_options', null, 'op_question=qu_entity' )
175            ->where( [
176                'qu_election' => $electionId,
177            ] )
178            ->orderBy( [ 'qu_index', 'qu_entity' ] )
179            ->caller( __METHOD__ )
180            ->fetchResultSet();
181
182        $questions = [];
183        $options = [];
184        $questionId = false;
185        $electionId = false;
186        foreach ( $res as $row ) {
187            if ( $questionId !== false && $questionId !== $row->qu_entity ) {
188                $questions[] = [
189                    'id' => $questionId,
190                    'election' => $electionId,
191                    'options' => $options
192                ];
193                $options = [];
194            }
195            $options[] = [
196                'id' => $row->op_entity,
197                'election' => $row->op_election,
198            ];
199            $questionId = $row->qu_entity;
200            $electionId = $row->qu_election;
201        }
202        if ( $questionId !== false ) {
203            $questions[] = [
204                'id' => $questionId,
205                'election' => $electionId,
206                'options' => $options
207            ];
208        }
209
210        return $questions;
211    }
212
213    /** @inheritDoc */
214    public function callbackValidVotes( $electionId, $callback, $voterId = null ) {
215        $dbr = $this->getDB( DB_REPLICA );
216        $queryBuilder = $dbr->newSelectQueryBuilder()
217            ->select( '*' )
218            ->from( 'securepoll_votes' )
219            ->where( [
220                'vote_election' => $electionId,
221                'vote_current' => 1,
222                'vote_struck' => 0
223            ] )
224            ->caller( __METHOD__ );
225        if ( $voterId !== null ) {
226            $queryBuilder->andWhere( [ 'vote_voter' => $voterId ] );
227        }
228        $res = $queryBuilder->fetchResultSet();
229
230        foreach ( $res as $row ) {
231            $status = call_user_func( $callback, $this, $row->vote_record );
232            if ( $status instanceof Status && !$status->isOK() ) {
233                return $status;
234            }
235        }
236
237        return Status::newGood();
238    }
239
240    /** @inheritDoc */
241    public function getEntityType( $id ) {
242        $db = $this->getDB( DB_REPLICA );
243        $res = $db->newSelectQueryBuilder()
244            ->select( '*' )
245            ->from( 'securepoll_entity' )
246            ->where( [ 'en_id' => $id ] )
247            ->caller( __METHOD__ )
248            ->fetchRow();
249
250        return $res ? $res->en_type : false;
251    }
252}