1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Database;
9:
10: use Nette,
11: Tracy;
12:
13:
14: 15: 16: 17: 18:
19: class Helpers
20: {
21:
22: static public $maxLength = 100;
23:
24:
25: public static $typePatterns = array(
26: '^_' => IReflection::FIELD_TEXT,
27: 'BYTEA|BLOB|BIN' => IReflection::FIELD_BINARY,
28: 'TEXT|CHAR|POINT|INTERVAL' => IReflection::FIELD_TEXT,
29: 'YEAR|BYTE|COUNTER|SERIAL|INT|LONG|SHORT|^TINY$' => IReflection::FIELD_INTEGER,
30: 'CURRENCY|REAL|MONEY|FLOAT|DOUBLE|DECIMAL|NUMERIC|NUMBER' => IReflection::FIELD_FLOAT,
31: '^TIME$' => IReflection::FIELD_TIME,
32: 'TIME' => IReflection::FIELD_DATETIME,
33: 'DATE' => IReflection::FIELD_DATE,
34: 'BOOL' => IReflection::FIELD_BOOL,
35: );
36:
37:
38: 39: 40: 41:
42: public static function dumpResult(ResultSet $result)
43: {
44: echo "\n<table class=\"dump\">\n<caption>" . htmlSpecialChars($result->getQueryString()) . "</caption>\n";
45: if (!$result->getColumnCount()) {
46: echo "\t<tr>\n\t\t<th>Affected rows:</th>\n\t\t<td>", $result->getRowCount(), "</td>\n\t</tr>\n</table>\n";
47: return;
48: }
49: $i = 0;
50: foreach ($result as $row) {
51: if ($i === 0) {
52: echo "<thead>\n\t<tr>\n\t\t<th>#row</th>\n";
53: foreach ($row as $col => $foo) {
54: echo "\t\t<th>" . htmlSpecialChars($col) . "</th>\n";
55: }
56: echo "\t</tr>\n</thead>\n<tbody>\n";
57: }
58: echo "\t<tr>\n\t\t<th>", $i, "</th>\n";
59: foreach ($row as $col) {
60:
61: echo "\t\t<td>", htmlSpecialChars($col), "</td>\n";
62: }
63: echo "\t</tr>\n";
64: $i++;
65: }
66:
67: if ($i === 0) {
68: echo "\t<tr>\n\t\t<td><em>empty result set</em></td>\n\t</tr>\n</table>\n";
69: } else {
70: echo "</tbody>\n</table>\n";
71: }
72: }
73:
74:
75: 76: 77: 78: 79:
80: public static function dumpSql($sql, array $params = NULL)
81: {
82: static $keywords1 = 'SELECT|(?:ON\s+DUPLICATE\s+KEY)?UPDATE|INSERT(?:\s+INTO)?|REPLACE(?:\s+INTO)?|DELETE|CALL|UNION|FROM|WHERE|HAVING|GROUP\s+BY|ORDER\s+BY|LIMIT|OFFSET|SET|VALUES|LEFT\s+JOIN|INNER\s+JOIN|TRUNCATE';
83: static $keywords2 = 'ALL|DISTINCT|DISTINCTROW|IGNORE|AS|USING|ON|AND|OR|IN|IS|NOT|NULL|[RI]?LIKE|REGEXP|TRUE|FALSE';
84:
85:
86: $sql = " $sql ";
87: $sql = preg_replace("#(?<=[\\s,(])($keywords1)(?=[\\s,)])#i", "\n\$1", $sql);
88:
89:
90: $sql = preg_replace('#[ \t]{2,}#', ' ', $sql);
91:
92: $sql = wordwrap($sql, 100);
93: $sql = preg_replace('#([ \t]*\r?\n){2,}#', "\n", $sql);
94:
95:
96: $sql = htmlSpecialChars($sql);
97: $sql = preg_replace_callback("#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|(?<=[\\s,(])($keywords1)(?=[\\s,)])|(?<=[\\s,(=])($keywords2)(?=[\\s,)=])#is", function($matches) {
98: if (!empty($matches[1])) {
99: return '<em style="color:gray">' . $matches[1] . '</em>';
100:
101: } elseif (!empty($matches[2])) {
102: return '<strong style="color:red">' . $matches[2] . '</strong>';
103:
104: } elseif (!empty($matches[3])) {
105: return '<strong style="color:blue">' . $matches[3] . '</strong>';
106:
107: } elseif (!empty($matches[4])) {
108: return '<strong style="color:green">' . $matches[4] . '</strong>';
109: }
110: }, $sql);
111:
112:
113: $sql = preg_replace_callback('#\?#', function() use ($params) {
114: static $i = 0;
115: if (!isset($params[$i])) {
116: return '?';
117: }
118: $param = $params[$i++];
119: if (is_string($param) && (preg_match('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u', $param) || preg_last_error())) {
120: return '<i title="Length ' . strlen($param) . ' bytes"><binary></i>';
121:
122: } elseif (is_string($param)) {
123: return '<span title="Length ' . Nette\Utils\Strings::length($param) . ' characters">\'' . htmlspecialchars(Nette\Utils\Strings::truncate($param, Helpers::$maxLength)) . "'</span>";
124:
125: } elseif (is_resource($param)) {
126: $type = get_resource_type($param);
127: if ($type === 'stream') {
128: $info = stream_get_meta_data($param);
129: }
130: return '<i' . (isset($info['uri']) ? ' title="' . htmlspecialchars($info['uri']) . '"' : NULL) . '><' . htmlSpecialChars($type) . ' resource></i> ';
131:
132: } else {
133: return htmlspecialchars($param);
134: }
135: }, $sql);
136:
137: return '<pre class="dump">' . trim($sql) . "</pre>\n";
138: }
139:
140:
141: 142: 143: 144:
145: public static function detectTypes(\PDOStatement $statement)
146: {
147: $types = array();
148: $count = $statement->columnCount();
149: for ($col = 0; $col < $count; $col++) {
150: $meta = $statement->getColumnMeta($col);
151: if (isset($meta['native_type'])) {
152: $types[$meta['name']] = self::detectType($meta['native_type']);
153: }
154: }
155: return $types;
156: }
157:
158:
159: 160: 161: 162: 163: 164:
165: public static function detectType($type)
166: {
167: static $cache;
168: if (!isset($cache[$type])) {
169: $cache[$type] = 'string';
170: foreach (self::$typePatterns as $s => $val) {
171: if (preg_match("#$s#i", $type)) {
172: return $cache[$type] = $val;
173: }
174: }
175: }
176: return $cache[$type];
177: }
178:
179:
180: 181: 182: 183:
184: public static function loadFromFile(Connection $connection, $file)
185: {
186: @set_time_limit(0);
187:
188: $handle = @fopen($file, 'r');
189: if (!$handle) {
190: throw new Nette\FileNotFoundException("Cannot open file '$file'.");
191: }
192:
193: $count = 0;
194: $delimiter = ';';
195: $sql = '';
196: while (!feof($handle)) {
197: $s = rtrim(fgets($handle));
198: if (!strncasecmp($s, 'DELIMITER ', 10)) {
199: $delimiter = substr($s, 10);
200:
201: } elseif (substr($s, -strlen($delimiter)) === $delimiter) {
202: $sql .= substr($s, 0, -strlen($delimiter));
203: $connection->query($sql);
204: $sql = '';
205: $count++;
206:
207: } else {
208: $sql .= $s . "\n";
209: }
210: }
211: if (trim($sql) !== '') {
212: $connection->query($sql);
213: $count++;
214: }
215: fclose($handle);
216: return $count;
217: }
218:
219:
220: public static function createDebugPanel($connection, $explain = TRUE, $name = NULL)
221: {
222: $panel = new Nette\Bridges\DatabaseTracy\ConnectionPanel($connection);
223: $panel->explain = $explain;
224: $panel->name = $name;
225: Tracy\Debugger::getBar()->addPanel($panel);
226: return $panel;
227: }
228:
229:
230: 231: 232: 233:
234: public static function toPairs(array $rows, $key = NULL, $value = NULL)
235: {
236: if (!$rows) {
237: return array();
238: }
239:
240: $keys = array_keys((array) reset($rows));
241: if (!count($keys)) {
242: throw new \LogicException('Result set does not contain any column.');
243:
244: } elseif ($key === NULL && $value === NULL) {
245: if (count($keys) === 1) {
246: list($value) = $keys;
247: } else {
248: list($key, $value) = $keys;
249: }
250: }
251:
252: $return = array();
253: if ($key === NULL) {
254: foreach ($rows as $row) {
255: $return[] = ($value === NULL ? $row : $row[$value]);
256: }
257: } else {
258: foreach ($rows as $row) {
259: $return[is_object($row[$key]) ? (string) $row[$key] : $row[$key]] = ($value === NULL ? $row : $row[$value]);
260: }
261: }
262:
263: return $return;
264: }
265:
266: }
267: