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