1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26: App::import('Core', array('Set', 'String'));
27:
28: 29: 30: 31: 32: 33: 34: 35:
36: class DboSource extends DataSource {
37: 38: 39: 40: 41:
42: var $description = "Database Data Source";
43: 44: 45: 46: 47:
48: var $index = array('PRI' => 'primary', 'MUL' => 'index', 'UNI' => 'unique');
49: 50: 51: 52: 53:
54: var $alias = 'AS ';
55: 56: 57: 58: 59:
60: var $fieldCache = array();
61: 62: 63: 64: 65:
66: var $__bypass = false;
67: 68: 69: 70: 71:
72: var $__sqlOps = array('like', 'ilike', 'or', 'not', 'in', 'between', 'regexp', 'similar to');
73: 74: 75: 76: 77: 78:
79: var $_commands = array(
80: 'begin' => 'BEGIN',
81: 'commit' => 'COMMIT',
82: 'rollback' => 'ROLLBACK'
83: );
84: 85: 86:
87: function __construct($config = null, $autoConnect = true) {
88: if (!isset($config['prefix'])) {
89: $config['prefix'] = '';
90: }
91: parent::__construct($config);
92: $this->fullDebug = Configure::read() > 1;
93: if (!$this->enabled()) {
94: return false;
95: }
96: if ($autoConnect) {
97: return $this->connect();
98: } else {
99: return true;
100: }
101: }
102: 103: 104: 105: 106: 107:
108: function reconnect($config = array()) {
109: $this->disconnect();
110: $this->setConfig($config);
111: $this->_sources = null;
112:
113: return $this->connect();
114: }
115: 116: 117: 118: 119: 120: 121: 122:
123: function value($data, $column = null, $read = true) {
124: if (is_array($data) && !empty($data)) {
125: return array_map(
126: array(&$this, 'value'),
127: $data, array_fill(0, count($data), $column), array_fill(0, count($data), $read)
128: );
129: } elseif (is_object($data) && isset($data->type)) {
130: if ($data->type == 'identifier') {
131: return $this->name($data->value);
132: } elseif ($data->type == 'expression') {
133: return $data->value;
134: }
135: } elseif (in_array($data, array('{$__cakeID__$}', '{$__cakeForeignKey__$}'), true)) {
136: return $data;
137: } else {
138: return null;
139: }
140: }
141: 142: 143: 144: 145: 146:
147: function identifier($identifier) {
148: $obj = new stdClass();
149: $obj->type = 'identifier';
150: $obj->value = $identifier;
151: return $obj;
152: }
153: 154: 155: 156: 157: 158:
159: function expression($expression) {
160: $obj = new stdClass();
161: $obj->type = 'expression';
162: $obj->value = $expression;
163: return $obj;
164: }
165: 166: 167: 168: 169: 170:
171: function rawQuery($sql) {
172: $this->took = $this->error = $this->numRows = false;
173: return $this->execute($sql);
174: }
175: 176: 177: 178: 179: 180: 181: 182: 183:
184: function execute($sql, $options = array()) {
185: $defaults = array('stats' => true, 'log' => $this->fullDebug);
186: $options = array_merge($defaults, $options);
187:
188: $t = getMicrotime();
189: $this->_result = $this->_execute($sql);
190: if ($options['stats']) {
191: $this->took = round((getMicrotime() - $t) * 1000, 0);
192: $this->affected = $this->lastAffected();
193: $this->error = $this->lastError();
194: $this->numRows = $this->lastNumRows();
195: }
196:
197: if ($options['log']) {
198: $this->logQuery($sql);
199: }
200:
201: if ($this->error) {
202: $this->showQuery($sql);
203: return false;
204: }
205: return $this->_result;
206: }
207: 208: 209: 210: 211:
212: function query() {
213: $args = func_get_args();
214: $fields = null;
215: $order = null;
216: $limit = null;
217: $page = null;
218: $recursive = null;
219:
220: if (count($args) == 1) {
221: return $this->fetchAll($args[0]);
222:
223: } elseif (count($args) > 1 && (strpos(strtolower($args[0]), 'findby') === 0 || strpos(strtolower($args[0]), 'findallby') === 0)) {
224: $params = $args[1];
225:
226: if (strpos(strtolower($args[0]), 'findby') === 0) {
227: $all = false;
228: $field = Inflector::underscore(preg_replace('/^findBy/i', '', $args[0]));
229: } else {
230: $all = true;
231: $field = Inflector::underscore(preg_replace('/^findAllBy/i', '', $args[0]));
232: }
233:
234: $or = (strpos($field, '_or_') !== false);
235: if ($or) {
236: $field = explode('_or_', $field);
237: } else {
238: $field = explode('_and_', $field);
239: }
240: $off = count($field) - 1;
241:
242: if (isset($params[1 + $off])) {
243: $fields = $params[1 + $off];
244: }
245:
246: if (isset($params[2 + $off])) {
247: $order = $params[2 + $off];
248: }
249:
250: if (!array_key_exists(0, $params)) {
251: return false;
252: }
253:
254: $c = 0;
255: $conditions = array();
256:
257: foreach ($field as $f) {
258: $conditions[$args[2]->alias . '.' . $f] = $params[$c];
259: $c++;
260: }
261:
262: if ($or) {
263: $conditions = array('OR' => $conditions);
264: }
265:
266: if ($all) {
267: if (isset($params[3 + $off])) {
268: $limit = $params[3 + $off];
269: }
270:
271: if (isset($params[4 + $off])) {
272: $page = $params[4 + $off];
273: }
274:
275: if (isset($params[5 + $off])) {
276: $recursive = $params[5 + $off];
277: }
278: return $args[2]->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive'));
279: } else {
280: if (isset($params[3 + $off])) {
281: $recursive = $params[3 + $off];
282: }
283: return $args[2]->find('first', compact('conditions', 'fields', 'order', 'recursive'));
284: }
285: } else {
286: if (isset($args[1]) && $args[1] === true) {
287: return $this->fetchAll($args[0], true);
288: } else if (isset($args[1]) && !is_array($args[1]) ) {
289: return $this->fetchAll($args[0], false);
290: } else if (isset($args[1]) && is_array($args[1])) {
291: $offset = 0;
292: if (isset($args[2])) {
293: $cache = $args[2];
294: } else {
295: $cache = true;
296: }
297: $args[1] = array_map(array(&$this, 'value'), $args[1]);
298: return $this->fetchAll(String::insert($args[0], $args[1]), $cache);
299: }
300: }
301: }
302: 303: 304: 305: 306:
307: function fetchRow($sql = null) {
308: if (!empty($sql) && is_string($sql) && strlen($sql) > 5) {
309: if (!$this->execute($sql)) {
310: return null;
311: }
312: }
313:
314: if ($this->hasResult()) {
315: $this->resultSet($this->_result);
316: $resultRow = $this->fetchResult();
317: return $resultRow;
318: } else {
319: return null;
320: }
321: }
322: 323: 324: 325: 326: 327: 328: 329:
330: function fetchAll($sql, $cache = true, $modelName = null) {
331: if ($cache && isset($this->_queryCache[$sql])) {
332: if (preg_match('/^\s*select/i', $sql)) {
333: return $this->_queryCache[$sql];
334: }
335: }
336:
337: if ($this->execute($sql)) {
338: $out = array();
339:
340: $first = $this->fetchRow();
341: if ($first != null) {
342: $out[] = $first;
343: }
344: while ($this->hasResult() && $item = $this->fetchResult()) {
345: $out[] = $item;
346: }
347:
348: if ($cache) {
349: if (strpos(trim(strtolower($sql)), 'select') !== false) {
350: $this->_queryCache[$sql] = $out;
351: }
352: }
353: return $out;
354:
355: } else {
356: return false;
357: }
358: }
359: 360: 361: 362: 363: 364: 365:
366: function field($name, $sql) {
367: $data = $this->fetchRow($sql);
368:
369: if (!isset($data[$name]) || empty($data[$name])) {
370: return false;
371: } else {
372: return $data[$name];
373: }
374: }
375: 376: 377: 378: 379: 380: 381:
382: function name($data) {
383: if (is_object($data) && isset($data->type)) {
384: return $data->value;
385: }
386: if ($data == '*') {
387: return '*';
388: }
389: $array = is_array($data);
390: $data = (array)$data;
391: $count = count($data);
392:
393: for ($i = 0; $i < $count; $i++) {
394: if ($data[$i] == '*') {
395: continue;
396: }
397: if (strpos($data[$i], '(') !== false && preg_match_all('/([^(]*)\((.*)\)(.*)/', $data[$i], $fields)) {
398: $fields = Set::extract($fields, '{n}.0');
399:
400: if (!empty($fields[1])) {
401: if (!empty($fields[2])) {
402: $data[$i] = $fields[1] . '(' . $this->name($fields[2]) . ')' . $fields[3];
403: } else {
404: $data[$i] = $fields[1] . '()' . $fields[3];
405: }
406: }
407: }
408: $data[$i] = str_replace('.', $this->endQuote . '.' . $this->startQuote, $data[$i]);
409: $data[$i] = $this->startQuote . $data[$i] . $this->endQuote;
410: $data[$i] = str_replace($this->startQuote . $this->startQuote, $this->startQuote, $data[$i]);
411: $data[$i] = str_replace($this->startQuote . '(', '(', $data[$i]);
412: $data[$i] = str_replace(')' . $this->startQuote, ')', $data[$i]);
413: $alias = !empty($this->alias) ? $this->alias : 'AS ';
414:
415: if (preg_match('/\s+' . $alias . '\s*/', $data[$i])) {
416: if (preg_match('/\w+\s+' . $alias . '\s*/', $data[$i])) {
417: $quoted = $this->endQuote . ' ' . $alias . $this->startQuote;
418: $data[$i] = str_replace(' ' . $alias, $quoted, $data[$i]);
419: } else {
420: $quoted = $alias . $this->startQuote;
421: $data[$i] = str_replace($alias, $quoted, $data[$i]) . $this->endQuote;
422: }
423: }
424:
425: if (!empty($this->endQuote) && $this->endQuote == $this->startQuote) {
426: if (substr_count($data[$i], $this->endQuote) % 2 == 1) {
427: if (substr($data[$i], -2) == $this->endQuote . $this->endQuote) {
428: $data[$i] = substr($data[$i], 0, -1);
429: } else {
430: $data[$i] = trim($data[$i], $this->endQuote);
431: }
432: }
433: }
434: if (strpos($data[$i], '*')) {
435: $data[$i] = str_replace($this->endQuote . '*' . $this->endQuote, '*', $data[$i]);
436: }
437: $data[$i] = str_replace($this->endQuote . $this->endQuote, $this->endQuote, $data[$i]);
438: }
439: return (!$array) ? $data[0] : $data;
440: }
441: 442: 443: 444: 445:
446: function isConnected() {
447: return $this->connected;
448: }
449: 450: 451: 452: 453:
454: function hasResult() {
455: return is_resource($this->_result);
456: }
457: 458: 459: 460: 461:
462: function showLog($sorted = false) {
463: if ($sorted) {
464: $log = sortByKey($this->_queriesLog, 'took', 'desc', SORT_NUMERIC);
465: } else {
466: $log = $this->_queriesLog;
467: }
468:
469: if ($this->_queriesCnt > 1) {
470: $text = 'queries';
471: } else {
472: $text = 'query';
473: }
474:
475: if (PHP_SAPI != 'cli') {
476: print ("<table class=\"cake-sql-log\" id=\"cakeSqlLog_" . preg_replace('/[^A-Za-z0-9_]/', '_', uniqid(time(), true)) . "\" summary=\"Cake SQL Log\" cellspacing=\"0\" border = \"0\">\n<caption>({$this->configKeyName}) {$this->_queriesCnt} {$text} took {$this->_queriesTime} ms</caption>\n");
477: print ("<thead>\n<tr><th>Nr</th><th>Query</th><th>Error</th><th>Affected</th><th>Num. rows</th><th>Took (ms)</th></tr>\n</thead>\n<tbody>\n");
478:
479: foreach ($log as $k => $i) {
480: print ("<tr><td>" . ($k + 1) . "</td><td>" . h($i['query']) . "</td><td>{$i['error']}</td><td style = \"text-align: right\">{$i['affected']}</td><td style = \"text-align: right\">{$i['numRows']}</td><td style = \"text-align: right\">{$i['took']}</td></tr>\n");
481: }
482: print ("</tbody></table>\n");
483: } else {
484: foreach ($log as $k => $i) {
485: print (($k + 1) . ". {$i['query']} {$i['error']}\n");
486: }
487: }
488: }
489: 490: 491: 492: 493: 494:
495: function logQuery($sql) {
496: $this->_queriesCnt++;
497: $this->_queriesTime += $this->took;
498: $this->_queriesLog[] = array(
499: 'query' => $sql,
500: 'error' => $this->error,
501: 'affected' => $this->affected,
502: 'numRows' => $this->numRows,
503: 'took' => $this->took
504: );
505: if (count($this->_queriesLog) > $this->_queriesLogMax) {
506: array_pop($this->_queriesLog);
507: }
508: if ($this->error) {
509: return false;
510: }
511: }
512: 513: 514: 515: 516: 517:
518: function showQuery($sql) {
519: $error = $this->error;
520: if (strlen($sql) > 200 && !$this->fullDebug && Configure::read() > 1) {
521: $sql = substr($sql, 0, 200) . '[...]';
522: }
523: if (Configure::read() > 0) {
524: $out = null;
525: if ($error) {
526: trigger_error("<span style = \"color:Red;text-align:left\"><b>SQL Error:</b> {$this->error}</span>", E_USER_WARNING);
527: } else {
528: $out = ("<small>[Aff:{$this->affected} Num:{$this->numRows} Took:{$this->took}ms]</small>");
529: }
530: pr(sprintf("<p style = \"text-align:left\"><b>Query:</b> %s %s</p>", $sql, $out));
531: }
532: }
533: 534: 535: 536: 537: 538: 539:
540: function fullTableName($model, $quote = true) {
541: if (is_object($model)) {
542: $table = $model->tablePrefix . $model->table;
543: } elseif (isset($this->config['prefix'])) {
544: $table = $this->config['prefix'] . strval($model);
545: } else {
546: $table = strval($model);
547: }
548: if ($quote) {
549: return $this->name($table);
550: }
551: return $table;
552: }
553: 554: 555: 556: 557: 558: 559: 560:
561: function create(&$model, $fields = null, $values = null) {
562: $id = null;
563:
564: if ($fields == null) {
565: unset($fields, $values);
566: $fields = array_keys($model->data);
567: $values = array_values($model->data);
568: }
569: $count = count($fields);
570:
571: for ($i = 0; $i < $count; $i++) {
572: $valueInsert[] = $this->value($values[$i], $model->getColumnType($fields[$i]), false);
573: }
574: for ($i = 0; $i < $count; $i++) {
575: $fieldInsert[] = $this->name($fields[$i]);
576: if ($fields[$i] == $model->primaryKey) {
577: $id = $values[$i];
578: }
579: }
580: $query = array(
581: 'table' => $this->fullTableName($model),
582: 'fields' => implode(', ', $fieldInsert),
583: 'values' => implode(', ', $valueInsert)
584: );
585:
586: if ($this->execute($this->renderStatement('create', $query))) {
587: if (empty($id)) {
588: $id = $this->lastInsertId($this->fullTableName($model, false), $model->primaryKey);
589: }
590: $model->setInsertID($id);
591: $model->id = $id;
592: return true;
593: } else {
594: $model->onError();
595: return false;
596: }
597: }
598: 599: 600: 601: 602: 603: 604: 605:
606: function read(&$model, $queryData = array(), $recursive = null) {
607: $queryData = $this->__scrubQueryData($queryData);
608:
609: $null = null;
610: $array = array();
611: $linkedModels = array();
612: $this->__bypass = false;
613: $this->__booleans = array();
614:
615: if ($recursive === null && isset($queryData['recursive'])) {
616: $recursive = $queryData['recursive'];
617: }
618:
619: if (!is_null($recursive)) {
620: $_recursive = $model->recursive;
621: $model->recursive = $recursive;
622: }
623:
624: if (!empty($queryData['fields'])) {
625: $this->__bypass = true;
626: $queryData['fields'] = $this->fields($model, null, $queryData['fields']);
627: } else {
628: $queryData['fields'] = $this->fields($model);
629: }
630:
631: $_associations = $model->__associations;
632:
633: if ($model->recursive == -1) {
634: $_associations = array();
635: } else if ($model->recursive == 0) {
636: unset($_associations[2], $_associations[3]);
637: }
638:
639: foreach ($_associations as $type) {
640: foreach ($model->{$type} as $assoc => $assocData) {
641: $linkModel =& $model->{$assoc};
642: $external = isset($assocData['external']);
643:
644: if ($model->useDbConfig == $linkModel->useDbConfig) {
645: if (true === $this->generateAssociationQuery($model, $linkModel, $type, $assoc, $assocData, $queryData, $external, $null)) {
646: $linkedModels[$type . '/' . $assoc] = true;
647: }
648: }
649: }
650: }
651:
652: $query = $this->generateAssociationQuery($model, $null, null, null, null, $queryData, false, $null);
653:
654: $resultSet = $this->fetchAll($query, $model->cacheQueries, $model->alias);
655:
656: if ($resultSet === false) {
657: $model->onError();
658: return false;
659: }
660:
661: $filtered = $this->__filterResults($resultSet, $model);
662:
663: if ($model->recursive > -1) {
664: foreach ($_associations as $type) {
665: foreach ($model->{$type} as $assoc => $assocData) {
666: $linkModel =& $model->{$assoc};
667:
668: if (empty($linkedModels[$type . '/' . $assoc])) {
669: if ($model->useDbConfig == $linkModel->useDbConfig) {
670: $db =& $this;
671: } else {
672: $db =& ConnectionManager::getDataSource($linkModel->useDbConfig);
673: }
674: } elseif ($model->recursive > 1 && ($type == 'belongsTo' || $type == 'hasOne')) {
675: $db =& $this;
676: }
677:
678: if (isset($db) && method_exists($db, 'queryAssociation')) {
679: $stack = array($assoc);
680: $db->queryAssociation($model, $linkModel, $type, $assoc, $assocData, $array, true, $resultSet, $model->recursive - 1, $stack);
681: unset($db);
682: }
683: }
684: }
685: $this->__filterResults($resultSet, $model, $filtered);
686: }
687:
688: if (!is_null($recursive)) {
689: $model->recursive = $_recursive;
690: }
691: return $resultSet;
692: }
693: 694: 695: 696: 697: 698: 699: 700:
701: function __filterResults(&$results, &$model, $filtered = array()) {
702: $filtering = array();
703: $count = count($results);
704:
705: for ($i = 0; $i < $count; $i++) {
706: if (is_array($results[$i])) {
707: $classNames = array_keys($results[$i]);
708: $count2 = count($classNames);
709:
710: for ($j = 0; $j < $count2; $j++) {
711: $className = $classNames[$j];
712: if ($model->alias != $className && !in_array($className, $filtered)) {
713: if (!in_array($className, $filtering)) {
714: $filtering[] = $className;
715: }
716:
717: if (isset($model->{$className}) && is_object($model->{$className})) {
718: $data = $model->{$className}->afterFind(array(array($className => $results[$i][$className])), false);
719: }
720: if (isset($data[0][$className])) {
721: $results[$i][$className] = $data[0][$className];
722: }
723: }
724: }
725: }
726: }
727: return $filtering;
728: }
729: 730: 731: 732: 733: 734: 735: 736: 737: 738: 739: 740: 741: 742:
743: function queryAssociation(&$model, &$linkModel, $type, $association, $assocData, &$queryData, $external = false, &$resultSet, $recursive, $stack) {
744: if ($query = $this->generateAssociationQuery($model, $linkModel, $type, $association, $assocData, $queryData, $external, $resultSet)) {
745: if (!isset($resultSet) || !is_array($resultSet)) {
746: if (Configure::read() > 0) {
747: echo '<div style = "font: Verdana bold 12px; color: #FF0000">' . sprintf(__('SQL Error in model %s:', true), $model->alias) . ' ';
748: if (isset($this->error) && $this->error != null) {
749: echo $this->error;
750: }
751: echo '</div>';
752: }
753: return null;
754: }
755: $count = count($resultSet);
756:
757: if ($type === 'hasMany' && empty($assocData['limit']) && !empty($assocData['foreignKey'])) {
758: $ins = $fetch = array();
759: for ($i = 0; $i < $count; $i++) {
760: if ($in = $this->insertQueryData('{$__cakeID__$}', $resultSet[$i], $association, $assocData, $model, $linkModel, $stack)) {
761: $ins[] = $in;
762: }
763: }
764:
765: if (!empty($ins)) {
766: $fetch = $this->fetchAssociated($model, $query, $ins);
767: }
768:
769: if (!empty($fetch) && is_array($fetch)) {
770: if ($recursive > 0) {
771: foreach ($linkModel->__associations as $type1) {
772: foreach ($linkModel->{$type1} as $assoc1 => $assocData1) {
773: $deepModel =& $linkModel->{$assoc1};
774: $tmpStack = $stack;
775: $tmpStack[] = $assoc1;
776:
777: if ($linkModel->useDbConfig === $deepModel->useDbConfig) {
778: $db =& $this;
779: } else {
780: $db =& ConnectionManager::getDataSource($deepModel->useDbConfig);
781: }
782: $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack);
783: }
784: }
785: }
786: }
787: $this->__filterResults($fetch, $model);
788: return $this->__mergeHasMany($resultSet, $fetch, $association, $model, $linkModel, $recursive);
789: } elseif ($type === 'hasAndBelongsToMany') {
790: $ins = $fetch = array();
791: for ($i = 0; $i < $count; $i++) {
792: if ($in = $this->insertQueryData('{$__cakeID__$}', $resultSet[$i], $association, $assocData, $model, $linkModel, $stack)) {
793: $ins[] = $in;
794: }
795: }
796: if (!empty($ins)) {
797: if (count($ins) > 1) {
798: $query = str_replace('{$__cakeID__$}', '(' .implode(', ', $ins) .')', $query);
799: $query = str_replace('= (', 'IN (', $query);
800: $query = str_replace('= (', 'IN (', $query);
801: } else {
802: $query = str_replace('{$__cakeID__$}',$ins[0], $query);
803: }
804:
805: $query = str_replace(' WHERE 1 = 1', '', $query);
806: }
807:
808: $foreignKey = $model->hasAndBelongsToMany[$association]['foreignKey'];
809: $joinKeys = array($foreignKey, $model->hasAndBelongsToMany[$association]['associationForeignKey']);
810: list($with, $habtmFields) = $model->joinModel($model->hasAndBelongsToMany[$association]['with'], $joinKeys);
811: $habtmFieldsCount = count($habtmFields);
812: $q = $this->insertQueryData($query, null, $association, $assocData, $model, $linkModel, $stack);
813:
814: if ($q != false) {
815: $fetch = $this->fetchAll($q, $model->cacheQueries, $model->alias);
816: } else {
817: $fetch = null;
818: }
819: }
820:
821: for ($i = 0; $i < $count; $i++) {
822: $row =& $resultSet[$i];
823:
824: if ($type !== 'hasAndBelongsToMany') {
825: $q = $this->insertQueryData($query, $resultSet[$i], $association, $assocData, $model, $linkModel, $stack);
826: if ($q != false) {
827: $fetch = $this->fetchAll($q, $model->cacheQueries, $model->alias);
828: } else {
829: $fetch = null;
830: }
831: }
832: $selfJoin = false;
833:
834: if ($linkModel->name === $model->name) {
835: $selfJoin = true;
836: }
837:
838: if (!empty($fetch) && is_array($fetch)) {
839: if ($recursive > 0) {
840: foreach ($linkModel->__associations as $type1) {
841: foreach ($linkModel->{$type1} as $assoc1 => $assocData1) {
842: $deepModel =& $linkModel->{$assoc1};
843:
844: if (($type1 === 'belongsTo') || ($deepModel->alias === $model->alias && $type === 'belongsTo') || ($deepModel->alias != $model->alias)) {
845: $tmpStack = $stack;
846: $tmpStack[] = $assoc1;
847: if ($linkModel->useDbConfig == $deepModel->useDbConfig) {
848: $db =& $this;
849: } else {
850: $db =& ConnectionManager::getDataSource($deepModel->useDbConfig);
851: }
852: $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack);
853: }
854: }
855: }
856: }
857: if ($type == 'hasAndBelongsToMany') {
858: $uniqueIds = $merge = array();
859:
860: foreach ($fetch as $j => $data) {
861: if (
862: (isset($data[$with]) && $data[$with][$foreignKey] === $row[$model->alias][$model->primaryKey])
863: ) {
864: if ($habtmFieldsCount <= 2) {
865: unset($data[$with]);
866: }
867: $merge[] = $data;
868: }
869: }
870: if (empty($merge) && !isset($row[$association])) {
871: $row[$association] = $merge;
872: } else {
873: $this->__mergeAssociation($resultSet[$i], $merge, $association, $type);
874: }
875: } else {
876: $this->__mergeAssociation($resultSet[$i], $fetch, $association, $type, $selfJoin);
877: }
878: if (isset($resultSet[$i][$association])) {
879: $resultSet[$i][$association] = $linkModel->afterFind($resultSet[$i][$association], false);
880: }
881: } else {
882: $tempArray[0][$association] = false;
883: $this->__mergeAssociation($resultSet[$i], $tempArray, $association, $type, $selfJoin);
884: }
885: }
886: }
887: }
888: 889: 890: 891: 892: 893: 894: 895:
896: function fetchAssociated($model, $query, $ids) {
897: $query = str_replace('{$__cakeID__$}', implode(', ', $ids), $query);
898: if (count($ids) > 1) {
899: $query = str_replace('= (', 'IN (', $query);
900: $query = str_replace('= (', 'IN (', $query);
901: }
902: return $this->fetchAll($query, $model->cacheQueries, $model->alias);
903: }
904: 905: 906: 907: 908: 909: 910: 911: 912: 913: 914:
915: function __mergeHasMany(&$resultSet, $merge, $association, &$model, &$linkModel) {
916: foreach ($resultSet as $i => $value) {
917: $count = 0;
918: $merged[$association] = array();
919: foreach ($merge as $j => $data) {
920: if (isset($value[$model->alias]) && $value[$model->alias][$model->primaryKey] === $data[$association][$model->hasMany[$association]['foreignKey']]) {
921: if (count($data) > 1) {
922: $data = array_merge($data[$association], $data);
923: unset($data[$association]);
924: foreach ($data as $key => $name) {
925: if (is_numeric($key)) {
926: $data[$association][] = $name;
927: unset($data[$key]);
928: }
929: }
930: $merged[$association][] = $data;
931: } else {
932: $merged[$association][] = $data[$association];
933: }
934: }
935: $count++;
936: }
937: if (isset($value[$model->alias])) {
938: $resultSet[$i] = Set::pushDiff($resultSet[$i], $merged);
939: unset($merged);
940: }
941: }
942: }
943: 944: 945: 946: 947: 948: 949: 950: 951:
952: function __mergeAssociation(&$data, $merge, $association, $type, $selfJoin = false) {
953: if (isset($merge[0]) && !isset($merge[0][$association])) {
954: $association = Inflector::pluralize($association);
955: }
956:
957: if ($type == 'belongsTo' || $type == 'hasOne') {
958: if (isset($merge[$association])) {
959: $data[$association] = $merge[$association][0];
960: } else {
961: if (count($merge[0][$association]) > 1) {
962: foreach ($merge[0] as $assoc => $data2) {
963: if ($assoc != $association) {
964: $merge[0][$association][$assoc] = $data2;
965: }
966: }
967: }
968: if (!isset($data[$association])) {
969: if ($merge[0][$association] != null) {
970: $data[$association] = $merge[0][$association];
971: } else {
972: $data[$association] = array();
973: }
974: } else {
975: if (is_array($merge[0][$association])) {
976: foreach ($data[$association] as $k => $v) {
977: if (!is_array($v)) {
978: $dataAssocTmp[$k] = $v;
979: }
980: }
981:
982: foreach ($merge[0][$association] as $k => $v) {
983: if (!is_array($v)) {
984: $mergeAssocTmp[$k] = $v;
985: }
986: }
987: $dataKeys = array_keys($data);
988: $mergeKeys = array_keys($merge[0]);
989:
990: if ($mergeKeys[0] === $dataKeys[0] || $mergeKeys === $dataKeys) {
991: $data[$association][$association] = $merge[0][$association];
992: } else {
993: $diff = Set::diff($dataAssocTmp, $mergeAssocTmp);
994: $data[$association] = array_merge($merge[0][$association], $diff);
995: }
996: } elseif ($selfJoin && array_key_exists($association, $merge[0])) {
997: $data[$association] = array_merge($data[$association], array($association => array()));
998: }
999: }
1000: }
1001: } else {
1002: if (isset($merge[0][$association]) && $merge[0][$association] === false) {
1003: if (!isset($data[$association])) {
1004: $data[$association] = array();
1005: }
1006: } else {
1007: foreach ($merge as $i => $row) {
1008: if (count($row) == 1) {
1009: if (empty($data[$association]) || (isset($data[$association]) && !in_array($row[$association], $data[$association]))) {
1010: $data[$association][] = $row[$association];
1011: }
1012: } else if (!empty($row)) {
1013: $tmp = array_merge($row[$association], $row);
1014: unset($tmp[$association]);
1015: $data[$association][] = $tmp;
1016: }
1017: }
1018: }
1019: }
1020: }
1021: 1022: 1023: 1024: 1025: 1026: 1027: 1028: 1029: 1030: 1031: 1032: 1033:
1034: function generateAssociationQuery(&$model, &$linkModel, $type, $association = null, $assocData = array(), &$queryData, $external = false, &$resultSet) {
1035: $queryData = $this->__scrubQueryData($queryData);
1036: $assocData = $this->__scrubQueryData($assocData);
1037:
1038: if (empty($queryData['fields'])) {
1039: $queryData['fields'] = $this->fields($model, $model->alias);
1040: } elseif (!empty($model->hasMany) && $model->recursive > -1) {
1041: $assocFields = $this->fields($model, $model->alias, array("{$model->alias}.{$model->primaryKey}"));
1042: $passedFields = $this->fields($model, $model->alias, $queryData['fields']);
1043:
1044: if (count($passedFields) === 1) {
1045: $match = strpos($passedFields[0], $assocFields[0]);
1046: $match1 = strpos($passedFields[0], 'COUNT(');
1047: if ($match === false && $match1 === false) {
1048: $queryData['fields'] = array_merge($passedFields, $assocFields);
1049: } else {
1050: $queryData['fields'] = $passedFields;
1051: }
1052: } else {
1053: $queryData['fields'] = array_merge($passedFields, $assocFields);
1054: }
1055: unset($assocFields, $passedFields);
1056: }
1057:
1058: if ($linkModel == null) {
1059: return $this->buildStatement(
1060: array(
1061: 'fields' => array_unique($queryData['fields']),
1062: 'table' => $this->fullTableName($model),
1063: 'alias' => $model->alias,
1064: 'limit' => $queryData['limit'],
1065: 'offset' => $queryData['offset'],
1066: 'joins' => $queryData['joins'],
1067: 'conditions' => $queryData['conditions'],
1068: 'order' => $queryData['order'],
1069: 'group' => $queryData['group']
1070: ),
1071: $model
1072: );
1073: }
1074: if ($external && !empty($assocData['finderQuery'])) {
1075: return $assocData['finderQuery'];
1076: }
1077:
1078: $alias = $association;
1079: $self = ($model->name == $linkModel->name);
1080: $fields = array();
1081:
1082: if ((!$external && in_array($type, array('hasOne', 'belongsTo')) && $this->__bypass === false) || $external) {
1083: $fields = $this->fields($linkModel, $alias, $assocData['fields']);
1084: }
1085: if (empty($assocData['offset']) && !empty($assocData['page'])) {
1086: $assocData['offset'] = ($assocData['page'] - 1) * $assocData['limit'];
1087: }
1088: $assocData['limit'] = $this->limit($assocData['limit'], $assocData['offset']);
1089:
1090: switch ($type) {
1091: case 'hasOne':
1092: case 'belongsTo':
1093: $conditions = $this->__mergeConditions(
1094: $assocData['conditions'],
1095: $this->getConstraint($type, $model, $linkModel, $alias, array_merge($assocData, compact('external', 'self')))
1096: );
1097:
1098: if (!$self && $external) {
1099: foreach ($conditions as $key => $condition) {
1100: if (is_numeric($key) && strpos($condition, $model->alias . '.') !== false) {
1101: unset($conditions[$key]);
1102: }
1103: }
1104: }
1105:
1106: if ($external) {
1107: $query = array_merge($assocData, array(
1108: 'conditions' => $conditions,
1109: 'table' => $this->fullTableName($linkModel),
1110: 'fields' => $fields,
1111: 'alias' => $alias,
1112: 'group' => null
1113: ));
1114: $query = array_merge(array('order' => $assocData['order'], 'limit' => $assocData['limit']), $query);
1115: } else {
1116: $join = array(
1117: 'table' => $this->fullTableName($linkModel),
1118: 'alias' => $alias,
1119: 'type' => isset($assocData['type']) ? $assocData['type'] : 'LEFT',
1120: 'conditions' => trim($this->conditions($conditions, true, false, $model))
1121: );
1122: $queryData['fields'] = array_merge($queryData['fields'], $fields);
1123:
1124: if (!empty($assocData['order'])) {
1125: $queryData['order'][] = $assocData['order'];
1126: }
1127: if (!in_array($join, $queryData['joins'])) {
1128: $queryData['joins'][] = $join;
1129: }
1130: return true;
1131: }
1132: break;
1133: case 'hasMany':
1134: $assocData['fields'] = $this->fields($linkModel, $alias, $assocData['fields']);
1135: if (!empty($assocData['foreignKey'])) {
1136: $assocData['fields'] = array_merge($assocData['fields'], $this->fields($linkModel, $alias, array("{$alias}.{$assocData['foreignKey']}")));
1137: }
1138: $query = array(
1139: 'conditions' => $this->__mergeConditions($this->getConstraint('hasMany', $model, $linkModel, $alias, $assocData), $assocData['conditions']),
1140: 'fields' => array_unique($assocData['fields']),
1141: 'table' => $this->fullTableName($linkModel),
1142: 'alias' => $alias,
1143: 'order' => $assocData['order'],
1144: 'limit' => $assocData['limit'],
1145: 'group' => null
1146: );
1147: break;
1148: case 'hasAndBelongsToMany':
1149: $joinFields = array();
1150: $joinAssoc = null;
1151:
1152: if (isset($assocData['with']) && !empty($assocData['with'])) {
1153: $joinKeys = array($assocData['foreignKey'], $assocData['associationForeignKey']);
1154: list($with, $joinFields) = $model->joinModel($assocData['with'], $joinKeys);
1155:
1156: $joinTbl = $this->fullTableName($model->{$with});
1157: $joinAlias = $joinTbl;
1158:
1159: if (is_array($joinFields) && !empty($joinFields)) {
1160: $joinFields = $this->fields($model->{$with}, $model->{$with}->alias, $joinFields);
1161: $joinAssoc = $joinAlias = $model->{$with}->alias;
1162: } else {
1163: $joinFields = array();
1164: }
1165: } else {
1166: $joinTbl = $this->fullTableName($assocData['joinTable']);
1167: $joinAlias = $joinTbl;
1168: }
1169: $query = array(
1170: 'conditions' => $assocData['conditions'],
1171: 'limit' => $assocData['limit'],
1172: 'table' => $this->fullTableName($linkModel),
1173: 'alias' => $alias,
1174: 'fields' => array_merge($this->fields($linkModel, $alias, $assocData['fields']), $joinFields),
1175: 'order' => $assocData['order'],
1176: 'group' => null,
1177: 'joins' => array(array(
1178: 'table' => $joinTbl,
1179: 'alias' => $joinAssoc,
1180: 'conditions' => $this->getConstraint('hasAndBelongsToMany', $model, $linkModel, $joinAlias, $assocData, $alias)
1181: ))
1182: );
1183: break;
1184: }
1185: if (isset($query)) {
1186: return $this->buildStatement($query, $model);
1187: }
1188: return null;
1189: }
1190: 1191: 1192: 1193: 1194: 1195: 1196: 1197:
1198: function getConstraint($type, $model, $linkModel, $alias, $assoc, $alias2 = null) {
1199: $assoc = array_merge(array('external' => false, 'self' => false), $assoc);
1200:
1201: if (array_key_exists('foreignKey', $assoc) && empty($assoc['foreignKey'])) {
1202: return array();
1203: }
1204:
1205: switch (true) {
1206: case ($assoc['external'] && $type == 'hasOne'):
1207: return array("{$alias}.{$assoc['foreignKey']}" => '{$__cakeID__$}');
1208: break;
1209: case ($assoc['external'] && $type == 'belongsTo'):
1210: return array("{$alias}.{$linkModel->primaryKey}" => '{$__cakeForeignKey__$}');
1211: break;
1212: case (!$assoc['external'] && $type == 'hasOne'):
1213: return array("{$alias}.{$assoc['foreignKey']}" => $this->identifier("{$model->alias}.{$model->primaryKey}"));
1214: break;
1215: case (!$assoc['external'] && $type == 'belongsTo'):
1216: return array("{$model->alias}.{$assoc['foreignKey']}" => $this->identifier("{$alias}.{$linkModel->primaryKey}"));
1217: break;
1218: case ($type == 'hasMany'):
1219: return array("{$alias}.{$assoc['foreignKey']}" => array('{$__cakeID__$}'));
1220: break;
1221: case ($type == 'hasAndBelongsToMany'):
1222: return array(
1223: array("{$alias}.{$assoc['foreignKey']}" => '{$__cakeID__$}'),
1224: array("{$alias}.{$assoc['associationForeignKey']}" => $this->identifier("{$alias2}.{$linkModel->primaryKey}"))
1225: );
1226: break;
1227: }
1228: return array();
1229: }
1230: 1231: 1232: 1233: 1234: 1235: 1236: 1237:
1238: function buildJoinStatement($join) {
1239: $data = array_merge(array(
1240: 'type' => null,
1241: 'alias' => null,
1242: 'table' => 'join_table',
1243: 'conditions' => array()
1244: ), $join);
1245:
1246: if (!empty($data['alias'])) {
1247: $data['alias'] = $this->alias . $this->name($data['alias']);
1248: }
1249: if (!empty($data['conditions'])) {
1250: $data['conditions'] = trim($this->conditions($data['conditions'], true, false));
1251: }
1252: return $this->renderJoinStatement($data);
1253: }
1254: 1255: 1256: 1257: 1258: 1259: 1260: 1261:
1262: function buildStatement($query, $model) {
1263: $query = array_merge(array('offset' => null, 'joins' => array()), $query);
1264: if (!empty($query['joins'])) {
1265: $count = count($query['joins']);
1266: for ($i = 0; $i < $count; $i++) {
1267: if (is_array($query['joins'][$i])) {
1268: $query['joins'][$i] = $this->buildJoinStatement($query['joins'][$i]);
1269: }
1270: }
1271: }
1272: return $this->renderStatement('select', array(
1273: 'conditions' => $this->conditions($query['conditions'], true, true, $model),
1274: 'fields' => implode(', ', $query['fields']),
1275: 'table' => $query['table'],
1276: 'alias' => $this->alias . $this->name($query['alias']),
1277: 'order' => $this->order($query['order']),
1278: 'limit' => $this->limit($query['limit'], $query['offset']),
1279: 'joins' => implode(' ', $query['joins']),
1280: 'group' => $this->group($query['group'])
1281: ));
1282: }
1283: 1284: 1285: 1286: 1287: 1288:
1289: function renderJoinStatement($data) {
1290: extract($data);
1291: return trim("{$type} JOIN {$table} {$alias} ON ({$conditions})");
1292: }
1293: 1294: 1295: 1296: 1297: 1298: 1299:
1300: function renderStatement($type, $data) {
1301: extract($data);
1302: $aliases = null;
1303:
1304: switch (strtolower($type)) {
1305: case 'select':
1306: return "SELECT {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order} {$limit}";
1307: break;
1308: case 'create':
1309: return "INSERT INTO {$table} ({$fields}) VALUES ({$values})";
1310: break;
1311: case 'update':
1312: if (!empty($alias)) {
1313: $aliases = "{$this->alias}{$alias} {$joins} ";
1314: }
1315: return "UPDATE {$table} {$aliases}SET {$fields} {$conditions}";
1316: break;
1317: case 'delete':
1318: if (!empty($alias)) {
1319: $aliases = "{$this->alias}{$alias} {$joins} ";
1320: }
1321: return "DELETE {$alias} FROM {$table} {$aliases}{$conditions}";
1322: break;
1323: case 'schema':
1324: foreach (array('columns', 'indexes') as $var) {
1325: if (is_array(${$var})) {
1326: ${$var} = "\t" . implode(",\n\t", array_filter(${$var}));
1327: }
1328: }
1329: if (trim($indexes) != '') {
1330: $columns .= ',';
1331: }
1332: return "CREATE TABLE {$table} (\n{$columns}{$indexes});";
1333: break;
1334: case 'alter':
1335: break;
1336: }
1337: }
1338: 1339: 1340: 1341: 1342:
1343: function __mergeConditions($query, $assoc) {
1344: if (empty($assoc)) {
1345: return $query;
1346: }
1347:
1348: if (is_array($query)) {
1349: return array_merge((array)$assoc, $query);
1350: }
1351:
1352: if (!empty($query)) {
1353: $query = array($query);
1354: if (is_array($assoc)) {
1355: $query = array_merge($query, $assoc);
1356: } else {
1357: $query[] = $assoc;
1358: }
1359: return $query;
1360: }
1361:
1362: return $assoc;
1363: }
1364: 1365: 1366: 1367: 1368: 1369: 1370: 1371: 1372: 1373:
1374: function update(&$model, $fields = array(), $values = null, $conditions = null) {
1375: if ($values == null) {
1376: $combined = $fields;
1377: } else {
1378: $combined = array_combine($fields, $values);
1379: }
1380:
1381: $fields = implode(', ', $this->_prepareUpdateFields($model, $combined, empty($conditions)));
1382:
1383: $alias = $joins = null;
1384: $table = $this->fullTableName($model);
1385: $conditions = $this->_matchRecords($model, $conditions);
1386:
1387: if ($conditions === false) {
1388: return false;
1389: }
1390: $query = compact('table', 'alias', 'joins', 'fields', 'conditions');
1391:
1392: if (!$this->execute($this->renderStatement('update', $query))) {
1393: $model->onError();
1394: return false;
1395: }
1396: return true;
1397: }
1398: 1399: 1400: 1401: 1402: 1403: 1404: 1405: 1406: 1407:
1408: function _prepareUpdateFields(&$model, $fields, $quoteValues = true, $alias = false) {
1409: $quotedAlias = $this->startQuote . $model->alias . $this->endQuote;
1410:
1411: $updates = array();
1412: foreach ($fields as $field => $value) {
1413: if ($alias && strpos($field, '.') === false) {
1414: $quoted = $model->escapeField($field);
1415: } elseif (!$alias && strpos($field, '.') !== false) {
1416: $quoted = $this->name(str_replace($quotedAlias . '.', '', str_replace(
1417: $model->alias . '.', '', $field
1418: )));
1419: } else {
1420: $quoted = $this->name($field);
1421: }
1422:
1423: if ($value === null) {
1424: $updates[] = $quoted . ' = NULL';
1425: continue;
1426: }
1427: $update = $quoted . ' = ';
1428:
1429: if ($quoteValues) {
1430: $update .= $this->value($value, $model->getColumnType($field), false);
1431: } elseif (!$alias) {
1432: $update .= str_replace($quotedAlias . '.', '', str_replace(
1433: $model->alias . '.', '', $value
1434: ));
1435: } else {
1436: $update .= $value;
1437: }
1438: $updates[] = $update;
1439: }
1440: return $updates;
1441: }
1442: 1443: 1444: 1445: 1446: 1447: 1448: 1449:
1450: function delete(&$model, $conditions = null) {
1451: $alias = $joins = null;
1452: $table = $this->fullTableName($model);
1453: $conditions = $this->_matchRecords($model, $conditions);
1454:
1455: if ($conditions === false) {
1456: return false;
1457: }
1458:
1459: if ($this->execute($this->renderStatement('delete', compact('alias', 'table', 'joins', 'conditions'))) === false) {
1460: $model->onError();
1461: return false;
1462: }
1463: return true;
1464: }
1465: 1466: 1467: 1468: 1469: 1470: 1471: 1472: 1473:
1474: function _matchRecords(&$model, $conditions = null) {
1475: if ($conditions === true) {
1476: $conditions = $this->conditions(true);
1477: } elseif ($conditions === null) {
1478: $conditions = $this->conditions($this->defaultConditions($model, $conditions, false), true, true, $model);
1479: } else {
1480: $noJoin = true;
1481: foreach ($conditions as $field => $value) {
1482: $originalField = $field;
1483: if (strpos($field, '.') !== false) {
1484: list($alias, $field) = explode('.', $field);
1485: }
1486: if (!$model->hasField($field)) {
1487: $noJoin = false;
1488: break;
1489: }
1490: if ($field !== $originalField) {
1491: $conditions[$field] = $value;
1492: unset($conditions[$originalField]);
1493: }
1494: }
1495: if ($noJoin === true) {
1496: return $this->conditions($conditions);
1497: }
1498: $idList = $model->find('all', array(
1499: 'fields' => "{$model->alias}.{$model->primaryKey}",
1500: 'conditions' => $conditions
1501: ));
1502:
1503: if (empty($idList)) {
1504: return false;
1505: }
1506: $conditions = $this->conditions(array(
1507: $model->primaryKey => Set::extract($idList, "{n}.{$model->alias}.{$model->primaryKey}")
1508: ));
1509: }
1510: return $conditions;
1511: }
1512: 1513: 1514: 1515: 1516: 1517:
1518: function _getJoins($model) {
1519: $join = array();
1520: $joins = array_merge($model->getAssociated('hasOne'), $model->getAssociated('belongsTo'));
1521:
1522: foreach ($joins as $assoc) {
1523: if (isset($model->{$assoc}) && $model->useDbConfig == $model->{$assoc}->useDbConfig) {
1524: $assocData = $model->getAssociated($assoc);
1525: $join[] = $this->buildJoinStatement(array(
1526: 'table' => $this->fullTableName($model->{$assoc}),
1527: 'alias' => $assoc,
1528: 'type' => isset($assocData['type']) ? $assocData['type'] : 'LEFT',
1529: 'conditions' => trim($this->conditions(
1530: $this->__mergeConditions($assocData['conditions'], $this->getConstraint($assocData['association'], $model, $model->{$assoc}, $assoc, $assocData)),
1531: true, false, $model
1532: ))
1533: ));
1534: }
1535: }
1536: return $join;
1537: }
1538: 1539: 1540: 1541: 1542: 1543: 1544: 1545: 1546:
1547: function calculate(&$model, $func, $params = array()) {
1548: $params = (array)$params;
1549:
1550: switch (strtolower($func)) {
1551: case 'count':
1552: if (!isset($params[0])) {
1553: $params[0] = '*';
1554: }
1555: if (!isset($params[1])) {
1556: $params[1] = 'count';
1557: }
1558: return 'COUNT(' . $this->name($params[0]) . ') AS ' . $this->name($params[1]);
1559: case 'max':
1560: case 'min':
1561: if (!isset($params[1])) {
1562: $params[1] = $params[0];
1563: }
1564: return strtoupper($func) . '(' . $this->name($params[0]) . ') AS ' . $this->name($params[1]);
1565: break;
1566: }
1567: }
1568: 1569: 1570: 1571: 1572: 1573: 1574: 1575:
1576: function truncate($table) {
1577: return $this->execute('TRUNCATE TABLE ' . $this->fullTableName($table));
1578: }
1579: 1580: 1581: 1582: 1583: 1584: 1585: 1586:
1587: function begin(&$model) {
1588: if (parent::begin($model) && $this->execute($this->_commands['begin'])) {
1589: $this->_transactionStarted = true;
1590: return true;
1591: }
1592: return false;
1593: }
1594: 1595: 1596: 1597: 1598: 1599: 1600: 1601:
1602: function commit(&$model) {
1603: if (parent::commit($model) && $this->execute($this->_commands['commit'])) {
1604: $this->_transactionStarted = false;
1605: return true;
1606: }
1607: return false;
1608: }
1609: 1610: 1611: 1612: 1613: 1614: 1615: 1616:
1617: function rollback(&$model) {
1618: if (parent::rollback($model) && $this->execute($this->_commands['rollback'])) {
1619: $this->_transactionStarted = false;
1620: return true;
1621: }
1622: return false;
1623: }
1624: 1625: 1626: 1627: 1628: 1629: 1630: 1631: 1632: 1633: 1634: 1635: 1636: 1637:
1638: function defaultConditions(&$model, $conditions, $useAlias = true) {
1639: if (!empty($conditions)) {
1640: return $conditions;
1641: }
1642: $exists = $model->exists();
1643: if (!$exists && $conditions !== null) {
1644: return false;
1645: } elseif (!$exists) {
1646: return null;
1647: }
1648: $alias = $model->alias;
1649:
1650: if (!$useAlias) {
1651: $alias = $this->fullTableName($model, false);
1652: }
1653: return array("{$alias}.{$model->primaryKey}" => $model->getID());
1654: }
1655: 1656: 1657: 1658: 1659: 1660: 1661: 1662:
1663: function resolveKey($model, $key, $assoc = null) {
1664: if (empty($assoc)) {
1665: $assoc = $model->alias;
1666: }
1667: if (!strpos('.', $key)) {
1668: return $this->name($model->alias) . '.' . $this->name($key);
1669: }
1670: return $key;
1671: }
1672: 1673: 1674: 1675: 1676: 1677:
1678: function __scrubQueryData($data) {
1679: foreach (array('conditions', 'fields', 'joins', 'order', 'limit', 'offset', 'group') as $key) {
1680: if (!isset($data[$key]) || empty($data[$key])) {
1681: $data[$key] = array();
1682: }
1683: }
1684: return $data;
1685: }
1686: 1687: 1688: 1689: 1690: 1691: 1692: 1693: 1694:
1695: function fields(&$model, $alias = null, $fields = array(), $quote = true) {
1696: if (empty($alias)) {
1697: $alias = $model->alias;
1698: }
1699: if (empty($fields)) {
1700: $fields = array_keys($model->schema());
1701: } elseif (!is_array($fields)) {
1702: $fields = String::tokenize($fields);
1703: }
1704: $fields = array_values(array_filter($fields));
1705:
1706: if (!$quote) {
1707: return $fields;
1708: }
1709: $count = count($fields);
1710:
1711: if ($count >= 1 && !in_array($fields[0], array('*', 'COUNT(*)'))) {
1712: for ($i = 0; $i < $count; $i++) {
1713: if (is_object($fields[$i]) && isset($fields[$i]->type) && $fields[$i]->type === 'expression') {
1714: $fields[$i] = $fields[$i]->value;
1715: } elseif (preg_match('/^\(.*\)\s' . $this->alias . '.*/i', $fields[$i])){
1716: continue;
1717: } elseif (!preg_match('/^.+\\(.*\\)/', $fields[$i])) {
1718: $prepend = '';
1719:
1720: if (strpos($fields[$i], 'DISTINCT') !== false) {
1721: $prepend = 'DISTINCT ';
1722: $fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i]));
1723: }
1724: $dot = strpos($fields[$i], '.');
1725:
1726: if ($dot === false) {
1727: $prefix = !(
1728: strpos($fields[$i], ' ') !== false ||
1729: strpos($fields[$i], '(') !== false
1730: );
1731: $fields[$i] = $this->name(($prefix ? $alias . '.' : '') . $fields[$i]);
1732: } else {
1733: $value = array();
1734: $comma = strpos($fields[$i], ',');
1735: if ($comma === false) {
1736: $build = explode('.', $fields[$i]);
1737: if (!Set::numeric($build)) {
1738: $fields[$i] = $this->name($build[0] . '.' . $build[1]);
1739: }
1740: $comma = String::tokenize($fields[$i]);
1741: foreach ($comma as $string) {
1742: if (preg_match('/^[0-9]+\.[0-9]+$/', $string)) {
1743: $value[] = $string;
1744: } else {
1745: $build = explode('.', $string);
1746: $value[] = $this->name(trim($build[0]) . '.' . trim($build[1]));
1747: }
1748: }
1749: $fields[$i] = implode(', ', $value);
1750: }
1751: }
1752: $fields[$i] = $prepend . $fields[$i];
1753: } elseif (preg_match('/\(([\.\w]+)\)/', $fields[$i], $field)) {
1754: if (isset($field[1])) {
1755: if (strpos($field[1], '.') === false) {
1756: $field[1] = $this->name($alias . '.' . $field[1]);
1757: } else {
1758: $field[0] = explode('.', $field[1]);
1759: if (!Set::numeric($field[0])) {
1760: $field[0] = implode('.', array_map(array($this, 'name'), $field[0]));
1761: $fields[$i] = preg_replace('/\(' . $field[1] . '\)/', '(' . $field[0] . ')', $fields[$i], 1);
1762: }
1763: }
1764: }
1765: }
1766: }
1767: }
1768: return array_unique($fields);
1769: }
1770: 1771: 1772: 1773: 1774: 1775: 1776: 1777: 1778: 1779: 1780:
1781: function conditions($conditions, $quoteValues = true, $where = true, $model = null) {
1782: $clause = $out = '';
1783:
1784: if ($where) {
1785: $clause = ' WHERE ';
1786: }
1787:
1788: if (is_array($conditions) && !empty($conditions)) {
1789: $out = $this->conditionKeysToString($conditions, $quoteValues, $model);
1790:
1791: if (empty($out)) {
1792: return $clause . ' 1 = 1';
1793: }
1794: return $clause . implode(' AND ', $out);
1795: }
1796: if ($conditions === false || $conditions === true) {
1797: return $clause . (int)$conditions . ' = 1';
1798: }
1799:
1800: if (empty($conditions) || trim($conditions) == '') {
1801: return $clause . '1 = 1';
1802: }
1803: $clauses = '/^WHERE\\x20|^GROUP\\x20BY\\x20|^HAVING\\x20|^ORDER\\x20BY\\x20/i';
1804:
1805: if (preg_match($clauses, $conditions, $match)) {
1806: $clause = '';
1807: }
1808: if (trim($conditions) == '') {
1809: $conditions = ' 1 = 1';
1810: } else {
1811: $conditions = $this->__quoteFields($conditions);
1812: }
1813: return $clause . $conditions;
1814: }
1815: 1816: 1817: 1818: 1819: 1820: 1821: 1822:
1823: function conditionKeysToString($conditions, $quoteValues = true, $model = null) {
1824: $c = 0;
1825: $out = array();
1826: $data = $columnType = null;
1827: $bool = array('and', 'or', 'not', 'and not', 'or not', 'xor', '||', '&&');
1828:
1829: foreach ($conditions as $key => $value) {
1830: $join = ' AND ';
1831: $not = null;
1832:
1833: if (is_array($value)) {
1834: $valueInsert = (
1835: !empty($value) &&
1836: (substr_count($key, '?') == count($value) || substr_count($key, ':') == count($value))
1837: );
1838: }
1839:
1840: if (is_numeric($key) && empty($value)) {
1841: continue;
1842: } elseif (is_numeric($key) && is_string($value)) {
1843: $out[] = $not . $this->__quoteFields($value);
1844: } elseif ((is_numeric($key) && is_array($value)) || in_array(strtolower(trim($key)), $bool)) {
1845: if (in_array(strtolower(trim($key)), $bool)) {
1846: $join = ' ' . strtoupper($key) . ' ';
1847: } else {
1848: $key = $join;
1849: }
1850: $value = $this->conditionKeysToString($value, $quoteValues, $model);
1851:
1852: if (strpos($join, 'NOT') !== false) {
1853: if (strtoupper(trim($key)) == 'NOT') {
1854: $key = 'AND ' . trim($key);
1855: }
1856: $not = 'NOT ';
1857: }
1858:
1859: if (empty($value[1])) {
1860: if ($not) {
1861: $out[] = $not . '(' . $value[0] . ')';
1862: } else {
1863: $out[] = $value[0] ;
1864: }
1865: } else {
1866: $out[] = '(' . $not . '(' . implode(') ' . strtoupper($key) . ' (', $value) . '))';
1867: }
1868:
1869: } else {
1870: if (is_object($value) && isset($value->type)) {
1871: if ($value->type == 'identifier') {
1872: $data .= $this->name($key) . ' = ' . $this->name($value->value);
1873: } elseif ($value->type == 'expression') {
1874: if (is_numeric($key)) {
1875: $data .= $value->value;
1876: } else {
1877: $data .= $this->name($key) . ' = ' . $value->value;
1878: }
1879: }
1880: } elseif (is_array($value) && !empty($value) && !$valueInsert) {
1881: $keys = array_keys($value);
1882: if (array_keys($value) === array_values(array_keys($value))) {
1883: $count = count($value);
1884: if ($count === 1) {
1885: $data = $this->__quoteFields($key) . ' = (';
1886: } else {
1887: $data = $this->__quoteFields($key) . ' IN (';
1888: }
1889: if ($quoteValues || strpos($value[0], '-!') !== 0) {
1890: if (is_object($model)) {
1891: $columnType = $model->getColumnType($key);
1892: }
1893: $data .= implode(', ', $this->value($value, $columnType));
1894: }
1895: $data .= ')';
1896: } else {
1897: $ret = $this->conditionKeysToString($value, $quoteValues, $model);
1898: if (count($ret) > 1) {
1899: $data = '(' . implode(') AND (', $ret) . ')';
1900: } elseif (isset($ret[0])) {
1901: $data = $ret[0];
1902: }
1903: }
1904: } elseif (is_numeric($key) && !empty($value)) {
1905: $data = $this->__quoteFields($value);
1906: } else {
1907: $data = $this->__parseKey($model, trim($key), $value);
1908: }
1909:
1910: if ($data != null) {
1911: if (preg_match('/^\(\(\((.+)\)\)\)$/', $data)) {
1912: $data = substr($data, 1, strlen($data) - 2);
1913: }
1914: $out[] = $data;
1915: $data = null;
1916: }
1917: }
1918: $c++;
1919: }
1920: return $out;
1921: }
1922: 1923: 1924: 1925: 1926: 1927: 1928: 1929: 1930: 1931:
1932: function __parseKey($model, $key, $value) {
1933: $operatorMatch = '/^((' . implode(')|(', $this->__sqlOps);
1934: $operatorMatch .= '\\x20)|<[>=]?(?![^>]+>)\\x20?|[>=!]{1,3}(?!<)\\x20?)/is';
1935: $bound = (strpos($key, '?') !== false || (is_array($value) && strpos($key, ':') !== false));
1936:
1937: if (!strpos($key, ' ')) {
1938: $operator = '=';
1939: } else {
1940: list($key, $operator) = explode(' ', trim($key), 2);
1941:
1942: if (!preg_match($operatorMatch, trim($operator)) && strpos($operator, ' ') !== false) {
1943: $key = $key . ' ' . $operator;
1944: $split = strrpos($key, ' ');
1945: $operator = substr($key, $split);
1946: $key = substr($key, 0, $split);
1947: }
1948: }
1949:
1950:
1951: $type = (is_object($model) ? $model->getColumnType($key) : null);
1952:
1953: $null = ($value === null || (is_array($value) && empty($value)));
1954:
1955: if (strtolower($operator) === 'not') {
1956: $data = $this->conditionKeysToString(
1957: array($operator => array($key => $value)), true, $model
1958: );
1959: return $data[0];
1960: }
1961:
1962: $value = $this->value($value, $type);
1963:
1964: if ($key !== '?') {
1965: $isKey = (strpos($key, '(') !== false || strpos($key, ')') !== false);
1966: $key = $isKey ? $this->__quoteFields($key) : $this->name($key);
1967: }
1968:
1969: if ($bound) {
1970: return String::insert($key . ' ' . trim($operator), $value);
1971: }
1972:
1973: if (!preg_match($operatorMatch, trim($operator))) {
1974: $operator .= ' =';
1975: }
1976: $operator = trim($operator);
1977:
1978: if (is_array($value)) {
1979: $value = implode(', ', $value);
1980:
1981: switch ($operator) {
1982: case '=':
1983: $operator = 'IN';
1984: break;
1985: case '!=':
1986: case '<>':
1987: $operator = 'NOT IN';
1988: break;
1989: }
1990: $value = "({$value})";
1991: } elseif ($null) {
1992: switch ($operator) {
1993: case '=':
1994: $operator = 'IS';
1995: break;
1996: case '!=':
1997: case '<>':
1998: $operator = 'IS NOT';
1999: break;
2000: }
2001: }
2002:
2003: return "{$key} {$operator} {$value}";
2004: }
2005: 2006: 2007: 2008: 2009: 2010: 2011:
2012: function __quoteFields($conditions) {
2013: $start = $end = null;
2014: $original = $conditions;
2015:
2016: if (!empty($this->startQuote)) {
2017: $start = preg_quote($this->startQuote);
2018: }
2019: if (!empty($this->endQuote)) {
2020: $end = preg_quote($this->endQuote);
2021: }
2022: $conditions = str_replace(array($start, $end), '', $conditions);
2023: preg_match_all('/(?:[\'\"][^\'\"\\\]*(?:\\\.[^\'\"\\\]*)*[\'\"])|([a-z0-9_' . $start . $end . ']*\\.[a-z0-9_' . $start . $end . ']*)/i', $conditions, $replace, PREG_PATTERN_ORDER);
2024:
2025: if (isset($replace['1']['0'])) {
2026: $pregCount = count($replace['1']);
2027:
2028: for ($i = 0; $i < $pregCount; $i++) {
2029: if (!empty($replace['1'][$i]) && !is_numeric($replace['1'][$i])) {
2030: $conditions = preg_replace('/\b' . preg_quote($replace['1'][$i]) . '\b/', $this->name($replace['1'][$i]), $conditions);
2031: }
2032: }
2033: return $conditions;
2034: }
2035: return $original;
2036: }
2037: 2038: 2039: 2040: 2041: 2042: 2043:
2044: function limit($limit, $offset = null) {
2045: if ($limit) {
2046: $rt = '';
2047: if (!strpos(strtolower($limit), 'limit') || strpos(strtolower($limit), 'limit') === 0) {
2048: $rt = ' LIMIT';
2049: }
2050:
2051: if ($offset) {
2052: $rt .= ' ' . $offset . ',';
2053: }
2054:
2055: $rt .= ' ' . $limit;
2056: return $rt;
2057: }
2058: return null;
2059: }
2060: 2061: 2062: 2063: 2064: 2065: 2066:
2067: function order($keys, $direction = 'ASC') {
2068: if (is_string($keys) && strpos($keys, ',') && !preg_match('/\(.+\,.+\)/', $keys)) {
2069: $keys = array_map('trim', explode(',', $keys));
2070: }
2071:
2072: if (is_array($keys)) {
2073: $keys = array_filter($keys);
2074: }
2075:
2076: if (empty($keys) || (is_array($keys) && isset($keys[0]) && empty($keys[0]))) {
2077: return '';
2078: }
2079:
2080: if (is_array($keys)) {
2081: $keys = (Set::countDim($keys) > 1) ? array_map(array(&$this, 'order'), $keys) : $keys;
2082:
2083: foreach ($keys as $key => $value) {
2084: if (is_numeric($key)) {
2085: $key = $value = ltrim(str_replace('ORDER BY ', '', $this->order($value)));
2086: $value = (!preg_match('/\\x20ASC|\\x20DESC/i', $key) ? ' ' . $direction : '');
2087: } else {
2088: $value = ' ' . $value;
2089: }
2090:
2091: if (!preg_match('/^.+\\(.*\\)/', $key) && !strpos($key, ',')) {
2092: if (preg_match('/\\x20ASC|\\x20DESC/i', $key, $dir)) {
2093: $dir = $dir[0];
2094: $key = preg_replace('/\\x20ASC|\\x20DESC/i', '', $key);
2095: } else {
2096: $dir = '';
2097: }
2098: $key = trim($key);
2099: if (!preg_match('/\s/', $key)) {
2100: $key = $this->name($key);
2101: }
2102: $key .= ' ' . trim($dir);
2103: }
2104: $order[] = $this->order($key . $value);
2105: }
2106: return ' ORDER BY ' . trim(str_replace('ORDER BY', '', implode(',', $order)));
2107: }
2108: $keys = preg_replace('/ORDER\\x20BY/i', '', $keys);
2109:
2110: if (strpos($keys, '.')) {
2111: preg_match_all('/([a-zA-Z0-9_-]{1,})\\.([a-zA-Z0-9_-]{1,})/', $keys, $result, PREG_PATTERN_ORDER);
2112: $pregCount = count($result[0]);
2113:
2114: for ($i = 0; $i < $pregCount; $i++) {
2115: if (!is_numeric($result[0][$i])) {
2116: $keys = preg_replace('/' . $result[0][$i] . '/', $this->name($result[0][$i]), $keys);
2117: }
2118: }
2119: $result = ' ORDER BY ' . $keys;
2120: return $result . (!preg_match('/\\x20ASC|\\x20DESC/i', $keys) ? ' ' . $direction : '');
2121:
2122: } elseif (preg_match('/(\\x20ASC|\\x20DESC)/i', $keys, $match)) {
2123: $direction = $match[1];
2124: return ' ORDER BY ' . preg_replace('/' . $match[1] . '/', '', $keys) . $direction;
2125: }
2126: return ' ORDER BY ' . $keys . ' ' . $direction;
2127: }
2128: 2129: 2130: 2131: 2132: 2133:
2134: function group($group) {
2135: if ($group) {
2136: if (is_array($group)) {
2137: $group = implode(', ', $group);
2138: }
2139: return ' GROUP BY ' . $this->__quoteFields($group);
2140: }
2141: return null;
2142: }
2143: 2144: 2145: 2146: 2147:
2148: function close() {
2149: if (Configure::read() > 1) {
2150: $this->showLog();
2151: }
2152: $this->disconnect();
2153: }
2154: 2155: 2156: 2157: 2158: 2159: 2160:
2161: function hasAny(&$Model, $sql) {
2162: $sql = $this->conditions($sql);
2163: $table = $this->fullTableName($Model);
2164: $alias = $this->alias . $this->name($Model->alias);
2165: $where = $sql ? "{$sql}" : ' WHERE 1 = 1';
2166: $id = $Model->escapeField();
2167:
2168: $out = $this->fetchRow("SELECT COUNT({$id}) {$this->alias}count FROM {$table} {$alias}{$where}");
2169:
2170: if (is_array($out)) {
2171: return $out[0]['count'];
2172: }
2173: return false;
2174: }
2175: 2176: 2177: 2178: 2179: 2180:
2181: function length($real) {
2182: if (!preg_match_all('/([\w\s]+)(?:\((\d+)(?:,(\d+))?\))?(\sunsigned)?(\szerofill)?/', $real, $result)) {
2183: trigger_error(__('FIXME: Can\'t parse field: ' . $real, true), E_USER_WARNING);
2184: $col = str_replace(array(')', 'unsigned'), '', $real);
2185: $limit = null;
2186:
2187: if (strpos($col, '(') !== false) {
2188: list($col, $limit) = explode('(', $col);
2189: }
2190: if ($limit != null) {
2191: return intval($limit);
2192: }
2193: return null;
2194: }
2195:
2196: $types = array(
2197: 'int' => 1, 'tinyint' => 1, 'smallint' => 1, 'mediumint' => 1, 'integer' => 1, 'bigint' => 1
2198: );
2199:
2200: list($real, $type, $length, $offset, $sign, $zerofill) = $result;
2201: $typeArr = $type;
2202: $type = $type[0];
2203: $length = $length[0];
2204: $offset = $offset[0];
2205:
2206: $isFloat = in_array($type, array('dec', 'decimal', 'float', 'numeric', 'double'));
2207: if ($isFloat && $offset) {
2208: return $length.','.$offset;
2209: }
2210:
2211: if (($real[0] == $type) && (count($real) == 1)) {
2212: return null;
2213: }
2214:
2215: if (isset($types[$type])) {
2216: $length += $types[$type];
2217: if (!empty($sign)) {
2218: $length--;
2219: }
2220: } elseif (in_array($type, array('enum', 'set'))) {
2221: $length = 0;
2222: foreach ($typeArr as $key => $enumValue) {
2223: if ($key == 0) {
2224: continue;
2225: }
2226: $tmpLength = strlen($enumValue);
2227: if ($tmpLength > $length) {
2228: $length = $tmpLength;
2229: }
2230: }
2231: }
2232: return intval($length);
2233: }
2234: 2235: 2236: 2237: 2238: 2239:
2240: function boolean($data) {
2241: if ($data === true || $data === false) {
2242: if ($data === true) {
2243: return 1;
2244: }
2245: return 0;
2246: } else {
2247: return !empty($data);
2248: }
2249: }
2250: 2251: 2252: 2253: 2254: 2255: 2256: 2257:
2258: function insertMulti($table, $fields, $values) {
2259: $table = $this->fullTableName($table);
2260: if (is_array($fields)) {
2261: $fields = implode(', ', array_map(array(&$this, 'name'), $fields));
2262: }
2263: $count = count($values);
2264: for ($x = 0; $x < $count; $x++) {
2265: $this->query("INSERT INTO {$table} ({$fields}) VALUES {$values[$x]}");
2266: }
2267: }
2268: 2269: 2270: 2271: 2272: 2273:
2274: function index($model) {
2275: return false;
2276: }
2277: 2278: 2279: 2280: 2281: 2282: 2283: 2284:
2285: function createSchema($schema, $tableName = null) {
2286: if (!is_a($schema, 'CakeSchema')) {
2287: trigger_error(__('Invalid schema object', true), E_USER_WARNING);
2288: return null;
2289: }
2290: $out = '';
2291:
2292: foreach ($schema->tables as $curTable => $columns) {
2293: if (!$tableName || $tableName == $curTable) {
2294: $cols = $colList = $indexes = array();
2295: $primary = null;
2296: $table = $this->fullTableName($curTable);
2297:
2298: foreach ($columns as $name => $col) {
2299: if (is_string($col)) {
2300: $col = array('type' => $col);
2301: }
2302: if (isset($col['key']) && $col['key'] == 'primary') {
2303: $primary = $name;
2304: }
2305: if ($name !== 'indexes') {
2306: $col['name'] = $name;
2307: if (!isset($col['type'])) {
2308: $col['type'] = 'string';
2309: }
2310: $cols[] = $this->buildColumn($col);
2311: } else {
2312: $indexes = array_merge($indexes, $this->buildIndex($col, $table));
2313: }
2314: }
2315: if (empty($indexes) && !empty($primary)) {
2316: $col = array('PRIMARY' => array('column' => $primary, 'unique' => 1));
2317: $indexes = array_merge($indexes, $this->buildIndex($col, $table));
2318: }
2319: $columns = $cols;
2320: $out .= $this->renderStatement('schema', compact('table', 'columns', 'indexes')) . "\n\n";
2321: }
2322: }
2323: return $out;
2324: }
2325: 2326: 2327: 2328: 2329: 2330:
2331: function alterSchema($compare, $table = null) {
2332: return false;
2333: }
2334: 2335: 2336: 2337: 2338: 2339: 2340: 2341:
2342: function dropSchema($schema, $table = null) {
2343: if (!is_a($schema, 'CakeSchema')) {
2344: trigger_error(__('Invalid schema object', true), E_USER_WARNING);
2345: return null;
2346: }
2347: $out = '';
2348:
2349: foreach ($schema->tables as $curTable => $columns) {
2350: if (!$table || $table == $curTable) {
2351: $out .= 'DROP TABLE ' . $this->fullTableName($curTable) . ";\n";
2352: }
2353: }
2354: return $out;
2355: }
2356: 2357: 2358: 2359: 2360: 2361: 2362:
2363: function buildColumn($column) {
2364: $name = $type = null;
2365: extract(array_merge(array('null' => true), $column));
2366:
2367: if (empty($name) || empty($type)) {
2368: trigger_error('Column name or type not defined in schema', E_USER_WARNING);
2369: return null;
2370: }
2371:
2372: if (!isset($this->columns[$type])) {
2373: trigger_error("Column type {$type} does not exist", E_USER_WARNING);
2374: return null;
2375: }
2376:
2377: $real = $this->columns[$type];
2378: $out = $this->name($name) . ' ' . $real['name'];
2379:
2380: if (isset($real['limit']) || isset($real['length']) || isset($column['limit']) || isset($column['length'])) {
2381: if (isset($column['length'])) {
2382: $length = $column['length'];
2383: } elseif (isset($column['limit'])) {
2384: $length = $column['limit'];
2385: } elseif (isset($real['length'])) {
2386: $length = $real['length'];
2387: } else {
2388: $length = $real['limit'];
2389: }
2390: $out .= '(' . $length . ')';
2391: }
2392:
2393: if (($column['type'] == 'integer' || $column['type'] == 'float' ) && isset($column['default']) && $column['default'] === '') {
2394: $column['default'] = null;
2395: }
2396:
2397: if (isset($column['key']) && $column['key'] == 'primary' && $type == 'integer') {
2398: $out .= ' ' . $this->columns['primary_key']['name'];
2399: } elseif (isset($column['key']) && $column['key'] == 'primary') {
2400: $out .= ' NOT NULL';
2401: } elseif (isset($column['default']) && isset($column['null']) && $column['null'] == false) {
2402: $out .= ' DEFAULT ' . $this->value($column['default'], $type) . ' NOT NULL';
2403: } elseif (isset($column['default'])) {
2404: $out .= ' DEFAULT ' . $this->value($column['default'], $type);
2405: } elseif (isset($column['null']) && $column['null'] == true) {
2406: $out .= ' DEFAULT NULL';
2407: } elseif (isset($column['null']) && $column['null'] == false) {
2408: $out .= ' NOT NULL';
2409: }
2410: return $out;
2411: }
2412: 2413: 2414: 2415: 2416: 2417: 2418:
2419: function buildIndex($indexes, $table = null) {
2420: $join = array();
2421: foreach ($indexes as $name => $value) {
2422: $out = '';
2423: if ($name == 'PRIMARY') {
2424: $out .= 'PRIMARY ';
2425: $name = null;
2426: } else {
2427: if (!empty($value['unique'])) {
2428: $out .= 'UNIQUE ';
2429: }
2430: $name = $this->startQuote . $name . $this->endQuote;
2431: }
2432: if (is_array($value['column'])) {
2433: $out .= 'KEY ' . $name . ' (' . implode(', ', array_map(array(&$this, 'name'), $value['column'])) . ')';
2434: } else {
2435: $out .= 'KEY ' . $name . ' (' . $this->name($value['column']) . ')';
2436: }
2437: $join[] = $out;
2438: }
2439: return $join;
2440: }
2441: 2442: 2443: 2444: 2445: 2446: 2447:
2448: function introspectType($value) {
2449: if (!is_array($value)) {
2450: if ($value === true || $value === false) {
2451: return 'boolean';
2452: }
2453: if (is_float($value) && floatval($value) === $value) {
2454: return 'float';
2455: }
2456: if (is_int($value) && intval($value) === $value) {
2457: return 'integer';
2458: }
2459: if (is_string($value) && strlen($value) > 255) {
2460: return 'text';
2461: }
2462: return 'string';
2463: }
2464:
2465: $isAllFloat = $isAllInt = true;
2466: $containsFloat = $containsInt = $containsString = false;
2467: foreach ($value as $key => $valElement) {
2468: $valElement = trim($valElement);
2469: if (!is_float($valElement) && !preg_match('/^[\d]+\.[\d]+$/', $valElement)) {
2470: $isAllFloat = false;
2471: } else {
2472: $containsFloat = true;
2473: continue;
2474: }
2475: if (!is_int($valElement) && !preg_match('/^[\d]+$/', $valElement)) {
2476: $isAllInt = false;
2477: } else {
2478: $containsInt = true;
2479: continue;
2480: }
2481: $containsString = true;
2482: }
2483:
2484: if ($isAllFloat) {
2485: return 'float';
2486: }
2487: if ($isAllInt) {
2488: return 'integer';
2489: }
2490:
2491: if ($containsInt && !$containsString) {
2492: return 'integer';
2493: }
2494: return 'string';
2495: }
2496: }
2497: ?>
2498: