Completed
Push — namespace-model ( c67c40...018a87 )
by Sam
07:37
created

Query::value()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 4
rs 10
1
<?php
2
3
namespace SilverStripe\Model\Connect;
4
use Convert;
5
use Iterator;
6
7
8
/**
9
 * Abstract query-result class.
10
 * Once again, this should be subclassed by an actual database implementation.  It will only
11
 * ever be constructed by a subclass of SS_Database.  The result of a database query - an iteratable object
12
 * that's returned by DB::SS_Query
13
 *
14
 * Primarily, the SS_Query class takes care of the iterator plumbing, letting the subclasses focusing
15
 * on providing the specific data-access methods that are required: {@link nextRecord()}, {@link numRecords()}
16
 * and {@link seek()}
17
 * @package framework
18
 * @subpackage model
19
 */
20
abstract class Query implements Iterator {
21
22
	/**
23
	 * The current record in the interator.
24
	 *
25
	 * @var array
26
	 */
27
	protected $currentRecord = null;
28
29
	/**
30
	 * The number of the current row in the interator.
31
	 *
32
	 * @var int
33
	 */
34
	protected $rowNum = -1;
35
36
	/**
37
	 * Flag to keep track of whether iteration has begun, to prevent unnecessary seeks
38
	 *
39
	 * @var bool
40
	 */
41
	protected $queryHasBegun = false;
42
43
	/**
44
	 * Return an array containing all the values from a specific column. If no column is set, then the first will be
45
	 * returned
46
	 *
47
	 * @param string $column
48
	 * @return array
49
	 */
50
	public function column($column = null) {
51
		$result = array();
52
53
		while ($record = $this->next()) {
54
			if ($column) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $column of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
55
				$result[] = $record[$column];
56
			} else {
57
				$result[] = $record[key($record)];
58
			}
59
		}
60
61
		return $result;
62
	}
63
64
	/**
65
	 * Return an array containing all values in the leftmost column, where the keys are the
66
	 * same as the values.
67
	 *
68
	 * @return array
69
	 */
70 View Code Duplication
	public function keyedColumn() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
71
		$column = array();
72
		foreach ($this as $record) {
73
			$val = $record[key($record)];
74
			$column[$val] = $val;
75
		}
76
		return $column;
77
	}
78
79
	/**
80
	 * Return a map from the first column to the second column.
81
	 *
82
	 * @return array
83
	 */
84 View Code Duplication
	public function map() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
85
		$column = array();
86
		foreach ($this as $record) {
87
			$key = reset($record);
88
			$val = next($record);
89
			$column[$key] = $val;
90
		}
91
		return $column;
92
	}
93
94
	/**
95
	 * Returns the next record in the iterator.
96
	 *
97
	 * @return array
98
	 */
99
	public function record() {
100
		return $this->next();
101
	}
102
103
	/**
104
	 * Returns the first column of the first record.
105
	 *
106
	 * @return string
107
	 */
108
	public function value() {
109
		$record = $this->next();
110
		if ($record) return $record[key($record)];
0 ignored issues
show
Bug Best Practice introduced by
The expression $record of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
111
	}
112
113
	/**
114
	 * Return an HTML table containing the full result-set
115
	 *
116
	 * @return string
117
	 */
118
	public function table() {
119
		$first = true;
120
		$result = "<table>\n";
121
122
		foreach ($this as $record) {
123
			if ($first) {
124
				$result .= "<tr>";
125
				foreach ($record as $k => $v) {
126
					$result .= "<th>" . Convert::raw2xml($k) . "</th> ";
127
				}
128
				$result .= "</tr> \n";
129
			}
130
131
			$result .= "<tr>";
132
			foreach ($record as $k => $v) {
133
				$result .= "<td>" . Convert::raw2xml($v) . "</td> ";
134
			}
135
			$result .= "</tr> \n";
136
137
			$first = false;
138
		}
139
		$result .= "</table>\n";
140
141
		if ($first) return "No records found";
142
		return $result;
143
	}
144
145
	/**
146
	 * Iterator function implementation. Rewind the iterator to the first item and return it.
147
	 * Makes use of {@link seek()} and {@link numRecords()}, takes care of the plumbing.
148
	 *
149
	 * @return array
150
	 */
151
	public function rewind() {
152
		if ($this->queryHasBegun && $this->numRecords() > 0) {
153
			$this->queryHasBegun = false;
154
			$this->currentRecord = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $currentRecord.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
155
			return $this->seek(0);
156
		}
157
	}
158
159
	/**
160
	 * Iterator function implementation. Return the current item of the iterator.
161
	 *
162
	 * @return array
163
	 */
164
	public function current() {
165
		if (!$this->currentRecord) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->currentRecord of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
166
			return $this->next();
167
		} else {
168
			return $this->currentRecord;
169
		}
170
	}
171
172
	/**
173
	 * Iterator function implementation. Return the first item of this iterator.
174
	 *
175
	 * @return array
176
	 */
177
	public function first() {
178
		$this->rewind();
179
		return $this->current();
180
	}
181
182
	/**
183
	 * Iterator function implementation. Return the row number of the current item.
184
	 *
185
	 * @return int
186
	 */
187
	public function key() {
188
		return $this->rowNum;
189
	}
190
191
	/**
192
	 * Iterator function implementation. Return the next record in the iterator.
193
	 * Makes use of {@link nextRecord()}, takes care of the plumbing.
194
	 *
195
	 * @return array
196
	 */
197
	public function next() {
198
		$this->queryHasBegun = true;
199
		$this->currentRecord = $this->nextRecord();
200
		$this->rowNum++;
201
		return $this->currentRecord;
202
	}
203
204
	/**
205
	 * Iterator function implementation. Check if the iterator is pointing to a valid item.
206
	 *
207
	 * @return bool
208
	 */
209
	public function valid() {
210
		if (!$this->queryHasBegun) $this->next();
211
		return $this->currentRecord !== false;
212
	}
213
214
	/**
215
	 * Return the next record in the query result.
216
	 *
217
	 * @return array
218
	 */
219
	abstract public function nextRecord();
220
221
	/**
222
	 * Return the total number of items in the query result.
223
	 *
224
	 * @return int
225
	 */
226
	abstract public function numRecords();
227
228
	/**
229
	 * Go to a specific row number in the query result and return the record.
230
	 *
231
	 * @param int $rowNum Row number to go to.
232
	 * @return array
233
	 */
234
	abstract public function seek($rowNum);
235
}
236