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