1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Nette\Database;
13:
14: use Nette;
15:
16:
17:
18: 19: 20: 21: 22:
23: class SqlPreprocessor extends Nette\Object
24: {
25:
26: private $connection;
27:
28:
29: private $driver;
30:
31:
32: private $params;
33:
34:
35: private $remaining;
36:
37:
38: private $counter;
39:
40:
41: private $arrayMode;
42:
43:
44:
45: public function __construct(Connection $connection)
46: {
47: $this->connection = $connection;
48: $this->driver = $connection->getSupplementalDriver();
49: }
50:
51:
52:
53: 54: 55: 56: 57:
58: public function process($sql, $params)
59: {
60: $this->params = $params;
61: $this->counter = 0;
62: $this->remaining = array();
63:
64: $cmd = strtoupper(substr(ltrim($sql), 0, 6));
65: $this->arrayMode = $cmd === 'INSERT' || $cmd === 'REPLAC' ? 'values' : 'assoc';
66:
67: 68: 69: 70: 71:
72: $sql = Nette\Utils\Strings::replace($sql, '~\'.*?\'|".*?"|:[a-zA-Z0-9_]+:|\?~s', array($this, 'callback'));
73:
74: while ($this->counter < count($params)) {
75: $sql .= ' ' . $this->formatValue($params[$this->counter++]);
76: }
77:
78: return array($sql, $this->remaining);
79: }
80:
81:
82:
83:
84: public function callback($m)
85: {
86: $m = $m[0];
87: if ($m[0] === "'" || $m[0] === '"') {
88: return $m;
89:
90: } elseif ($m[0] === '?') {
91: return $this->formatValue($this->params[$this->counter++]);
92:
93: } elseif ($m[0] === ':') {
94: $s = substr($m, 1, -1);
95: return isset($this->connection->substitutions[$s]) ? $this->connection->substitutions[$s] : $m;
96: }
97: }
98:
99:
100:
101: private function formatValue($value)
102: {
103: if (is_string($value)) {
104: if (strlen($value) > 20) {
105: $this->remaining[] = $value;
106: return '?';
107:
108: } else {
109: return $this->connection->quote($value);
110: }
111:
112: } elseif (is_int($value)) {
113: return (string) $value;
114:
115: } elseif (is_float($value)) {
116: return rtrim(rtrim(number_format($value, 10, '.', ''), '0'), '.');
117:
118: } elseif (is_bool($value)) {
119: $this->remaining[] = $value;
120: return '?';
121:
122: } elseif ($value === NULL) {
123: return 'NULL';
124:
125: } elseif (is_array($value) || $value instanceof \Traversable) {
126: $vx = $kx = array();
127:
128: if (isset($value[0])) {
129: foreach ($value as $v) {
130: $vx[] = $this->formatValue($v);
131: }
132: return implode(', ', $vx);
133:
134: } elseif ($this->arrayMode === 'values') {
135: $this->arrayMode = 'multi';
136: foreach ($value as $k => $v) {
137: $kx[] = $this->driver->delimite($k);
138: $vx[] = $this->formatValue($v);
139: }
140: return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')';
141:
142: } elseif ($this->arrayMode === 'assoc') {
143: foreach ($value as $k => $v) {
144: $vx[] = $this->driver->delimite($k) . '=' . $this->formatValue($v);
145: }
146: return implode(', ', $vx);
147:
148: } elseif ($this->arrayMode === 'multi') {
149: foreach ($value as $k => $v) {
150: $vx[] = $this->formatValue($v);
151: }
152: return ', (' . implode(', ', $vx) . ')';
153: }
154:
155: } elseif ($value instanceof \DateTime) {
156: return $this->driver->formatDateTime($value);
157:
158: } elseif ($value instanceof SqlLiteral) {
159: return $value->value;
160:
161: } else {
162: $this->remaining[] = $value;
163: return '?';
164: }
165: }
166:
167: }
168: