1 <?php
2 3 4 5 6 7 8 9 10
11
12 namespace Neevo;
13
14 use Neevo\Cache\StorageInterface;
15 use SplObjectStorage;
16
17
18 19 20 21
22 class Manager implements ObservableInterface, ObserverInterface {
23
24
25
26 public static $defaultDriver = 'mysqli';
27
28
29 private $last;
30
31
32 private $queries = 0;
33
34
35 private $connection;
36
37
38 private $observers;
39
40
41
42 const VERSION = '2.3.2';
43
44
45 const BOOL = 'b',
46 INT = 'i',
47 FLOAT = 'f',
48 TEXT = 's',
49 BINARY = 'bin',
50 DATETIME = 'd',
51 ARR = 'a',
52 LITERAL = 'l',
53 IDENTIFIER = 'id',
54 SUBQUERY = 'sub';
55
56
57 const STMT_SELECT = 'stmt_select',
58 STMT_INSERT = 'stmt_insert',
59 STMT_UPDATE = 'stmt_update',
60 STMT_DELETE = 'stmt_delete';
61
62
63 const JOIN_LEFT = 'join_left',
64 JOIN_INNER = 'join_inner';
65
66
67 const ASC = 'ASC',
68 DESC = 'DESC';
69
70
71 72 73 74 75 76 77
78 public function __construct($config, StorageInterface $cache = null){
79 $this->connection = new Connection($config, $cache);
80 $this->observers = new SplObjectStorage;
81 $this->attachObserver($this, self::QUERY);
82 }
83
84
85 86 87 88 89 90
91 public function select($columns = null, $table = null){
92 $result = new Result($this->connection, $columns, $table);
93 foreach($this->observers as $observer){
94 $result->attachObserver($observer, $this->observers->getInfo());
95 }
96 return $result;
97 }
98
99
100 101 102 103 104 105
106 public function insert($table, $values){
107 $statement = Statement::createInsert($this->connection, $table, $values);
108 foreach($this->observers as $observer){
109 $statement->attachObserver($observer, $this->observers->getInfo());
110 }
111 return $statement;
112 }
113
114
115 116 117 118 119 120
121 public function update($table, $data){
122 $statement = Statement::createUpdate($this->connection, $table, $data);
123 foreach($this->observers as $observer){
124 $statement->attachObserver($observer, $this->observers->getInfo());
125 }
126 return $statement;
127 }
128
129
130 131 132 133 134
135 public function delete($table){
136 $statement = Statement::createDelete($this->connection, $table);
137 foreach($this->observers as $observer){
138 $statement->attachObserver($observer, $this->observers->getInfo());
139 }
140 return $statement;
141 }
142
143
144 145 146 147 148 149 150 151
152 public function loadFile($filename){
153 $this->connection->connect();
154 $abort = ignore_user_abort();
155 @set_time_limit(0);
156 ignore_user_abort(true);
157
158 $handle = @fopen($filename, 'r');
159 if($handle === false){
160 ignore_user_abort($abort);
161 throw new NeevoException("Cannot open file '$filename' for SQL import.");
162 }
163
164 $sql = '';
165 $count = 0;
166 while(!feof($handle)){
167 $content = fgets($handle);
168 $sql .= $content;
169 if(substr(rtrim($content), -1) === ';'){
170
171 $this->connection->getDriver()->runQuery($sql);
172 $sql = '';
173 $count++;
174 }
175 }
176 if(trim($sql)){
177 $this->connection->getDriver()->runQuery($sql);
178 $count++;
179 }
180 fclose($handle);
181 ignore_user_abort($abort);
182 return $count;
183 }
184
185
186 187 188 189 190
191 public function begin($savepoint = null){
192 $this->connection->getDriver()->beginTransaction($savepoint);
193 $this->notifyObservers(ObserverInterface::BEGIN);
194 return $this;
195 }
196
197
198 199 200 201 202
203 public function commit($savepoint = null){
204 $this->connection->getDriver()->commit($savepoint);
205 $this->notifyObservers(ObserverInterface::COMMIT);
206 return $this;
207 }
208
209
210 211 212 213 214
215 public function rollback($savepoint = null){
216 $this->connection->getDriver()->rollback($savepoint);
217 $this->notifyObservers(ObserverInterface::ROLLBACK);
218 return $this;
219 }
220
221
222 223 224 225 226
227 public function attachObserver(ObserverInterface $observer, $event){
228 $this->observers->attach($observer, $event);
229 $this->connection->attachObserver($observer, $event);
230 $e = new NeevoException;
231 $e->attachObserver($observer, $event);
232 }
233
234
235 236 237 238
239 public function detachObserver(ObserverInterface $observer){
240 $this->connection->detachObserver($observer);
241 $this->observers->detach($observer);
242 $e = new NeevoException;
243 $e->detachObserver($observer);
244 }
245
246
247 248 249 250
251 public function notifyObservers($event){
252 foreach($this->observers as $observer){
253 if($event & $this->observers->getInfo())
254 $observer->updateStatus($this, $event);
255 }
256 }
257
258
259 260 261 262 263
264 public function updateStatus(ObservableInterface $subject, $event){
265 $this->last = (string) $subject;
266 $this->queries++;
267 }
268
269
270 271 272 273
274 public function getConnection(){
275 return $this->connection;
276 }
277
278
279 280 281 282
283 public function getLast(){
284 return $this->last;
285 }
286
287
288 289 290 291
292 public function getQueries(){
293 return $this->queries;
294 }
295
296
297 298 299 300 301
302 public static function highlightSql($sql){
303 $keywords1 = 'SELECT|UPDATE|INSERT\s+INTO|DELETE|FROM|VALUES|SET|WHERE|HAVING|GROUP\s+BY|ORDER\s+BY|LIMIT|OFFSET|(?:LEFT\s+|RIGHT\s+|INNER\s+)?JOIN';
304 $keywords2 = 'RANDOM|RAND|ASC|DESC|USING|AND|OR|ON|IN|IS|NOT|NULL|LIKE|TRUE|FALSE|AS';
305
306 $sql = str_replace("\\'", '\\'', $sql);
307 $sql = preg_replace_callback("~(/\\*.*\\*/)|($keywords1)|($keywords2)|('[^']+'|[0-9]+)~", 'self::_highlightCallback', $sql);
308 $sql = str_replace('\\'', "\\'", $sql);
309 return '<pre style="color:#555" class="sql-dump">' . trim($sql) . "</pre>\n";
310 }
311
312
313 private static function _highlightCallback($match){
314
315 if(!empty($match[1]))
316 return '<em style="color:#999">' . $match[1] . '</em>';
317
318 if(!empty($match[2]))
319 return '<strong style="color:#e71818">' . $match[2] . '</strong>';
320
321 if(!empty($match[3]))
322 return '<strong style="color:#d59401">' . $match[3] . '</strong>';
323
324 if(!empty($match[4]) || $match[4] === '0')
325 return '<em style="color:#008000">' . $match[4] . '</em>';
326 }
327
328
329 }
330