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