/
Query.php
159 lines (141 loc) · 3.97 KB
/
Query.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<?php
namespace SilverStripe\ORM\Connect;
use SilverStripe\Core\Convert;
use Iterator;
use Traversable;
/**
* Abstract query-result class. A query result provides an iterator that returns a map for each record of a query
* result.
*
* The map should be keyed by the column names, and the values should use the following types:
*
* - boolean returned as integer 1 or 0 (to ensure consistency with MySQL that doesn't have native booleans)
* - integer types returned as integers
* - floating point / decimal types returned as floats
* - strings returned as strings
* - dates / datetimes returned as strings
*
* Note that until SilverStripe 4.3, bugs meant that strings were used for every column type.
*
* Once again, this should be subclassed by an actual database implementation. It will only
* ever be constructed by a subclass of SS_Database. The result of a database query - an iteratable object
* that's returned by DB::SS_Query
*
* Primarily, the Query class takes care of the iterator plumbing, letting the subclasses focusing
* on providing the specific data-access methods that are required: {@link nextRecord()}, {@link numRecords()}
* and {@link seek()}
*/
abstract class Query implements \IteratorAggregate
{
/**
* Return an array containing all the values from a specific column. If no column is set, then the first will be
* returned
*
* @param string $column
* @return array
*/
public function column($column = null)
{
$result = [];
foreach ($this as $record) {
if ($column) {
$result[] = $record[$column];
} else {
$result[] = $record[key($record)];
}
}
return $result;
}
/**
* Return an array containing all values in the leftmost column, where the keys are the
* same as the values.
*
* @return array
*/
public function keyedColumn()
{
$column = [];
foreach ($this as $record) {
$val = $record[key($record)];
$column[$val] = $val;
}
return $column;
}
/**
* Return a map from the first column to the second column.
*
* @return array
*/
public function map()
{
$column = [];
foreach ($this as $record) {
$key = reset($record);
$val = next($record);
$column[$key] = $val;
}
return $column;
}
/**
* Returns the first record in the result
*
* @return array
*/
public function record()
{
return $this->getIterator()->current();
}
/**
* Returns the first column of the first record.
*
* @return string
*/
public function value()
{
$record = $this->record();
if ($record) {
return $record[key($record)];
}
return null;
}
/**
* Return an HTML table containing the full result-set
*
* @return string
*/
public function table()
{
$first = true;
$result = "<table>\n";
foreach ($this as $record) {
if ($first) {
$result .= "<tr>";
foreach ($record as $k => $v) {
$result .= "<th>" . Convert::raw2xml($k) . "</th> ";
}
$result .= "</tr> \n";
}
$result .= "<tr>";
foreach ($record as $k => $v) {
$result .= "<td>" . Convert::raw2xml($v) . "</td> ";
}
$result .= "</tr> \n";
$first = false;
}
$result .= "</table>\n";
if ($first) {
return "No records found";
}
return $result;
}
/**
* Return the next record in the query result.
*/
abstract public function getIterator(): Traversable;
/**
* Return the total number of items in the query result.
*
* @return int
*/
abstract public function numRecords();
}