1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Database;
9:
10: use Nette;
11: use PDO;
12:
13:
14: 15: 16: 17: 18: 19: 20: 21:
22: class ResultSet extends Nette\Object implements \Iterator, IRowContainer
23: {
24:
25: private $connection;
26:
27:
28: private $supplementalDriver;
29:
30:
31: private $pdoStatement;
32:
33:
34: private $result;
35:
36:
37: private $resultKey = -1;
38:
39:
40: private $results;
41:
42:
43: private $time;
44:
45:
46: private $queryString;
47:
48:
49: private $params;
50:
51:
52: private $types;
53:
54:
55: public function __construct(Connection $connection, $queryString, array $params)
56: {
57: $time = microtime(TRUE);
58: $this->connection = $connection;
59: $this->supplementalDriver = $connection->getSupplementalDriver();
60: $this->queryString = $queryString;
61: $this->params = $params;
62:
63: if (substr($queryString, 0, 2) === '::') {
64: $connection->getPdo()->{substr($queryString, 2)}();
65: } elseif ($queryString !== NULL) {
66: $this->pdoStatement = $connection->getPdo()->prepare($queryString);
67: $this->pdoStatement->setFetchMode(PDO::FETCH_ASSOC);
68: $this->pdoStatement->execute($params);
69: }
70: $this->time = microtime(TRUE) - $time;
71: }
72:
73:
74: 75: 76:
77: public function getConnection()
78: {
79: return $this->connection;
80: }
81:
82:
83: 84: 85: 86:
87: public function getPdoStatement()
88: {
89: return $this->pdoStatement;
90: }
91:
92:
93: 94: 95:
96: public function getQueryString()
97: {
98: return $this->queryString;
99: }
100:
101:
102: 103: 104:
105: public function getParameters()
106: {
107: return $this->params;
108: }
109:
110:
111: 112: 113:
114: public function getColumnCount()
115: {
116: return $this->pdoStatement ? $this->pdoStatement->columnCount() : NULL;
117: }
118:
119:
120: 121: 122:
123: public function getRowCount()
124: {
125: return $this->pdoStatement ? $this->pdoStatement->rowCount() : NULL;
126: }
127:
128:
129: 130: 131:
132: public function getTime()
133: {
134: return $this->time;
135: }
136:
137:
138: 139: 140: 141: 142:
143: public function normalizeRow($row)
144: {
145: if ($this->types === NULL) {
146: $this->types = (array) $this->supplementalDriver->getColumnTypes($this->pdoStatement);
147: }
148:
149: foreach ($this->types as $key => $type) {
150: $value = $row[$key];
151: if ($value === NULL || $value === FALSE || $type === IReflection::FIELD_TEXT) {
152:
153: } elseif ($type === IReflection::FIELD_INTEGER) {
154: $row[$key] = is_float($tmp = $value * 1) ? $value : $tmp;
155:
156: } elseif ($type === IReflection::FIELD_FLOAT) {
157: if (($pos = strpos($value, '.')) !== FALSE) {
158: $value = rtrim(rtrim($pos === 0 ? "0$value" : $value, '0'), '.');
159: }
160: $float = (float) $value;
161: $row[$key] = (string) $float === $value ? $float : $value;
162:
163: } elseif ($type === IReflection::FIELD_BOOL) {
164: $row[$key] = ((bool) $value) && $value !== 'f' && $value !== 'F';
165:
166: } elseif ($type === IReflection::FIELD_DATETIME || $type === IReflection::FIELD_DATE || $type === IReflection::FIELD_TIME) {
167: $row[$key] = new Nette\Utils\DateTime($value);
168:
169: } elseif ($type === IReflection::FIELD_TIME_INTERVAL) {
170: preg_match('#^(-?)(\d+)\D(\d+)\D(\d+)\z#', $value, $m);
171: $row[$key] = new \DateInterval("PT$m[2]H$m[3]M$m[4]S");
172: $row[$key]->invert = (int) (bool) $m[1];
173:
174: } elseif ($type === IReflection::FIELD_UNIX_TIMESTAMP) {
175: $row[$key] = Nette\Utils\DateTime::from($value);
176: }
177: }
178:
179: return $this->supplementalDriver->normalizeRow($row);
180: }
181:
182:
183:
184:
185:
186: 187: 188: 189:
190: public function dump()
191: {
192: Helpers::dumpResult($this);
193: }
194:
195:
196:
197:
198:
199: public function rewind()
200: {
201: if ($this->result === FALSE) {
202: throw new Nette\InvalidStateException('Nette\\Database\\ResultSet implements only one way iterator.');
203: }
204: }
205:
206:
207: public function current()
208: {
209: return $this->result;
210: }
211:
212:
213: public function key()
214: {
215: return $this->resultKey;
216: }
217:
218:
219: public function next()
220: {
221: $this->result = FALSE;
222: }
223:
224:
225: public function valid()
226: {
227: if ($this->result) {
228: return TRUE;
229: }
230:
231: return $this->fetch() !== FALSE;
232: }
233:
234:
235:
236:
237:
238: 239: 240:
241: public function fetch()
242: {
243: $data = $this->pdoStatement ? $this->pdoStatement->fetch() : NULL;
244: if (!$data) {
245: $this->pdoStatement->closeCursor();
246: return FALSE;
247: }
248:
249: $row = new Row;
250: foreach ($this->normalizeRow($data) as $key => $value) {
251: if ($key !== '') {
252: $row->$key = $value;
253: }
254: }
255:
256: if ($this->result === NULL && count($data) !== $this->pdoStatement->columnCount()) {
257: trigger_error('Found duplicate columns in database result set.', E_USER_NOTICE);
258: }
259:
260: $this->resultKey++;
261: return $this->result = $row;
262: }
263:
264:
265: 266: 267: 268: 269:
270: public function fetchField($column = 0)
271: {
272: $row = $this->fetch();
273: return $row ? $row[$column] : FALSE;
274: }
275:
276:
277: 278: 279:
280: public function fetchPairs($key = NULL, $value = NULL)
281: {
282: return Helpers::toPairs($this->fetchAll(), $key, $value);
283: }
284:
285:
286: 287: 288:
289: public function fetchAll()
290: {
291: if ($this->results === NULL) {
292: $this->results = iterator_to_array($this);
293: }
294: return $this->results;
295: }
296:
297:
298: 299: 300: 301: 302:
303: public function fetchAssoc($path)
304: {
305: return Nette\Utils\Arrays::associate($this->fetchAll(), $path);
306: }
307:
308: }
309: