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: class SqlPreprocessor extends Nette\Object
23: {
24:
25: private $connection;
26:
27:
28: private $driver;
29:
30:
31: private $params;
32:
33:
34: private $remaining;
35:
36:
37: private $counter;
38:
39:
40: private $arrayMode;
41:
42:
43: public function __construct(Connection $connection)
44: {
45: $this->connection = $connection;
46: $this->driver = $connection->getSupplementalDriver();
47: }
48:
49:
50: 51: 52: 53: 54:
55: public function process($sql, $params)
56: {
57: $this->params = $params;
58: $this->counter = 0;
59: $this->remaining = array();
60: $this->arrayMode = 'assoc';
61:
62: $sql = Nette\Utils\Strings::replace($sql, '~\'.*?\'|".*?"|\?|\b(?:INSERT|REPLACE|UPDATE)\b~si', array($this, 'callback'));
63:
64: while ($this->counter < count($params)) {
65: $sql .= ' ' . $this->formatValue($params[$this->counter++]);
66: }
67:
68: return array($sql, $this->remaining);
69: }
70:
71:
72:
73: public function callback($m)
74: {
75: $m = $m[0];
76: if ($m[0] === "'" || $m[0] === '"') {
77: return $m;
78:
79: } elseif ($m === '?') {
80: if ($this->counter >= count($this->params)) {
81: throw new Nette\InvalidArgumentException('There are more placeholders than passed parameters.');
82: }
83: return $this->formatValue($this->params[$this->counter++]);
84:
85: } else {
86: $this->arrayMode = strtoupper($m) === 'UPDATE' ? 'assoc' : 'values';
87: return $m;
88: }
89: }
90:
91:
92: private function formatValue($value)
93: {
94: if (is_string($value)) {
95: if (strlen($value) > 20) {
96: $this->remaining[] = $value;
97: return '?';
98:
99: } else {
100: return $this->connection->quote($value);
101: }
102:
103: } elseif (is_int($value)) {
104: return (string) $value;
105:
106: } elseif (is_float($value)) {
107: return rtrim(rtrim(number_format($value, 10, '.', ''), '0'), '.');
108:
109: } elseif (is_bool($value)) {
110: return $this->driver->formatBool($value);
111:
112: } elseif ($value === NULL) {
113: return 'NULL';
114:
115: } elseif ($value instanceof Table\ActiveRow) {
116: return $value->getPrimary();
117:
118: } elseif (is_array($value) || $value instanceof \Traversable) {
119: $vx = $kx = array();
120:
121: if ($value instanceof \Traversable) {
122: $value = iterator_to_array($value);
123: }
124:
125: if (isset($value[0])) {
126: foreach ($value as $v) {
127: $vx[] = $this->formatValue($v);
128: }
129: return implode(', ', $vx);
130:
131: } elseif ($this->arrayMode === 'values') {
132: $this->arrayMode = 'multi';
133: foreach ($value as $k => $v) {
134: $kx[] = $this->driver->delimite($k);
135: $vx[] = $this->formatValue($v);
136: }
137: return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')';
138:
139: } elseif ($this->arrayMode === 'assoc') {
140: foreach ($value as $k => $v) {
141: $vx[] = $this->driver->delimite($k) . '=' . $this->formatValue($v);
142: }
143: return implode(', ', $vx);
144:
145: } elseif ($this->arrayMode === 'multi') {
146: foreach ($value as $k => $v) {
147: $vx[] = $this->formatValue($v);
148: }
149: return '(' . implode(', ', $vx) . ')';
150: }
151:
152: } elseif ($value instanceof \DateTime) {
153: return $this->driver->formatDateTime($value);
154:
155: } elseif ($value instanceof SqlLiteral) {
156: return $value->__toString();
157:
158: } else {
159: $this->remaining[] = $value;
160: return '?';
161: }
162: }
163:
164: }
165: