1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Nette\Database;
13:
14: use Nette,
15: Nette\ObjectMixin,
16: PDO;
17:
18:
19:
20: 21: 22: 23: 24:
25: class Connection extends PDO
26: {
27:
28: private $dsn;
29:
30:
31: private $driver;
32:
33:
34: private $preprocessor;
35:
36:
37: public $databaseReflection;
38:
39:
40: private $cache;
41:
42:
43: public $substitutions = array();
44:
45:
46: public $onQuery;
47:
48:
49:
50: public function __construct($dsn, $username = NULL, $password = NULL, array $options = NULL, Reflection\DatabaseReflection $databaseReflection = NULL)
51: {
52: parent::__construct($this->dsn = $dsn, $username, $password, $options);
53: $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
54: $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('Nette\Database\Statement', array($this)));
55:
56: $class = 'Nette\Database\Drivers\\' . $this->getAttribute(PDO::ATTR_DRIVER_NAME) . 'Driver';
57: if (class_exists($class)) {
58: $this->driver = new $class($this, (array) $options);
59: }
60:
61: $this->preprocessor = new SqlPreprocessor($this);
62: $this->databaseReflection = $databaseReflection ?: new Reflection\DatabaseReflection;
63:
64: Diagnostics\ConnectionPanel::initialize($this);
65: }
66:
67:
68:
69:
70: public function getSupplementalDriver()
71: {
72: return $this->driver;
73: }
74:
75:
76:
77: public function setCacheStorage(Nette\Caching\IStorage $storage = NULL)
78: {
79: $this->cache = $storage ? new Nette\Caching\Cache($storage, "Nette.Database/$this->dsn") : NULL;
80: }
81:
82:
83:
84: public function getCache()
85: {
86: return $this->cache;
87: }
88:
89:
90:
91: 92: 93: 94: 95: 96:
97: public function query($statement)
98: {
99: $args = func_get_args();
100: return $this->queryArgs(array_shift($args), $args);
101: }
102:
103:
104:
105: 106: 107: 108: 109: 110:
111: public function exec($statement)
112: {
113: $args = func_get_args();
114: return $this->queryArgs(array_shift($args), $args)->rowCount();
115: }
116:
117:
118:
119: 120: 121: 122: 123:
124: public function queryArgs($statement, $params)
125: {
126: foreach ($params as $value) {
127: if (is_array($value) || is_object($value)) {
128: $need = TRUE; break;
129: }
130: }
131: if (isset($need) || strpos($statement, ':') !== FALSE && $this->preprocessor !== NULL) {
132: list($statement, $params) = $this->preprocessor->process($statement, $params);
133: }
134:
135: return $this->prepare($statement)->execute($params);
136: }
137:
138:
139:
140:
141:
142:
143:
144: 145: 146: 147: 148: 149:
150: public function fetch($args)
151: {
152: $args = func_get_args();
153: return $this->queryArgs(array_shift($args), $args)->fetch();
154: }
155:
156:
157:
158: 159: 160: 161: 162: 163:
164: public function fetchColumn($args)
165: {
166: $args = func_get_args();
167: return $this->queryArgs(array_shift($args), $args)->fetchColumn();
168: }
169:
170:
171:
172: 173: 174: 175: 176: 177:
178: public function fetchPairs($args)
179: {
180: $args = func_get_args();
181: return $this->queryArgs(array_shift($args), $args)->fetchPairs();
182: }
183:
184:
185:
186: 187: 188: 189: 190: 191:
192: public function fetchAll($args)
193: {
194: $args = func_get_args();
195: return $this->queryArgs(array_shift($args), $args)->fetchAll();
196: }
197:
198:
199:
200:
201:
202:
203:
204: 205: 206: 207: 208:
209: public function table($table)
210: {
211: return new Table\Selection($table, $this);
212: }
213:
214:
215:
216:
217:
218:
219:
220: 221: 222: 223: 224:
225: public function loadFile($file)
226: {
227: @set_time_limit(0);
228:
229: $handle = @fopen($file, 'r');
230: if (!$handle) {
231: throw new Nette\FileNotFoundException("Cannot open file '$file'.");
232: }
233:
234: $count = 0;
235: $sql = '';
236: while (!feof($handle)) {
237: $s = fgets($handle);
238: $sql .= $s;
239: if (substr(rtrim($s), -1) === ';') {
240: parent::exec($sql);
241: $sql = '';
242: $count++;
243: }
244: }
245: fclose($handle);
246: return $count;
247: }
248:
249:
250:
251: 252: 253: 254: 255:
256: public static function highlightSql($sql)
257: {
258: static $keywords1 = 'SELECT|UPDATE|INSERT(?:\s+INTO)?|REPLACE(?:\s+INTO)?|DELETE|FROM|WHERE|HAVING|GROUP\s+BY|ORDER\s+BY|LIMIT|OFFSET|SET|VALUES|LEFT\s+JOIN|INNER\s+JOIN|TRUNCATE';
259: static $keywords2 = 'ALL|DISTINCT|DISTINCTROW|AS|USING|ON|AND|OR|IN|IS|NOT|NULL|LIKE|TRUE|FALSE';
260:
261:
262: $sql = " $sql ";
263: $sql = preg_replace("#(?<=[\\s,(])($keywords1)(?=[\\s,)])#i", "\n\$1", $sql);
264:
265:
266: $sql = preg_replace('#[ \t]{2,}#', " ", $sql);
267:
268: $sql = wordwrap($sql, 100);
269: $sql = preg_replace("#([ \t]*\r?\n){2,}#", "\n", $sql);
270:
271:
272: $sql = htmlSpecialChars($sql);
273: $sql = preg_replace_callback("#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|(?<=[\\s,(])($keywords1)(?=[\\s,)])|(?<=[\\s,(=])($keywords2)(?=[\\s,)=])#is", function($matches) {
274: if (!empty($matches[1]))
275: return '<em style="color:gray">' . $matches[1] . '</em>';
276:
277: if (!empty($matches[2]))
278: return '<strong style="color:red">' . $matches[2] . '</strong>';
279:
280: if (!empty($matches[3]))
281: return '<strong style="color:blue">' . $matches[3] . '</strong>';
282:
283: if (!empty($matches[4]))
284: return '<strong style="color:green">' . $matches[4] . '</strong>';
285: }, $sql);
286:
287: return '<pre class="dump">' . trim($sql) . "</pre>\n";
288: }
289:
290:
291:
292:
293:
294:
295:
296: 297: 298:
299: public static function getReflection()
300: {
301: return new Nette\Reflection\ClassType(get_called_class());
302: }
303:
304:
305:
306: public function __call($name, $args)
307: {
308: return ObjectMixin::call($this, $name, $args);
309: }
310:
311:
312:
313: public function &__get($name)
314: {
315: return ObjectMixin::get($this, $name);
316: }
317:
318:
319:
320: public function __set($name, $value)
321: {
322: return ObjectMixin::set($this, $name, $value);
323: }
324:
325:
326:
327: public function __isset($name)
328: {
329: return ObjectMixin::has($this, $name);
330: }
331:
332:
333:
334: public function __unset($name)
335: {
336: ObjectMixin::remove($this, $name);
337: }
338:
339: }
340: