Completed
Push — newinternal ( 65a0f5...5b021c )
by Simon
08:29
created

SearchHelperBase::fetchColumn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
ccs 0
cts 4
cp 0
crap 2
1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 *                                                                            *
5
 * All code in this file is released into the public domain by the ACC        *
6
 * Development Team. Please see team.json for a list of contributors.         *
7
 ******************************************************************************/
8
9
namespace Waca\Helpers\SearchHelpers;
10
11
use PDO;
12
use PDOStatement;
13
use Waca\DataObject;
14
use Waca\PdoDatabase;
15
16
abstract class SearchHelperBase
17
{
18
    /** @var PdoDatabase */
19
    protected $database;
20
    /** @var array */
21
    protected $parameterList = array();
22
    /** @var null|int */
23
    private $limit = null;
24
    /** @var null|int */
25
    private $offset = null;
26
    private $orderBy = null;
27
    /**
28
     * @var string The where clause.
29
     *
30
     * (the 1=1 condition will be optimised out of the query by the query planner, and simplifies our code here). Note
31
     * that we use positional parameters instead of named parameters because we don't know many times different options
32
     * will be called (looking at excluding() here, but there's the option for others).
33
     */
34
    protected $whereClause = ' WHERE 1 = 1';
35
    /** @var string */
36
    protected $table;
37
    protected $joinClause = '';
38
    private $targetClass;
39
40
    /**
41
     * SearchHelperBase constructor.
42
     *
43
     * @param PdoDatabase $database
44
     * @param string      $table
45
     * @param             $targetClass
46
     * @param null|string $order Order by clause, excluding ORDER BY.
47
     */
48
    protected function __construct(PdoDatabase $database, $table, $targetClass, $order = null)
49
    {
50
        $this->database = $database;
51
        $this->table = $table;
52
        $this->orderBy = $order;
53
        $this->targetClass = $targetClass;
54
    }
55
56
    /**
57
     * Finalises the database query, and executes it, returning a set of objects.
58
     *
59
     * @return DataObject[]
60
     */
61
    public function fetch()
62
    {
63
        $statement = $this->getData();
64
65
        /** @var DataObject[] $returnedObjects */
66
        $returnedObjects = $statement->fetchAll(PDO::FETCH_CLASS, $this->targetClass);
67
        foreach ($returnedObjects as $req) {
68
            $req->setDatabase($this->database);
69
        }
70
71
        return $returnedObjects;
72
    }
73
74
    /**
75
     * Finalises the database query, and executes it, returning only the requested column.
76
     *
77
     * @param string $column The required column
78
     * @return array
79
     */
80
    public function fetchColumn($column){
81
        $statement = $this->getData(array($column));
82
83
        return $statement->fetchAll(PDO::FETCH_COLUMN);
84
    }
85
86
    public function fetchMap($column){
87
        $statement = $this->getData(array('id', $column));
88
89
        $data = $statement->fetchAll(PDO::FETCH_ASSOC);
90
        $map = array();
91
92
        foreach ($data as $row) {
93
            $map[$row['id']] = $row[$column];
94
        }
95
96
        return $map;
97
    }
98
99
    /**
100
     * @param int $count Returns the record count of the result set
101
     *
102
     * @return $this
103
     */
104
    public function getRecordCount(&$count)
105
    {
106
        $query = 'SELECT /* SearchHelper */ COUNT(*) FROM ' . $this->table . ' origin ';
107
        $query .= $this->joinClause . $this->whereClause;
108
109
        $statement = $this->database->prepare($query);
110
        $statement->execute($this->parameterList);
111
112
        $count = $statement->fetchColumn(0);
113
        $statement->closeCursor();
114
115
        return $this;
116
    }
117
118
    /**
119
     * Limits the results
120
     *
121
     * @param integer      $limit
122
     * @param integer|null $offset
123
     *
124
     * @return $this
125
     *
126
     */
127
    public function limit($limit, $offset = null)
128
    {
129
        $this->limit = $limit;
130
        $this->offset = $offset;
131
132
        return $this;
133
    }
134
135
    private function applyLimit()
136
    {
137
        $clause = '';
138
        if ($this->limit !== null) {
139
            $clause = ' LIMIT ?';
140
            $this->parameterList[] = $this->limit;
141
142
            if ($this->offset !== null) {
143
                $clause .= ' OFFSET ?';
144
                $this->parameterList[] = $this->offset;
145
            }
146
        }
147
148
        return $clause;
149
    }
150
151
    private function applyOrder()
152
    {
153
        if ($this->orderBy !== null) {
154
            return ' ORDER BY ' . $this->orderBy;
155
        }
156
157
        return '';
158
    }
159
160
    /**
161
     * @param array $columns
162
     *
163
     * @return PDOStatement
164
     */
165
    private function getData($columns = array('*'))
166
    {
167
        $query = $this->buildQuery($columns);
168
        $query .= $this->applyOrder();
169
        $query .= $this->applyLimit();
170
171
        $statement = $this->database->prepare($query);
172
        $statement->execute($this->parameterList);
173
174
        return $statement;
175
    }
176
177
    /**
178
     * @param array $columns
179
     *
180
     * @return string
181
     */
182
    protected function buildQuery($columns)
183
    {
184
        $colData = array();
185
        foreach ($columns as $c) {
186
            $colData[] = 'origin.' . $c;
187
        }
188
189
        $query = 'SELECT /* SearchHelper */ ' . implode(', ', $colData) . ' FROM ' . $this->table . ' origin ';
190
        $query .= $this->joinClause . $this->whereClause;
191
192
        return $query;
193
    }
194
195
    public function inIds($idList) {
196
        $this->inClause('id', $idList);
197
        return $this;
198
    }
199
200
    protected function inClause($column, $values) {
201
        if (count($values) === 0) {
202
            return;
203
        }
204
205
        // Urgh. OK. You can't use IN() with parameters directly, so let's munge something together.
206
        $valueCount = count($values);
207
208
        // Firstly, let's create a string of question marks, which will do as positional parameters.
209
        $inSection = str_repeat('?,', $valueCount - 1) . '?';
210
211
        $this->whereClause .= " AND {$column} IN ({$inSection})";
212
        $this->parameterList = array_merge($this->parameterList, $values);
213
    }
214
}
215