1: <?php
2: 3: 4: 5: 6: 7: 8: 9:
10:
11: namespace Kotchasan\Database;
12:
13: use PDO;
14:
15: 16: 17: 18: 19: 20: 21:
22: class PdoMysqlDriver extends Driver
23: {
24: 25: 26:
27: public function close()
28: {
29: $this->connection = null;
30: }
31:
32: 33: 34: 35: 36: 37: 38:
39: public function connect($param)
40: {
41: $this->options = array(
42: \PDO::ATTR_STRINGIFY_FETCHES => 0,
43: \PDO::ATTR_EMULATE_PREPARES => 0,
44: \PDO::ATTR_PERSISTENT => 1,
45: \PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
46: );
47: foreach ($param as $key => $value) {
48: $this->{$key} = $value;
49: }
50: if ($this->settings->dbdriver == 'mysql') {
51: $this->options[\PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$this->settings->char_set;
52: $this->options[\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY] = 1;
53: }
54: $sql = $this->settings->dbdriver.':host='.$this->settings->hostname;
55: $sql .= empty($this->settings->port) ? '' : ';port='.$this->settings->port;
56: $sql .= empty($this->settings->dbname) ? '' : ';dbname='.$this->settings->dbname;
57: if (isset($this->settings->username) && isset($this->settings->password)) {
58: try {
59: $this->connection = new \PDO($sql, $this->settings->username, $this->settings->password, $this->options);
60: if (defined('SQL_MODE')) {
61: $this->connection->query("SET SESSION sql_mode='".SQL_MODE."'");
62: }
63: } catch (\PDOException $e) {
64: throw new \Exception($e->getMessage(), 500, $e);
65: }
66: } else {
67: throw new \InvalidArgumentException('Database configuration is invalid');
68: }
69: return $this;
70: }
71:
72: 73: 74: 75: 76:
77: public function fieldCount()
78: {
79: if (isset($this->result_id)) {
80: return $this->result_id->columnCount();
81: } else {
82: return 0;
83: }
84: }
85:
86: 87: 88: 89: 90:
91: public function getFields()
92: {
93: $filed_list = array();
94: for ($i = 0, $c = $this->fieldCount(); $i < $c; ++$i) {
95: $result = @$this->result_id->getColumnMeta($i);
96: if ($result) {
97: $filed_list[$result['name']] = $result;
98: }
99: }
100: return $filed_list;
101: }
102:
103: 104: 105: 106: 107: 108: 109: 110: 111:
112: public function insert($table_name, $save)
113: {
114: $params = array();
115: $sql = $this->makeInsert($table_name, $save, $params);
116: try {
117: $query = $this->connection->prepare($sql);
118: $query->execute($params);
119: $this->log('insert', $sql, $params);
120: ++self::$query_count;
121: return (int) $this->connection->lastInsertId();
122: } catch (\PDOException $e) {
123: throw new \Exception($e->getMessage(), 500, $e);
124: }
125: }
126:
127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139:
140: public function insertOrUpdate($table_name, $save)
141: {
142: $updates = array();
143: $params = array();
144: foreach ($save as $key => $value) {
145: $updates[] = '`'.$key.'`=:U'.$key;
146: $params[':U'.$key] = $value;
147: }
148: $sql = $this->makeInsert($table_name, $save, $params);
149: $sql .= ' ON DUPLICATE KEY UPDATE '.implode(', ', $updates);
150: try {
151: $query = $this->connection->prepare($sql);
152: $query->execute($params);
153: $this->log(__FUNCTION__, $sql);
154: ++self::$query_count;
155:
156: return (int) $this->connection->lastInsertId();
157: } catch (\PDOException $e) {
158: throw new \Exception($e->getMessage(), 500, $e);
159: }
160: }
161:
162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176:
177: public function makeQuery($sqls)
178: {
179: $sql = '';
180: if (!empty($sqls['explain'])) {
181: $sql = 'EXPLAIN ';
182: }
183: if (isset($sqls['insert'])) {
184: $keys = array_keys($sqls['keys']);
185: $sql .= 'INSERT INTO '.$sqls['insert'].' (`'.implode('`, `', $keys);
186: $sql .= '`) VALUES ('.implode(', ', $sqls['keys']).')';
187: if (isset($sqls['orupdate'])) {
188: $sql .= ' ON DUPLICATE KEY UPDATE '.implode(', ', $sqls['orupdate']);
189: }
190: } else {
191: if (isset($sqls['union'])) {
192: if (isset($sqls['select'])) {
193: $sql .= 'SELECT '.$sqls['select'].' FROM (('.implode(') UNION (', $sqls['union']).')) AS U9';
194: } else {
195: $sql .= '('.implode(') UNION (', $sqls['union']).')';
196: }
197: } elseif (isset($sqls['unionAll'])) {
198: if (isset($sqls['select'])) {
199: $sql .= 'SELECT '.$sqls['select'].' FROM (('.implode(') UNION ALL (', $sqls['unionAll']).')) AS U9';
200: } else {
201: $sql .= '('.implode(') UNION ALL (', $sqls['unionAll']).')';
202: }
203: } else {
204: if (isset($sqls['select'])) {
205: $sql .= 'SELECT '.$sqls['select'];
206: if (isset($sqls['from'])) {
207: $sql .= ' FROM '.$sqls['from'];
208: }
209: } elseif (isset($sqls['update'])) {
210: $sql .= 'UPDATE '.$sqls['update'];
211: } elseif (isset($sqls['delete'])) {
212: $sql .= 'DELETE FROM '.$sqls['delete'];
213: }
214: }
215: if (isset($sqls['join'])) {
216: foreach ($sqls['join'] as $join) {
217: $sql .= $join;
218: }
219: }
220: if (isset($sqls['set'])) {
221: $sql .= ' SET '.implode(', ', $sqls['set']);
222: }
223: if (isset($sqls['where'])) {
224: $sql .= ' WHERE '.$sqls['where'];
225: }
226: if (isset($sqls['group'])) {
227: $sql .= ' GROUP BY '.$sqls['group'];
228: }
229: if (isset($sqls['having'])) {
230: $sql .= ' HAVING '.$sqls['having'];
231: }
232: if (isset($sqls['order'])) {
233: $sql .= ' ORDER BY '.$sqls['order'];
234: }
235: if (isset($sqls['limit'])) {
236: $sql .= ' LIMIT '.(empty($sqls['start']) ? '' : $sqls['start'].',').$sqls['limit'];
237: }
238: }
239: return $sql;
240: }
241:
242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252:
253: public function select($table_name, $condition, $sort = array(), $limit = 0)
254: {
255: $values = array();
256: $condition = $this->buildWhere($condition);
257: if (is_array($condition)) {
258: $values = $condition[1];
259: $condition = $condition[0];
260: }
261: $sql = 'SELECT * FROM '.$table_name.' WHERE '.$condition;
262: if (!empty($sort)) {
263: if (is_string($sort) && preg_match('/^([a-z0-9_]+)\s(asc|desc)$/i', trim($sort), $match)) {
264: $sql .= ' ORDER BY `'.$match[1].'`'.(empty($match[2]) ? '' : ' '.$match[2]);
265: } elseif (is_array($sort)) {
266: $qs = array();
267: foreach ($sort as $item) {
268: if (preg_match('/^([a-z0-9_]+)\s(asc|desc)$/i', trim($item), $match)) {
269: $qs[] = '`'.$match[1].'`'.(empty($match[2]) ? '' : ' '.$match[2]);
270: }
271: }
272: if (count($qs) > 0) {
273: $sql .= ' ORDER BY '.implode(', ', $qs);
274: }
275: }
276: }
277: if (is_int($limit) && $limit > 0) {
278: $sql .= ' LIMIT '.$limit;
279: }
280: return $this->doCustomQuery($sql, $values);
281: }
282:
283: 284: 285: 286: 287: 288: 289: 290:
291: public function selectDB($database)
292: {
293: $this->settings->dbname = $database;
294: $result = $this->connection->query("USE $database");
295: ++self::$query_count;
296: return $result === false ? false : true;
297: }
298:
299: 300: 301: 302: 303: 304: 305: 306: 307: 308:
309: public function update($table_name, $condition, $save)
310: {
311: $sets = array();
312: $values = array();
313: foreach ($save as $key => $value) {
314: if ($value instanceof QueryBuilder) {
315: $sets[] = '`'.$key.'` = ('.$value->text().')';
316: } elseif ($value instanceof Sql) {
317: $sets[] = '`'.$key.'` = '.$value->text();
318: $values = $value->getValues($values);
319: } else {
320: $k = ':'.$key.count($values);
321: $sets[] = '`'.$key.'` = '.$k;
322: $values[$k] = $value;
323: }
324: }
325: $q = Sql::WHERE($condition);
326: $sql = 'UPDATE '.$table_name.' SET '.implode(', ', $sets).' WHERE '.$q->text();
327: $values = $q->getValues($values);
328: try {
329: $query = $this->connection->prepare($sql);
330: $query->execute($values);
331: $this->log(__FUNCTION__, $sql, $values);
332: ++self::$query_count;
333:
334: return true;
335: } catch (\PDOException $e) {
336: throw new \Exception($e->getMessage(), 500, $e);
337: }
338: }
339:
340: 341: 342: 343: 344: 345: 346: 347: 348:
349: protected function doCustomQuery($sql, $values = array())
350: {
351: $action = $this->cache->getAction();
352: if ($action) {
353: $cache = $this->cache->init($sql, $values);
354: $result = $this->cache->get($cache);
355: } else {
356: $result = false;
357: }
358: if (!$result) {
359: try {
360: if (empty($values)) {
361: $this->result_id = $this->connection->query($sql);
362: } else {
363: $this->result_id = $this->connection->prepare($sql);
364: $this->result_id->execute($values);
365: }
366: ++self::$query_count;
367: $result = $this->result_id->fetchAll(\PDO::FETCH_ASSOC);
368: if ($action == 1) {
369: $this->cache->save($cache, $result);
370: } elseif ($action == 2) {
371: $this->cache_item = $cache;
372: }
373: } catch (\PDOException $e) {
374: throw new \Exception($e->getMessage(), 500, $e);
375: }
376: $this->log('Database', $sql, $values);
377: } else {
378: $this->cache->setAction(0);
379: $this->cache_item = null;
380: $this->log('Cached', $sql, $values);
381: }
382: return $result;
383: }
384:
385: 386: 387: 388: 389: 390: 391: 392: 393:
394: protected function doQuery($sql, $values = array())
395: {
396: try {
397: if (empty($values)) {
398: $query = $this->connection->query($sql);
399: } else {
400: $query = $this->connection->prepare($sql);
401: $query->execute($values);
402: }
403: ++self::$query_count;
404: $this->log(__FUNCTION__, $sql, $values);
405:
406: return $query->rowCount();
407: } catch (\PDOException $e) {
408: throw new \Exception($e->getMessage(), 500, $e);
409: }
410: }
411:
412: 413: 414: 415: 416: 417: 418: 419: 420:
421: private function makeInsert($table_name, $save, &$params)
422: {
423: $keys = array();
424: $values = array();
425: foreach ($save as $key => $value) {
426: if ($value instanceof QueryBuilder) {
427: $keys[] = $key;
428: $values[] = '('.$value->text().')';
429: } elseif ($value instanceof Sql) {
430: $keys[] = $key;
431: $values[] = $value->text();
432: $params = $value->getValues($params);
433: } else {
434: $keys[] = $key;
435: $values[] = ':'.$key;
436: $params[':'.$key] = $value;
437: }
438: }
439: return 'INSERT INTO '.$table_name.' (`'.implode('`,`', $keys).'`) VALUES ('.implode(',', $values).')';
440: }
441: }
442: