00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 App::import('Core', array('Set', 'String'));
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 class DboSource extends DataSource {
00038
00039
00040
00041
00042
00043 var $description = "Database Data Source";
00044
00045
00046
00047
00048
00049 var $index = array('PRI' => 'primary', 'MUL' => 'index', 'UNI' => 'unique');
00050
00051
00052
00053
00054
00055 var $alias = 'AS ';
00056
00057
00058
00059
00060
00061 var $fieldCache = array();
00062
00063
00064
00065
00066
00067 var $__bypass = false;
00068
00069
00070
00071
00072
00073 var $__sqlOps = array('like', 'ilike', 'or', 'not', 'in', 'between', 'regexp', 'similar to');
00074
00075
00076
00077
00078
00079
00080 var $_commands = array(
00081 'begin' => 'BEGIN',
00082 'commit' => 'COMMIT',
00083 'rollback' => 'ROLLBACK'
00084 );
00085
00086
00087
00088 function __construct($config = null, $autoConnect = true) {
00089 if (!isset($config['prefix'])) {
00090 $config['prefix'] = '';
00091 }
00092 parent::__construct($config);
00093 $this->fullDebug = Configure::read() > 1;
00094
00095 if ($autoConnect) {
00096 return $this->connect();
00097 } else {
00098 return true;
00099 }
00100 }
00101
00102
00103
00104
00105
00106
00107 function reconnect($config = null) {
00108 $this->disconnect();
00109 $this->setConfig($config);
00110 $this->_sources = null;
00111
00112 return $this->connect();
00113 }
00114
00115
00116
00117
00118
00119
00120
00121
00122 function value($data, $column = null, $read = true) {
00123 if (is_array($data) && !empty($data)) {
00124 return array_map(
00125 array(&$this, 'value'),
00126 $data, array_fill(0, count($data), $column), array_fill(0, count($data), $read)
00127 );
00128 } elseif (is_object($data) && isset($data->type)) {
00129 if ($data->type == 'identifier') {
00130 return $this->name($data->value);
00131 } elseif ($data->type == 'expression') {
00132 return $data->value;
00133 }
00134 } elseif (in_array($data, array('{$__cakeID__$}', '{$__cakeForeignKey__$}'), true)) {
00135 return $data;
00136 } else {
00137 return null;
00138 }
00139 }
00140
00141
00142
00143
00144
00145
00146 function identifier($identifier) {
00147 $obj = new stdClass();
00148 $obj->type = 'identifier';
00149 $obj->value = $identifier;
00150 return $obj;
00151 }
00152
00153
00154
00155
00156
00157
00158 function expression($expression) {
00159 $obj = new stdClass();
00160 $obj->type = 'expression';
00161 $obj->value = $expression;
00162 return $obj;
00163 }
00164
00165
00166
00167
00168
00169
00170 function rawQuery($sql) {
00171 $this->took = $this->error = $this->numRows = false;
00172 return $this->execute($sql);
00173 }
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 function execute($sql, $options = array()) {
00184 $defaults = array('stats' => true, 'log' => $this->fullDebug);
00185 $options = array_merge($defaults, $options);
00186
00187 if ($options['stats']) {
00188 $t = getMicrotime();
00189 $this->_result = $this->_execute($sql);
00190 $this->took = round((getMicrotime() - $t) * 1000, 0);
00191 $this->affected = $this->lastAffected();
00192 $this->error = $this->lastError();
00193 $this->numRows = $this->lastNumRows();
00194 }
00195
00196 if ($options['log']) {
00197 $this->logQuery($sql);
00198 }
00199
00200 if ($this->error) {
00201 $this->showQuery($sql);
00202 return false;
00203 }
00204 return $this->_result;
00205 }
00206
00207
00208
00209
00210
00211 function query() {
00212 $args = func_get_args();
00213 $fields = null;
00214 $order = null;
00215 $limit = null;
00216 $page = null;
00217 $recursive = null;
00218
00219 if (count($args) == 1) {
00220 return $this->fetchAll($args[0]);
00221
00222 } elseif (count($args) > 1 && (strpos(strtolower($args[0]), 'findby') === 0 || strpos(strtolower($args[0]), 'findallby') === 0)) {
00223 $params = $args[1];
00224
00225 if (strpos(strtolower($args[0]), 'findby') === 0) {
00226 $all = false;
00227 $field = Inflector::underscore(preg_replace('/^findBy/i', '', $args[0]));
00228 } else {
00229 $all = true;
00230 $field = Inflector::underscore(preg_replace('/^findAllBy/i', '', $args[0]));
00231 }
00232
00233 $or = (strpos($field, '_or_') !== false);
00234 if ($or) {
00235 $field = explode('_or_', $field);
00236 } else {
00237 $field = explode('_and_', $field);
00238 }
00239 $off = count($field) - 1;
00240
00241 if (isset($params[1 + $off])) {
00242 $fields = $params[1 + $off];
00243 }
00244
00245 if (isset($params[2 + $off])) {
00246 $order = $params[2 + $off];
00247 }
00248
00249 if (!array_key_exists(0, $params)) {
00250 return false;
00251 }
00252
00253 $c = 0;
00254 $conditions = array();
00255
00256 foreach ($field as $f) {
00257 $conditions[$args[2]->alias . '.' . $f] = $params[$c];
00258 $c++;
00259 }
00260
00261 if ($or) {
00262 $conditions = array('OR' => $conditions);
00263 }
00264
00265 if ($all) {
00266 if (isset($params[3 + $off])) {
00267 $limit = $params[3 + $off];
00268 }
00269
00270 if (isset($params[4 + $off])) {
00271 $page = $params[4 + $off];
00272 }
00273
00274 if (isset($params[5 + $off])) {
00275 $recursive = $params[5 + $off];
00276 }
00277 return $args[2]->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive'));
00278 } else {
00279 if (isset($params[3 + $off])) {
00280 $recursive = $params[3 + $off];
00281 }
00282 return $args[2]->find('first', compact('conditions', 'fields', 'order', 'recursive'));
00283 }
00284 } else {
00285 if (isset($args[1]) && $args[1] === true) {
00286 return $this->fetchAll($args[0], true);
00287 } else if (isset($args[1]) && !is_array($args[1]) ) {
00288 return $this->fetchAll($args[0], false);
00289 } else if (isset($args[1]) && is_array($args[1])) {
00290 $offset = 0;
00291 if (isset($args[2])) {
00292 $cache = $args[2];
00293 } else {
00294 $cache = true;
00295 }
00296 $args[1] = array_map(array(&$this, 'value'), $args[1]);
00297 return $this->fetchAll(String::insert($args[0], $args[1]), $cache);
00298 }
00299 }
00300 }
00301
00302
00303
00304
00305
00306 function fetchRow($sql = null) {
00307 if (!empty($sql) && is_string($sql) && strlen($sql) > 5) {
00308 if (!$this->execute($sql)) {
00309 return null;
00310 }
00311 }
00312
00313 if ($this->hasResult()) {
00314 $this->resultSet($this->_result);
00315 $resultRow = $this->fetchResult();
00316 return $resultRow;
00317 } else {
00318 return null;
00319 }
00320 }
00321
00322
00323
00324
00325
00326
00327
00328
00329 function fetchAll($sql, $cache = true, $modelName = null) {
00330 if ($cache && isset($this->_queryCache[$sql])) {
00331 if (preg_match('/^\s*select/i', $sql)) {
00332 return $this->_queryCache[$sql];
00333 }
00334 }
00335
00336 if ($this->execute($sql)) {
00337 $out = array();
00338
00339 $first = $this->fetchRow();
00340 if ($first != null) {
00341 $out[] = $first;
00342 }
00343 while ($this->hasResult() && $item = $this->fetchResult()) {
00344 $out[] = $item;
00345 }
00346
00347 if ($cache) {
00348 if (strpos(trim(strtolower($sql)), 'select') !== false) {
00349 $this->_queryCache[$sql] = $out;
00350 }
00351 }
00352 return $out;
00353
00354 } else {
00355 return false;
00356 }
00357 }
00358
00359
00360
00361
00362
00363
00364
00365 function field($name, $sql) {
00366 $data = $this->fetchRow($sql);
00367
00368 if (!isset($data[$name]) || empty($data[$name])) {
00369 return false;
00370 } else {
00371 return $data[$name];
00372 }
00373 }
00374
00375
00376
00377
00378
00379
00380
00381 function name($data) {
00382 if ($data == '*') {
00383 return '*';
00384 }
00385 if (is_object($data) && isset($data->type)) {
00386 return $data->value;
00387 }
00388 $array = is_array($data);
00389 $data = (array)$data;
00390 $count = count($data);
00391
00392 for ($i = 0; $i < $count; $i++) {
00393 if ($data[$i] == '*') {
00394 continue;
00395 }
00396 if (strpos($data[$i], '(') !== false && preg_match_all('/([^(]*)\((.*)\)(.*)/', $data[$i], $fields)) {
00397 $fields = Set::extract($fields, '{n}.0');
00398
00399 if (!empty($fields[1])) {
00400 if (!empty($fields[2])) {
00401 $data[$i] = $fields[1] . '(' . $this->name($fields[2]) . ')' . $fields[3];
00402 } else {
00403 $data[$i] = $fields[1] . '()' . $fields[3];
00404 }
00405 }
00406 }
00407 $data[$i] = str_replace('.', $this->endQuote . '.' . $this->startQuote, $data[$i]);
00408 $data[$i] = $this->startQuote . $data[$i] . $this->endQuote;
00409 $data[$i] = str_replace($this->startQuote . $this->startQuote, $this->startQuote, $data[$i]);
00410 $data[$i] = str_replace($this->startQuote . '(', '(', $data[$i]);
00411 $data[$i] = str_replace(')' . $this->startQuote, ')', $data[$i]);
00412
00413 if (preg_match('/\s+AS\s+/', $data[$i])) {
00414 if (preg_match('/\w+\s+AS\s+/', $data[$i])) {
00415 $quoted = $this->endQuote . ' AS ' . $this->startQuote;
00416 $data[$i] = str_replace(' AS ', $quoted, $data[$i]);
00417 } else {
00418 $quoted = ' AS ' . $this->startQuote;
00419 $data[$i] = str_replace(' AS ', $quoted, $data[$i]) . $this->endQuote;
00420 }
00421 }
00422
00423 if (!empty($this->endQuote) && $this->endQuote == $this->startQuote) {
00424 if (substr_count($data[$i], $this->endQuote) % 2 == 1) {
00425 if (substr($data[$i], -2) == $this->endQuote . $this->endQuote) {
00426 $data[$i] = substr($data[$i], 0, -1);
00427 } else {
00428 $data[$i] = trim($data[$i], $this->endQuote);
00429 }
00430 }
00431 }
00432 if (strpos($data[$i], '*')) {
00433 $data[$i] = str_replace($this->endQuote . '*' . $this->endQuote, '*', $data[$i]);
00434 }
00435 $data[$i] = str_replace($this->endQuote . $this->endQuote, $this->endQuote, $data[$i]);
00436 }
00437 return (!$array) ? $data[0] : $data;
00438 }
00439
00440
00441
00442
00443
00444 function isConnected() {
00445 return $this->connected;
00446 }
00447
00448
00449
00450
00451
00452 function hasResult() {
00453 return is_resource($this->_result);
00454 }
00455
00456
00457
00458
00459
00460 function showLog($sorted = false) {
00461 if ($sorted) {
00462 $log = sortByKey($this->_queriesLog, 'took', 'desc', SORT_NUMERIC);
00463 } else {
00464 $log = $this->_queriesLog;
00465 }
00466
00467 if ($this->_queriesCnt > 1) {
00468 $text = 'queries';
00469 } else {
00470 $text = 'query';
00471 }
00472
00473 if (PHP_SAPI != 'cli') {
00474 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");
00475 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");
00476
00477 foreach ($log as $k => $i) {
00478 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");
00479 }
00480 print ("</tbody></table>\n");
00481 } else {
00482 foreach ($log as $k => $i) {
00483 print (($k + 1) . ". {$i['query']} {$i['error']}\n");
00484 }
00485 }
00486 }
00487
00488
00489
00490
00491
00492
00493 function logQuery($sql) {
00494 $this->_queriesCnt++;
00495 $this->_queriesTime += $this->took;
00496 $this->_queriesLog[] = array(
00497 'query' => $sql,
00498 'error' => $this->error,
00499 'affected' => $this->affected,
00500 'numRows' => $this->numRows,
00501 'took' => $this->took
00502 );
00503 if (count($this->_queriesLog) > $this->_queriesLogMax) {
00504 array_pop($this->_queriesLog);
00505 }
00506 if ($this->error) {
00507 return false;
00508 }
00509 }
00510
00511
00512
00513
00514
00515
00516 function showQuery($sql) {
00517 $error = $this->error;
00518 if (strlen($sql) > 200 && !$this->fullDebug && Configure::read() > 1) {
00519 $sql = substr($sql, 0, 200) . '[...]';
00520 }
00521 if (Configure::read() > 0) {
00522 $out = null;
00523 if ($error) {
00524 trigger_error("<span style = \"color:Red;text-align:left\"><b>SQL Error:</b> {$this->error}</span>", E_USER_WARNING);
00525 } else {
00526 $out = ("<small>[Aff:{$this->affected} Num:{$this->numRows} Took:{$this->took}ms]</small>");
00527 }
00528 pr(sprintf("<p style = \"text-align:left\"><b>Query:</b> %s %s</p>", $sql, $out));
00529 }
00530 }
00531
00532
00533
00534
00535
00536
00537
00538 function fullTableName($model, $quote = true) {
00539 if (is_object($model)) {
00540 $table = $model->tablePrefix . $model->table;
00541 } elseif (isset($this->config['prefix'])) {
00542 $table = $this->config['prefix'] . strval($model);
00543 } else {
00544 $table = strval($model);
00545 }
00546 if ($quote) {
00547 return $this->name($table);
00548 }
00549 return $table;
00550 }
00551
00552
00553
00554
00555
00556
00557
00558
00559 function create(&$model, $fields = null, $values = null) {
00560 $id = null;
00561
00562 if ($fields == null) {
00563 unset($fields, $values);
00564 $fields = array_keys($model->data);
00565 $values = array_values($model->data);
00566 }
00567 $count = count($fields);
00568
00569 for ($i = 0; $i < $count; $i++) {
00570 $valueInsert[] = $this->value($values[$i], $model->getColumnType($fields[$i]), false);
00571 }
00572 for ($i = 0; $i < $count; $i++) {
00573 $fieldInsert[] = $this->name($fields[$i]);
00574 if ($fields[$i] == $model->primaryKey) {
00575 $id = $values[$i];
00576 }
00577 }
00578 $query = array(
00579 'table' => $this->fullTableName($model),
00580 'fields' => join(', ', $fieldInsert),
00581 'values' => join(', ', $valueInsert)
00582 );
00583
00584 if ($this->execute($this->renderStatement('create', $query))) {
00585 if (empty($id)) {
00586 $id = $this->lastInsertId($this->fullTableName($model, false), $model->primaryKey);
00587 }
00588 $model->setInsertID($id);
00589 $model->id = $id;
00590 return true;
00591 } else {
00592 $model->onError();
00593 return false;
00594 }
00595 }
00596
00597
00598
00599
00600
00601
00602
00603
00604 function read(&$model, $queryData = array(), $recursive = null) {
00605 $queryData = $this->__scrubQueryData($queryData);
00606
00607 $null = null;
00608 $array = array();
00609 $linkedModels = array();
00610 $this->__bypass = false;
00611 $this->__booleans = array();
00612
00613 if ($recursive === null && isset($queryData['recursive'])) {
00614 $recursive = $queryData['recursive'];
00615 }
00616
00617 if (!is_null($recursive)) {
00618 $_recursive = $model->recursive;
00619 $model->recursive = $recursive;
00620 }
00621
00622 if (!empty($queryData['fields'])) {
00623 $this->__bypass = true;
00624 $queryData['fields'] = $this->fields($model, null, $queryData['fields']);
00625 } else {
00626 $queryData['fields'] = $this->fields($model);
00627 }
00628
00629 $_associations = $model->__associations;
00630
00631 if ($model->recursive == -1) {
00632 $_associations = array();
00633 } else if ($model->recursive == 0) {
00634 unset($_associations[2], $_associations[3]);
00635 }
00636
00637 foreach ($_associations as $type) {
00638 foreach ($model->{$type} as $assoc => $assocData) {
00639 $linkModel =& $model->{$assoc};
00640 $external = isset($assocData['external']);
00641
00642 if ($model->useDbConfig == $linkModel->useDbConfig) {
00643 if (true === $this->generateAssociationQuery($model, $linkModel, $type, $assoc, $assocData, $queryData, $external, $null)) {
00644 $linkedModels[$type . '/' . $assoc] = true;
00645 }
00646 }
00647 }
00648 }
00649
00650 $query = $this->generateAssociationQuery($model, $null, null, null, null, $queryData, false, $null);
00651
00652 $resultSet = $this->fetchAll($query, $model->cacheQueries, $model->alias);
00653
00654 if ($resultSet === false) {
00655 $model->onError();
00656 return false;
00657 }
00658
00659 $filtered = $this->__filterResults($resultSet, $model);
00660
00661 if ($model->recursive > -1) {
00662 foreach ($_associations as $type) {
00663 foreach ($model->{$type} as $assoc => $assocData) {
00664 $linkModel =& $model->{$assoc};
00665
00666 if (empty($linkedModels[$type . '/' . $assoc])) {
00667 if ($model->useDbConfig == $linkModel->useDbConfig) {
00668 $db =& $this;
00669 } else {
00670 $db =& ConnectionManager::getDataSource($linkModel->useDbConfig);
00671 }
00672 } elseif ($model->recursive > 1 && ($type == 'belongsTo' || $type == 'hasOne')) {
00673 $db =& $this;
00674 }
00675
00676 if (isset($db)) {
00677 $stack = array($assoc);
00678 $db->queryAssociation($model, $linkModel, $type, $assoc, $assocData, $array, true, $resultSet, $model->recursive - 1, $stack);
00679 unset($db);
00680 }
00681 }
00682 }
00683 $this->__filterResults($resultSet, $model, $filtered);
00684 }
00685
00686 if (!is_null($recursive)) {
00687 $model->recursive = $_recursive;
00688 }
00689 return $resultSet;
00690 }
00691
00692
00693
00694
00695
00696
00697
00698
00699 function __filterResults(&$results, &$model, $filtered = array()) {
00700 $filtering = array();
00701 $count = count($results);
00702
00703 for ($i = 0; $i < $count; $i++) {
00704 if (is_array($results[$i])) {
00705 $classNames = array_keys($results[$i]);
00706 $count2 = count($classNames);
00707
00708 for ($j = 0; $j < $count2; $j++) {
00709 $className = $classNames[$j];
00710 if ($model->alias != $className && !in_array($className, $filtered)) {
00711 if (!in_array($className, $filtering)) {
00712 $filtering[] = $className;
00713 }
00714
00715 if (isset($model->{$className}) && is_object($model->{$className})) {
00716 $data = $model->{$className}->afterFind(array(array($className => $results[$i][$className])), false);
00717 }
00718 if (isset($data[0][$className])) {
00719 $results[$i][$className] = $data[0][$className];
00720 }
00721 }
00722 }
00723 }
00724 }
00725 return $filtering;
00726 }
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741 function queryAssociation(&$model, &$linkModel, $type, $association, $assocData, &$queryData, $external = false, &$resultSet, $recursive, $stack) {
00742 if ($query = $this->generateAssociationQuery($model, $linkModel, $type, $association, $assocData, $queryData, $external, $resultSet)) {
00743 if (!isset($resultSet) || !is_array($resultSet)) {
00744 if (Configure::read() > 0) {
00745 echo '<div style = "font: Verdana bold 12px; color: #FF0000">' . sprintf(__('SQL Error in model %s:', true), $model->alias) . ' ';
00746 if (isset($this->error) && $this->error != null) {
00747 echo $this->error;
00748 }
00749 echo '</div>';
00750 }
00751 return null;
00752 }
00753 $count = count($resultSet);
00754
00755 if ($type === 'hasMany' && empty($assocData['limit']) && !empty($assocData['foreignKey'])) {
00756 $ins = $fetch = array();
00757 for ($i = 0; $i < $count; $i++) {
00758 if ($in = $this->insertQueryData('{$__cakeID__$}', $resultSet[$i], $association, $assocData, $model, $linkModel, $stack)) {
00759 $ins[] = $in;
00760 }
00761 }
00762
00763 if (!empty($ins)) {
00764 $fetch = $this->fetchAssociated($model, $query, $ins);
00765 }
00766
00767 if (!empty($fetch) && is_array($fetch)) {
00768 if ($recursive > 0) {
00769 foreach ($linkModel->__associations as $type1) {
00770 foreach ($linkModel->{$type1} as $assoc1 => $assocData1) {
00771 $deepModel =& $linkModel->{$assoc1};
00772 $tmpStack = $stack;
00773 $tmpStack[] = $assoc1;
00774
00775 if ($linkModel->useDbConfig === $deepModel->useDbConfig) {
00776 $db =& $this;
00777 } else {
00778 $db =& ConnectionManager::getDataSource($deepModel->useDbConfig);
00779 }
00780 $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack);
00781 }
00782 }
00783 }
00784 }
00785 $this->__filterResults($fetch, $model);
00786 return $this->__mergeHasMany($resultSet, $fetch, $association, $model, $linkModel, $recursive);
00787 } elseif ($type === 'hasAndBelongsToMany') {
00788 $ins = $fetch = array();
00789 for ($i = 0; $i < $count; $i++) {
00790 if ($in = $this->insertQueryData('{$__cakeID__$}', $resultSet[$i], $association, $assocData, $model, $linkModel, $stack)) {
00791 $ins[] = $in;
00792 }
00793 }
00794 if (!empty($ins)) {
00795 if (count($ins) > 1) {
00796 $query = str_replace('{$__cakeID__$}', '(' .join(', ', $ins) .')', $query);
00797 $query = str_replace('= (', 'IN (', $query);
00798 $query = str_replace('= (', 'IN (', $query);
00799 } else {
00800 $query = str_replace('{$__cakeID__$}',$ins[0], $query);
00801 }
00802
00803 $query = str_replace(' WHERE 1 = 1', '', $query);
00804 }
00805
00806 $foreignKey = $model->hasAndBelongsToMany[$association]['foreignKey'];
00807 $joinKeys = array($foreignKey, $model->hasAndBelongsToMany[$association]['associationForeignKey']);
00808 list($with, $habtmFields) = $model->joinModel($model->hasAndBelongsToMany[$association]['with'], $joinKeys);
00809 $habtmFieldsCount = count($habtmFields);
00810 $q = $this->insertQueryData($query, null, $association, $assocData, $model, $linkModel, $stack);
00811
00812 if ($q != false) {
00813 $fetch = $this->fetchAll($q, $model->cacheQueries, $model->alias);
00814 } else {
00815 $fetch = null;
00816 }
00817 }
00818
00819 for ($i = 0; $i < $count; $i++) {
00820 $row =& $resultSet[$i];
00821
00822 if ($type !== 'hasAndBelongsToMany') {
00823 $q = $this->insertQueryData($query, $resultSet[$i], $association, $assocData, $model, $linkModel, $stack);
00824 if ($q != false) {
00825 $fetch = $this->fetchAll($q, $model->cacheQueries, $model->alias);
00826 } else {
00827 $fetch = null;
00828 }
00829 }
00830 $selfJoin = false;
00831
00832 if ($linkModel->name === $model->name) {
00833 $selfJoin = true;
00834 }
00835
00836 if (!empty($fetch) && is_array($fetch)) {
00837 if ($recursive > 0) {
00838 foreach ($linkModel->__associations as $type1) {
00839 foreach ($linkModel->{$type1} as $assoc1 => $assocData1) {
00840 $deepModel =& $linkModel->{$assoc1};
00841
00842 if (($type1 === 'belongsTo') || ($deepModel->alias === $model->alias && $type === 'belongsTo') || ($deepModel->alias != $model->alias)) {
00843 $tmpStack = $stack;
00844 $tmpStack[] = $assoc1;
00845 if ($linkModel->useDbConfig == $deepModel->useDbConfig) {
00846 $db =& $this;
00847 } else {
00848 $db =& ConnectionManager::getDataSource($deepModel->useDbConfig);
00849 }
00850 $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack);
00851 }
00852 }
00853 }
00854 }
00855 if ($type == 'hasAndBelongsToMany') {
00856 $uniqueIds = $merge = array();
00857
00858 foreach ($fetch as $j => $data) {
00859 if (
00860 (isset($data[$with]) && $data[$with][$foreignKey] === $row[$model->alias][$model->primaryKey])
00861 ) {
00862 if ($habtmFieldsCount <= 2) {
00863 unset($data[$with]);
00864 }
00865 $merge[] = $data;
00866 }
00867 }
00868 if (empty($merge) && !isset($row[$association])) {
00869 $row[$association] = $merge;
00870 } else {
00871 $this->__mergeAssociation($resultSet[$i], $merge, $association, $type);
00872 }
00873 } else {
00874 $this->__mergeAssociation($resultSet[$i], $fetch, $association, $type, $selfJoin);
00875 }
00876 if (isset($resultSet[$i][$association])) {
00877 $resultSet[$i][$association] = $linkModel->afterFind($resultSet[$i][$association]);
00878 }
00879 } else {
00880 $tempArray[0][$association] = false;
00881 $this->__mergeAssociation($resultSet[$i], $tempArray, $association, $type, $selfJoin);
00882 }
00883 }
00884 }
00885 }
00886
00887
00888
00889
00890
00891
00892
00893
00894 function fetchAssociated($model, $query, $ids) {
00895 $query = str_replace('{$__cakeID__$}', join(', ', $ids), $query);
00896 if (count($ids) > 1) {
00897 $query = str_replace('= (', 'IN (', $query);
00898 $query = str_replace('= (', 'IN (', $query);
00899 }
00900 return $this->fetchAll($query, $model->cacheQueries, $model->alias);
00901 }
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913 function __mergeHasMany(&$resultSet, $merge, $association, &$model, &$linkModel) {
00914 foreach ($resultSet as $i => $value) {
00915 $count = 0;
00916 $merged[$association] = array();
00917 foreach ($merge as $j => $data) {
00918 if (isset($value[$model->alias]) && $value[$model->alias][$model->primaryKey] === $data[$association][$model->hasMany[$association]['foreignKey']]) {
00919 if (count($data) > 1) {
00920 $data = array_merge($data[$association], $data);
00921 unset($data[$association]);
00922 foreach ($data as $key => $name) {
00923 if (is_numeric($key)) {
00924 $data[$association][] = $name;
00925 unset($data[$key]);
00926 }
00927 }
00928 $merged[$association][] = $data;
00929 } else {
00930 $merged[$association][] = $data[$association];
00931 }
00932 }
00933 $count++;
00934 }
00935 if (isset($value[$model->alias])) {
00936 $resultSet[$i] = Set::pushDiff($resultSet[$i], $merged);
00937 unset($merged);
00938 }
00939 }
00940 }
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950 function __mergeAssociation(&$data, $merge, $association, $type, $selfJoin = false) {
00951 if (isset($merge[0]) && !isset($merge[0][$association])) {
00952 $association = Inflector::pluralize($association);
00953 }
00954
00955 if ($type == 'belongsTo' || $type == 'hasOne') {
00956 if (isset($merge[$association])) {
00957 $data[$association] = $merge[$association][0];
00958 } else {
00959 if (count($merge[0][$association]) > 1) {
00960 foreach ($merge[0] as $assoc => $data2) {
00961 if ($assoc != $association) {
00962 $merge[0][$association][$assoc] = $data2;
00963 }
00964 }
00965 }
00966 if (!isset($data[$association])) {
00967 if ($merge[0][$association] != null) {
00968 $data[$association] = $merge[0][$association];
00969 } else {
00970 $data[$association] = array();
00971 }
00972 } else {
00973 if (is_array($merge[0][$association])) {
00974 foreach ($data[$association] as $k => $v) {
00975 if (!is_array($v)) {
00976 $dataAssocTmp[$k] = $v;
00977 }
00978 }
00979
00980 foreach ($merge[0][$association] as $k => $v) {
00981 if (!is_array($v)) {
00982 $mergeAssocTmp[$k] = $v;
00983 }
00984 }
00985 $dataKeys = array_keys($data);
00986 $mergeKeys = array_keys($merge[0]);
00987
00988 if ($mergeKeys[0] === $dataKeys[0] || $mergeKeys === $dataKeys) {
00989 $data[$association][$association] = $merge[0][$association];
00990 } else {
00991 $diff = Set::diff($dataAssocTmp, $mergeAssocTmp);
00992 $data[$association] = array_merge($merge[0][$association], $diff);
00993 }
00994 } elseif ($selfJoin && array_key_exists($association, $merge[0])) {
00995 $data[$association] = array_merge($data[$association], array($association => array()));
00996 }
00997 }
00998 }
00999 } else {
01000 if (isset($merge[0][$association]) && $merge[0][$association] === false) {
01001 if (!isset($data[$association])) {
01002 $data[$association] = array();
01003 }
01004 } else {
01005 foreach ($merge as $i => $row) {
01006 if (count($row) == 1) {
01007 if (empty($data[$association]) || (isset($data[$association]) && !in_array($row[$association], $data[$association]))) {
01008 $data[$association][] = $row[$association];
01009 }
01010 } else if (!empty($row)) {
01011 $tmp = array_merge($row[$association], $row);
01012 unset($tmp[$association]);
01013 $data[$association][] = $tmp;
01014 }
01015 }
01016 }
01017 }
01018 }
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032 function generateAssociationQuery(&$model, &$linkModel, $type, $association = null, $assocData = array(), &$queryData, $external = false, &$resultSet) {
01033 $queryData = $this->__scrubQueryData($queryData);
01034 $assocData = $this->__scrubQueryData($assocData);
01035
01036 if (empty($queryData['fields'])) {
01037 $queryData['fields'] = $this->fields($model, $model->alias);
01038 } elseif (!empty($model->hasMany) && $model->recursive > -1) {
01039 $assocFields = $this->fields($model, $model->alias, array("{$model->alias}.{$model->primaryKey}"));
01040 $passedFields = $this->fields($model, $model->alias, $queryData['fields']);
01041
01042 if (count($passedFields) === 1) {
01043 $match = strpos($passedFields[0], $assocFields[0]);
01044 $match1 = strpos($passedFields[0], 'COUNT(');
01045 if ($match === false && $match1 === false) {
01046 $queryData['fields'] = array_merge($passedFields, $assocFields);
01047 } else {
01048 $queryData['fields'] = $passedFields;
01049 }
01050 } else {
01051 $queryData['fields'] = array_merge($passedFields, $assocFields);
01052 }
01053 unset($assocFields, $passedFields);
01054 }
01055
01056 if ($linkModel == null) {
01057 return $this->buildStatement(
01058 array(
01059 'fields' => array_unique($queryData['fields']),
01060 'table' => $this->fullTableName($model),
01061 'alias' => $model->alias,
01062 'limit' => $queryData['limit'],
01063 'offset' => $queryData['offset'],
01064 'joins' => $queryData['joins'],
01065 'conditions' => $queryData['conditions'],
01066 'order' => $queryData['order'],
01067 'group' => $queryData['group']
01068 ),
01069 $model
01070 );
01071 }
01072 if ($external && !empty($assocData['finderQuery'])) {
01073 return $assocData['finderQuery'];
01074 }
01075
01076 $alias = $association;
01077 $self = ($model->name == $linkModel->name);
01078 $fields = array();
01079
01080 if ((!$external && in_array($type, array('hasOne', 'belongsTo')) && $this->__bypass === false) || $external) {
01081 $fields = $this->fields($linkModel, $alias, $assocData['fields']);
01082 }
01083 if (empty($assocData['offset']) && !empty($assocData['page'])) {
01084 $assocData['offset'] = ($assocData['page'] - 1) * $assocData['limit'];
01085 }
01086 $assocData['limit'] = $this->limit($assocData['limit'], $assocData['offset']);
01087
01088 switch ($type) {
01089 case 'hasOne':
01090 case 'belongsTo':
01091 $conditions = $this->__mergeConditions(
01092 $assocData['conditions'],
01093 $this->getConstraint($type, $model, $linkModel, $alias, array_merge($assocData, compact('external', 'self')))
01094 );
01095
01096 if (!$self && $external) {
01097 foreach ($conditions as $key => $condition) {
01098 if (is_numeric($key) && strpos($condition, $model->alias . '.') !== false) {
01099 unset($conditions[$key]);
01100 }
01101 }
01102 }
01103
01104 if ($external) {
01105 $query = array_merge($assocData, array(
01106 'conditions' => $conditions,
01107 'table' => $this->fullTableName($linkModel),
01108 'fields' => $fields,
01109 'alias' => $alias,
01110 'group' => null
01111 ));
01112 $query = array_merge(array('order' => $assocData['order'], 'limit' => $assocData['limit']), $query);
01113 } else {
01114 $join = array(
01115 'table' => $this->fullTableName($linkModel),
01116 'alias' => $alias,
01117 'type' => isset($assocData['type']) ? $assocData['type'] : 'LEFT',
01118 'conditions' => trim($this->conditions($conditions, true, false, $model))
01119 );
01120 $queryData['fields'] = array_merge($queryData['fields'], $fields);
01121
01122 if (!empty($assocData['order'])) {
01123 $queryData['order'][] = $assocData['order'];
01124 }
01125 if (!in_array($join, $queryData['joins'])) {
01126 $queryData['joins'][] = $join;
01127 }
01128 return true;
01129 }
01130 break;
01131 case 'hasMany':
01132 $assocData['fields'] = $this->fields($linkModel, $alias, $assocData['fields']);
01133 if (!empty($assocData['foreignKey'])) {
01134 $assocData['fields'] = array_merge($assocData['fields'], $this->fields($linkModel, $alias, array("{$alias}.{$assocData['foreignKey']}")));
01135 }
01136 $query = array(
01137 'conditions' => $this->__mergeConditions($this->getConstraint('hasMany', $model, $linkModel, $alias, $assocData), $assocData['conditions']),
01138 'fields' => array_unique($assocData['fields']),
01139 'table' => $this->fullTableName($linkModel),
01140 'alias' => $alias,
01141 'order' => $assocData['order'],
01142 'limit' => $assocData['limit'],
01143 'group' => null
01144 );
01145 break;
01146 case 'hasAndBelongsToMany':
01147 $joinFields = array();
01148 $joinAssoc = null;
01149
01150 if (isset($assocData['with']) && !empty($assocData['with'])) {
01151 $joinKeys = array($assocData['foreignKey'], $assocData['associationForeignKey']);
01152 list($with, $joinFields) = $model->joinModel($assocData['with'], $joinKeys);
01153
01154 $joinTbl = $this->fullTableName($model->{$with});
01155 $joinAlias = $joinTbl;
01156
01157 if (is_array($joinFields) && !empty($joinFields)) {
01158 $joinFields = $this->fields($model->{$with}, $model->{$with}->alias, $joinFields);
01159 $joinAssoc = $joinAlias = $model->{$with}->alias;
01160 } else {
01161 $joinFields = array();
01162 }
01163 } else {
01164 $joinTbl = $this->fullTableName($assocData['joinTable']);
01165 $joinAlias = $joinTbl;
01166 }
01167 $query = array(
01168 'conditions' => $assocData['conditions'],
01169 'limit' => $assocData['limit'],
01170 'table' => $this->fullTableName($linkModel),
01171 'alias' => $alias,
01172 'fields' => array_merge($this->fields($linkModel, $alias, $assocData['fields']), $joinFields),
01173 'order' => $assocData['order'],
01174 'group' => null,
01175 'joins' => array(array(
01176 'table' => $joinTbl,
01177 'alias' => $joinAssoc,
01178 'conditions' => $this->getConstraint('hasAndBelongsToMany', $model, $linkModel, $joinAlias, $assocData, $alias)
01179 ))
01180 );
01181 break;
01182 }
01183 if (isset($query)) {
01184 return $this->buildStatement($query, $model);
01185 }
01186 return null;
01187 }
01188
01189
01190
01191
01192
01193
01194
01195
01196 function getConstraint($type, $model, $linkModel, $alias, $assoc, $alias2 = null) {
01197 $assoc = array_merge(array('external' => false, 'self' => false), $assoc);
01198
01199 if (array_key_exists('foreignKey', $assoc) && empty($assoc['foreignKey'])) {
01200 return array();
01201 }
01202
01203 switch (true) {
01204 case ($assoc['external'] && $type == 'hasOne'):
01205 return array("{$alias}.{$assoc['foreignKey']}" => '{$__cakeID__$}');
01206 break;
01207 case ($assoc['external'] && $type == 'belongsTo'):
01208 return array("{$alias}.{$linkModel->primaryKey}" => '{$__cakeForeignKey__$}');
01209 break;
01210 case (!$assoc['external'] && $type == 'hasOne'):
01211 return array("{$alias}.{$assoc['foreignKey']}" => $this->identifier("{$model->alias}.{$model->primaryKey}"));
01212 break;
01213 case (!$assoc['external'] && $type == 'belongsTo'):
01214 return array("{$model->alias}.{$assoc['foreignKey']}" => $this->identifier("{$alias}.{$linkModel->primaryKey}"));
01215 break;
01216 case ($type == 'hasMany'):
01217 return array("{$alias}.{$assoc['foreignKey']}" => array('{$__cakeID__$}'));
01218 break;
01219 case ($type == 'hasAndBelongsToMany'):
01220 return array(
01221 array("{$alias}.{$assoc['foreignKey']}" => '{$__cakeID__$}'),
01222 array("{$alias}.{$assoc['associationForeignKey']}" => $this->identifier("{$alias2}.{$linkModel->primaryKey}"))
01223 );
01224 break;
01225 }
01226 return array();
01227 }
01228
01229
01230
01231
01232
01233
01234
01235
01236 function buildJoinStatement($join) {
01237 $data = array_merge(array(
01238 'type' => null,
01239 'alias' => null,
01240 'table' => 'join_table',
01241 'conditions' => array()
01242 ), $join);
01243
01244 if (!empty($data['alias'])) {
01245 $data['alias'] = $this->alias . $this->name($data['alias']);
01246 }
01247 if (!empty($data['conditions'])) {
01248 $data['conditions'] = trim($this->conditions($data['conditions'], true, false));
01249 }
01250 return $this->renderJoinStatement($data);
01251 }
01252
01253
01254
01255
01256
01257
01258
01259
01260 function buildStatement($query, $model) {
01261 $query = array_merge(array('offset' => null, 'joins' => array()), $query);
01262 if (!empty($query['joins'])) {
01263 $count = count($query['joins']);
01264 for ($i = 0; $i < $count; $i++) {
01265 if (is_array($query['joins'][$i])) {
01266 $query['joins'][$i] = $this->buildJoinStatement($query['joins'][$i]);
01267 }
01268 }
01269 }
01270 return $this->renderStatement('select', array(
01271 'conditions' => $this->conditions($query['conditions'], true, true, $model),
01272 'fields' => join(', ', $query['fields']),
01273 'table' => $query['table'],
01274 'alias' => $this->alias . $this->name($query['alias']),
01275 'order' => $this->order($query['order']),
01276 'limit' => $this->limit($query['limit'], $query['offset']),
01277 'joins' => join(' ', $query['joins']),
01278 'group' => $this->group($query['group'])
01279 ));
01280 }
01281
01282
01283
01284
01285
01286
01287 function renderJoinStatement($data) {
01288 extract($data);
01289 return trim("{$type} JOIN {$table} {$alias} ON ({$conditions})");
01290 }
01291
01292
01293
01294
01295
01296
01297
01298 function renderStatement($type, $data) {
01299 extract($data);
01300 $aliases = null;
01301
01302 switch (strtolower($type)) {
01303 case 'select':
01304 return "SELECT {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order} {$limit}";
01305 break;
01306 case 'create':
01307 return "INSERT INTO {$table} ({$fields}) VALUES ({$values})";
01308 break;
01309 case 'update':
01310 if (!empty($alias)) {
01311 $aliases = "{$this->alias}{$alias} {$joins} ";
01312 }
01313 return "UPDATE {$table} {$aliases}SET {$fields} {$conditions}";
01314 break;
01315 case 'delete':
01316 if (!empty($alias)) {
01317 $aliases = "{$this->alias}{$alias} {$joins} ";
01318 }
01319 return "DELETE {$alias} FROM {$table} {$aliases}{$conditions}";
01320 break;
01321 case 'schema':
01322 foreach (array('columns', 'indexes') as $var) {
01323 if (is_array(${$var})) {
01324 ${$var} = "\t" . join(",\n\t", array_filter(${$var}));
01325 }
01326 }
01327 if (trim($indexes) != '') {
01328 $columns .= ',';
01329 }
01330 return "CREATE TABLE {$table} (\n{$columns}{$indexes});";
01331 break;
01332 case 'alter':
01333 break;
01334 }
01335 }
01336
01337
01338
01339
01340
01341 function __mergeConditions($query, $assoc) {
01342 if (empty($assoc)) {
01343 return $query;
01344 }
01345
01346 if (is_array($query)) {
01347 return array_merge((array)$assoc, $query);
01348 }
01349
01350 if (!empty($query)) {
01351 $query = array($query);
01352 if (is_array($assoc)) {
01353 $query = array_merge($query, $assoc);
01354 } else {
01355 $query[] = $assoc;
01356 }
01357 return $query;
01358 }
01359
01360 return $assoc;
01361 }
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372 function update(&$model, $fields = array(), $values = null, $conditions = null) {
01373 if ($values == null) {
01374 $combined = $fields;
01375 } else {
01376 $combined = array_combine($fields, $values);
01377 }
01378 $fields = join(', ', $this->_prepareUpdateFields($model, $combined, empty($conditions)));
01379
01380 $alias = $joins = null;
01381 $table = $this->fullTableName($model);
01382 $conditions = $this->_matchRecords($model, $conditions);
01383
01384 if ($conditions === false) {
01385 return false;
01386 }
01387 $query = compact('table', 'alias', 'joins', 'fields', 'conditions');
01388
01389 if (!$this->execute($this->renderStatement('update', $query))) {
01390 $model->onError();
01391 return false;
01392 }
01393 return true;
01394 }
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405 function _prepareUpdateFields(&$model, $fields, $quoteValues = true, $alias = false) {
01406 $quotedAlias = $this->startQuote . $model->alias . $this->endQuote;
01407
01408 $updates = array();
01409 foreach ($fields as $field => $value) {
01410 if ($alias && strpos($field, '.') === false) {
01411 $quoted = $model->escapeField($field);
01412 } elseif (!$alias && strpos($field, '.') !== false) {
01413 $quoted = $this->name(str_replace($quotedAlias . '.', '', str_replace(
01414 $model->alias . '.', '', $field
01415 )));
01416 } else {
01417 $quoted = $this->name($field);
01418 }
01419
01420 if ($value === null) {
01421 $updates[] = $quoted . ' = NULL';
01422 continue;
01423 }
01424 $update = $quoted . ' = ';
01425
01426 if ($quoteValues) {
01427 $update .= $this->value($value, $model->getColumnType($field), false);
01428 } elseif (!$alias) {
01429 $update .= str_replace($quotedAlias . '.', '', str_replace(
01430 $model->alias . '.', '', $value
01431 ));
01432 } else {
01433 $update .= $value;
01434 }
01435 $updates[] = $update;
01436 }
01437 return $updates;
01438 }
01439
01440
01441
01442
01443
01444
01445
01446
01447 function delete(&$model, $conditions = null) {
01448 $alias = $joins = null;
01449 $table = $this->fullTableName($model);
01450 $conditions = $this->_matchRecords($model, $conditions);
01451
01452 if ($conditions === false) {
01453 return false;
01454 }
01455
01456 if ($this->execute($this->renderStatement('delete', compact('alias', 'table', 'joins', 'conditions'))) === false) {
01457 $model->onError();
01458 return false;
01459 }
01460 return true;
01461 }
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471 function _matchRecords(&$model, $conditions = null) {
01472 if ($conditions === true) {
01473 $conditions = $this->conditions(true);
01474 } elseif ($conditions === null) {
01475 $conditions = $this->conditions($this->defaultConditions($model, $conditions, false), true, true, $model);
01476 } else {
01477 $idList = $model->find('all', array(
01478 'fields' => "{$model->alias}.{$model->primaryKey}",
01479 'conditions' => $conditions
01480 ));
01481
01482 if (empty($idList)) {
01483 return false;
01484 }
01485 $conditions = $this->conditions(array(
01486 $model->primaryKey => Set::extract($idList, "{n}.{$model->alias}.{$model->primaryKey}")
01487 ));
01488 }
01489 return $conditions;
01490 }
01491
01492
01493
01494
01495
01496
01497 function _getJoins($model) {
01498 $join = array();
01499 $joins = array_merge($model->getAssociated('hasOne'), $model->getAssociated('belongsTo'));
01500
01501 foreach ($joins as $assoc) {
01502 if (isset($model->{$assoc}) && $model->useDbConfig == $model->{$assoc}->useDbConfig) {
01503 $assocData = $model->getAssociated($assoc);
01504 $join[] = $this->buildJoinStatement(array(
01505 'table' => $this->fullTableName($model->{$assoc}),
01506 'alias' => $assoc,
01507 'type' => isset($assocData['type']) ? $assocData['type'] : 'LEFT',
01508 'conditions' => trim($this->conditions(
01509 $this->getConstraint($assocData['association'], $model, $model->{$assoc}, $assoc, $assocData),
01510 true, false, $model
01511 ))
01512 ));
01513 }
01514 }
01515 return $join;
01516 }
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526 function calculate(&$model, $func, $params = array()) {
01527 $params = (array)$params;
01528
01529 switch (strtolower($func)) {
01530 case 'count':
01531 if (!isset($params[0])) {
01532 $params[0] = '*';
01533 }
01534 if (!isset($params[1])) {
01535 $params[1] = 'count';
01536 }
01537 return 'COUNT(' . $this->name($params[0]) . ') AS ' . $this->name($params[1]);
01538 case 'max':
01539 case 'min':
01540 if (!isset($params[1])) {
01541 $params[1] = $params[0];
01542 }
01543 return strtoupper($func) . '(' . $this->name($params[0]) . ') AS ' . $this->name($params[1]);
01544 break;
01545 }
01546 }
01547
01548
01549
01550
01551
01552
01553
01554
01555 function truncate($table) {
01556 return $this->execute('TRUNCATE TABLE ' . $this->fullTableName($table));
01557 }
01558
01559
01560
01561
01562
01563
01564
01565
01566 function begin(&$model) {
01567 if (parent::begin($model) && $this->execute($this->_commands['begin'])) {
01568 $this->_transactionStarted = true;
01569 return true;
01570 }
01571 return false;
01572 }
01573
01574
01575
01576
01577
01578
01579
01580
01581 function commit(&$model) {
01582 if (parent::commit($model) && $this->execute($this->_commands['commit'])) {
01583 $this->_transactionStarted = false;
01584 return true;
01585 }
01586 return false;
01587 }
01588
01589
01590
01591
01592
01593
01594
01595
01596 function rollback(&$model) {
01597 if (parent::rollback($model) && $this->execute($this->_commands['rollback'])) {
01598 $this->_transactionStarted = false;
01599 return true;
01600 }
01601 return false;
01602 }
01603
01604
01605
01606
01607
01608
01609
01610
01611 function defaultConditions(&$model, $conditions, $useAlias = true) {
01612 if (!empty($conditions)) {
01613 return $conditions;
01614 }
01615 if (!$model->exists()) {
01616 return false;
01617 }
01618 $alias = $model->alias;
01619
01620 if (!$useAlias) {
01621 $alias = $this->fullTableName($model, false);
01622 }
01623 return array("{$alias}.{$model->primaryKey}" => $model->getID());
01624 }
01625
01626
01627
01628
01629
01630
01631
01632
01633 function resolveKey($model, $key, $assoc = null) {
01634 if (empty($assoc)) {
01635 $assoc = $model->alias;
01636 }
01637 if (!strpos('.', $key)) {
01638 return $this->name($model->alias) . '.' . $this->name($key);
01639 }
01640 return $key;
01641 }
01642
01643
01644
01645
01646
01647
01648 function __scrubQueryData($data) {
01649 foreach (array('conditions', 'fields', 'joins', 'order', 'limit', 'offset', 'group') as $key) {
01650 if (!isset($data[$key]) || empty($data[$key])) {
01651 $data[$key] = array();
01652 }
01653 }
01654 return $data;
01655 }
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665 function fields(&$model, $alias = null, $fields = array(), $quote = true) {
01666 if (empty($alias)) {
01667 $alias = $model->alias;
01668 }
01669 if (empty($fields)) {
01670 $fields = array_keys($model->schema());
01671 } elseif (!is_array($fields)) {
01672 $fields = String::tokenize($fields);
01673 }
01674 $fields = array_values(array_filter($fields));
01675
01676 if (!$quote) {
01677 return $fields;
01678 }
01679 $count = count($fields);
01680
01681 if ($count >= 1 && !in_array($fields[0], array('*', 'COUNT(*)'))) {
01682 for ($i = 0; $i < $count; $i++) {
01683 if (!preg_match('/^.+\\(.*\\)/', $fields[$i])) {
01684 $prepend = '';
01685
01686 if (strpos($fields[$i], 'DISTINCT') !== false) {
01687 $prepend = 'DISTINCT ';
01688 $fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i]));
01689 }
01690 $dot = strpos($fields[$i], '.');
01691
01692 if ($dot === false) {
01693 $prefix = !(
01694 strpos($fields[$i], ' ') !== false ||
01695 strpos($fields[$i], '(') !== false
01696 );
01697 $fields[$i] = $this->name(($prefix ? $alias . '.' : '') . $fields[$i]);
01698 } else {
01699 $value = array();
01700 $comma = strpos($fields[$i], ',');
01701 if ($comma === false) {
01702 $build = explode('.', $fields[$i]);
01703 if (!Set::numeric($build)) {
01704 $fields[$i] = $this->name($build[0] . '.' . $build[1]);
01705 }
01706 $comma = String::tokenize($fields[$i]);
01707 foreach ($comma as $string) {
01708 if (preg_match('/^[0-9]+\.[0-9]+$/', $string)) {
01709 $value[] = $string;
01710 } else {
01711 $build = explode('.', $string);
01712 $value[] = $this->name(trim($build[0]) . '.' . trim($build[1]));
01713 }
01714 }
01715 $fields[$i] = implode(', ', $value);
01716 }
01717 }
01718 $fields[$i] = $prepend . $fields[$i];
01719 } elseif (preg_match('/\(([\.\w]+)\)/', $fields[$i], $field)) {
01720 if (isset($field[1])) {
01721 if (strpos($field[1], '.') === false) {
01722 $field[1] = $this->name($alias . '.' . $field[1]);
01723 } else {
01724 $field[0] = explode('.', $field[1]);
01725 if (!Set::numeric($field[0])) {
01726 $field[0] = join('.', array_map(array($this, 'name'), $field[0]));
01727 $fields[$i] = preg_replace('/\(' . $field[1] . '\)/', '(' . $field[0] . ')', $fields[$i], 1);
01728 }
01729 }
01730 }
01731 }
01732 }
01733 }
01734 return array_unique($fields);
01735 }
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745 function conditions($conditions, $quoteValues = true, $where = true, $model = null) {
01746 $clause = $out = '';
01747
01748 if ($where) {
01749 $clause = ' WHERE ';
01750 }
01751
01752 if (is_array($conditions) && !empty($conditions)) {
01753 $out = $this->conditionKeysToString($conditions, $quoteValues, $model);
01754
01755 if (empty($out)) {
01756 return $clause . ' 1 = 1';
01757 }
01758 return $clause . join(' AND ', $out);
01759 }
01760
01761 if (empty($conditions) || trim($conditions) == '' || $conditions === true) {
01762 return $clause . '1 = 1';
01763 }
01764 $clauses = '/^WHERE\\x20|^GROUP\\x20BY\\x20|^HAVING\\x20|^ORDER\\x20BY\\x20/i';
01765
01766 if (preg_match($clauses, $conditions, $match)) {
01767 $clause = '';
01768 }
01769 if (trim($conditions) == '') {
01770 $conditions = ' 1 = 1';
01771 } else {
01772 $conditions = $this->__quoteFields($conditions);
01773 }
01774 return $clause . $conditions;
01775 }
01776
01777
01778
01779
01780
01781
01782
01783
01784 function conditionKeysToString($conditions, $quoteValues = true, $model = null) {
01785 $c = 0;
01786 $out = array();
01787 $data = $columnType = null;
01788 $bool = array('and', 'or', 'not', 'and not', 'or not', 'xor', '||', '&&');
01789
01790 foreach ($conditions as $key => $value) {
01791 $join = ' AND ';
01792 $not = null;
01793
01794 if (is_array($value)) {
01795 $valueInsert = (
01796 !empty($value) &&
01797 (substr_count($key, '?') == count($value) || substr_count($key, ':') == count($value))
01798 );
01799 }
01800
01801 if (is_numeric($key) && empty($value)) {
01802 continue;
01803 } elseif (is_numeric($key) && is_string($value)) {
01804 $out[] = $not . $this->__quoteFields($value);
01805 } elseif ((is_numeric($key) && is_array($value)) || in_array(strtolower(trim($key)), $bool)) {
01806 if (in_array(strtolower(trim($key)), $bool)) {
01807 $join = ' ' . strtoupper($key) . ' ';
01808 } else {
01809 $key = $join;
01810 }
01811 $value = $this->conditionKeysToString($value, $quoteValues, $model);
01812
01813 if (strpos($join, 'NOT') !== false) {
01814 if (strtoupper(trim($key)) == 'NOT') {
01815 $key = 'AND ' . trim($key);
01816 }
01817 $not = 'NOT ';
01818 }
01819
01820 if (empty($value[1])) {
01821 if ($not) {
01822 $out[] = $not . '(' . $value[0] . ')';
01823 } else {
01824 $out[] = $value[0] ;
01825 }
01826 } else {
01827 $out[] = '(' . $not . '(' . join(') ' . strtoupper($key) . ' (', $value) . '))';
01828 }
01829
01830 } else {
01831 if (is_object($value) && isset($value->type)) {
01832 if ($value->type == 'identifier') {
01833 $data .= $this->name($key) . ' = ' . $this->name($value->value);
01834 } elseif ($value->type == 'expression') {
01835 if (is_numeric($key)) {
01836 $data .= $value->value;
01837 } else {
01838 $data .= $this->name($key) . ' = ' . $value->value;
01839 }
01840 }
01841 } elseif (is_array($value) && !empty($value) && !$valueInsert) {
01842 $keys = array_keys($value);
01843 if (array_keys($value) === array_values(array_keys($value))) {
01844 $count = count($value);
01845 if ($count === 1) {
01846 $data = $this->__quoteFields($key) . ' = (';
01847 } else {
01848 $data = $this->__quoteFields($key) . ' IN (';
01849 }
01850 if ($quoteValues || strpos($value[0], '-!') !== 0) {
01851 if (is_object($model)) {
01852 $columnType = $model->getColumnType($key);
01853 }
01854 $data .= join(', ', $this->value($value, $columnType));
01855 }
01856 $data .= ')';
01857 } else {
01858 $ret = $this->conditionKeysToString($value, $quoteValues, $model);
01859 if (count($ret) > 1) {
01860 $data = '(' . join(') AND (', $ret) . ')';
01861 } elseif (isset($ret[0])) {
01862 $data = $ret[0];
01863 }
01864 }
01865 } elseif (is_numeric($key) && !empty($value)) {
01866 $data = $this->__quoteFields($value);
01867 } else {
01868 $data = $this->__parseKey($model, trim($key), $value);
01869 }
01870
01871 if ($data != null) {
01872 if (preg_match('/^\(\(\((.+)\)\)\)$/', $data)) {
01873 $data = substr($data, 1, strlen($data) - 2);
01874 }
01875 $out[] = $data;
01876 $data = null;
01877 }
01878 }
01879 $c++;
01880 }
01881 return $out;
01882 }
01883
01884
01885
01886
01887
01888
01889
01890
01891
01892
01893 function __parseKey($model, $key, $value) {
01894 $operatorMatch = '/^((' . join(')|(', $this->__sqlOps);
01895 $operatorMatch .= '\\x20)|<[>=]?(?![^>]+>)\\x20?|[>=!]{1,3}(?!<)\\x20?)/is';
01896 $bound = (strpos($key, '?') !== false || (is_array($value) && strpos($key, ':') !== false));
01897
01898 if (!strpos($key, ' ')) {
01899 $operator = '=';
01900 } else {
01901 list($key, $operator) = explode(' ', trim($key), 2);
01902
01903 if (!preg_match($operatorMatch, trim($operator)) && strpos($operator, ' ') !== false) {
01904 $key = $key . ' ' . $operator;
01905 $split = strrpos($key, ' ');
01906 $operator = substr($key, $split);
01907 $key = substr($key, 0, $split);
01908 }
01909 }
01910
01911
01912 $type = (is_object($model) ? $model->getColumnType($key) : null);
01913
01914 $null = ($value === null || (is_array($value) && empty($value)));
01915
01916 if (strtolower($operator) === 'not') {
01917 $data = $this->conditionKeysToString(
01918 array($operator => array($key => $value)), true, $model
01919 );
01920 return $data[0];
01921 }
01922
01923 $value = $this->value($value, $type);
01924
01925 if ($key !== '?') {
01926 $isKey = (strpos($key, '(') !== false || strpos($key, ')') !== false);
01927 $key = $isKey ? $this->__quoteFields($key) : $this->name($key);
01928 }
01929
01930 if ($bound) {
01931 return String::insert($key . ' ' . trim($operator), $value);
01932 }
01933
01934 if (!preg_match($operatorMatch, trim($operator))) {
01935 $operator .= ' =';
01936 }
01937 $operator = trim($operator);
01938
01939 if (is_array($value)) {
01940 $value = join(', ', $value);
01941
01942 switch ($operator) {
01943 case '=':
01944 $operator = 'IN';
01945 break;
01946 case '!=':
01947 case '<>':
01948 $operator = 'NOT IN';
01949 break;
01950 }
01951 $value = "({$value})";
01952 } elseif ($null) {
01953 switch ($operator) {
01954 case '=':
01955 $operator = 'IS';
01956 break;
01957 case '!=':
01958 case '<>':
01959 $operator = 'IS NOT';
01960 break;
01961 }
01962 }
01963
01964 return "{$key} {$operator} {$value}";
01965 }
01966
01967
01968
01969
01970
01971
01972
01973 function __quoteFields($conditions) {
01974 $start = $end = null;
01975 $original = $conditions;
01976
01977 if (!empty($this->startQuote)) {
01978 $start = preg_quote($this->startQuote);
01979 }
01980 if (!empty($this->endQuote)) {
01981 $end = preg_quote($this->endQuote);
01982 }
01983 $conditions = str_replace(array($start, $end), '', $conditions);
01984 preg_match_all('/(?:[\'\"][^\'\"\\\]*(?:\\\.[^\'\"\\\]*)*[\'\"])|([a-z0-9_' . $start . $end . ']*\\.[a-z0-9_' . $start . $end . ']*)/i', $conditions, $replace, PREG_PATTERN_ORDER);
01985
01986 if (isset($replace['1']['0'])) {
01987 $pregCount = count($replace['1']);
01988
01989 for ($i = 0; $i < $pregCount; $i++) {
01990 if (!empty($replace['1'][$i]) && !is_numeric($replace['1'][$i])) {
01991 $conditions = preg_replace('/\b' . preg_quote($replace['1'][$i]) . '\b/', $this->name($replace['1'][$i]), $conditions);
01992 }
01993 }
01994 return $conditions;
01995 }
01996 return $original;
01997 }
01998
01999
02000
02001
02002
02003
02004
02005 function limit($limit, $offset = null) {
02006 if ($limit) {
02007 $rt = '';
02008 if (!strpos(strtolower($limit), 'limit') || strpos(strtolower($limit), 'limit') === 0) {
02009 $rt = ' LIMIT';
02010 }
02011
02012 if ($offset) {
02013 $rt .= ' ' . $offset . ',';
02014 }
02015
02016 $rt .= ' ' . $limit;
02017 return $rt;
02018 }
02019 return null;
02020 }
02021
02022
02023
02024
02025
02026
02027
02028 function order($keys, $direction = 'ASC') {
02029 if (is_string($keys) && strpos($keys, ',') && !preg_match('/\(.+\,.+\)/', $keys)) {
02030 $keys = array_map('trim', explode(',', $keys));
02031 }
02032
02033 if (is_array($keys)) {
02034 $keys = array_filter($keys);
02035 }
02036
02037 if (empty($keys) || (is_array($keys) && count($keys) && isset($keys[0]) && empty($keys[0]))) {
02038 return '';
02039 }
02040
02041 if (is_array($keys)) {
02042 $keys = (Set::countDim($keys) > 1) ? array_map(array(&$this, 'order'), $keys) : $keys;
02043
02044 foreach ($keys as $key => $value) {
02045 if (is_numeric($key)) {
02046 $key = $value = ltrim(str_replace('ORDER BY ', '', $this->order($value)));
02047 $value = (!preg_match('/\\x20ASC|\\x20DESC/i', $key) ? ' ' . $direction : '');
02048 } else {
02049 $value = ' ' . $value;
02050 }
02051
02052 if (!preg_match('/^.+\\(.*\\)/', $key) && !strpos($key, ',')) {
02053 if (preg_match('/\\x20ASC|\\x20DESC/i', $key, $dir)) {
02054 $dir = $dir[0];
02055 $key = preg_replace('/\\x20ASC|\\x20DESC/i', '', $key);
02056 } else {
02057 $dir = '';
02058 }
02059 $key = trim($key);
02060 if (!preg_match('/\s/', $key)) {
02061 $key = $this->name($key);
02062 }
02063 $key .= ' ' . trim($dir);
02064 }
02065 $order[] = $this->order($key . $value);
02066 }
02067 return ' ORDER BY ' . trim(str_replace('ORDER BY', '', join(',', $order)));
02068 }
02069 $keys = preg_replace('/ORDER\\x20BY/i', '', $keys);
02070
02071 if (strpos($keys, '.')) {
02072 preg_match_all('/([a-zA-Z0-9_]{1,})\\.([a-zA-Z0-9_]{1,})/', $keys, $result, PREG_PATTERN_ORDER);
02073 $pregCount = count($result[0]);
02074
02075 for ($i = 0; $i < $pregCount; $i++) {
02076 if (!is_numeric($result[0][$i])) {
02077 $keys = preg_replace('/' . $result[0][$i] . '/', $this->name($result[0][$i]), $keys);
02078 }
02079 }
02080 $result = ' ORDER BY ' . $keys;
02081 return $result . (!preg_match('/\\x20ASC|\\x20DESC/i', $keys) ? ' ' . $direction : '');
02082
02083 } elseif (preg_match('/(\\x20ASC|\\x20DESC)/i', $keys, $match)) {
02084 $direction = $match[1];
02085 return ' ORDER BY ' . preg_replace('/' . $match[1] . '/', '', $keys) . $direction;
02086 }
02087 return ' ORDER BY ' . $keys . ' ' . $direction;
02088 }
02089
02090
02091
02092
02093
02094
02095 function group($group) {
02096 if ($group) {
02097 if (is_array($group)) {
02098 $group = join(', ', $group);
02099 }
02100 return ' GROUP BY ' . $this->__quoteFields($group);
02101 }
02102 return null;
02103 }
02104
02105
02106
02107
02108
02109 function close() {
02110 if (Configure::read() > 1) {
02111 $this->showLog();
02112 }
02113 $this->disconnect();
02114 }
02115
02116
02117
02118
02119
02120
02121
02122 function hasAny(&$Model, $sql) {
02123 $sql = $this->conditions($sql);
02124 $table = $this->fullTableName($Model);
02125 $alias = $this->alias . $this->name($Model->alias);
02126 $where = $sql ? "{$sql}" : ' WHERE 1 = 1';
02127 $id = $Model->escapeField();
02128
02129 $out = $this->fetchRow("SELECT COUNT({$id}) {$this->alias}count FROM {$table} {$alias}{$where}");
02130
02131 if (is_array($out)) {
02132 return $out[0]['count'];
02133 }
02134 return false;
02135 }
02136
02137
02138
02139
02140
02141
02142 function length($real) {
02143 if (!preg_match_all('/([\w\s]+)(?:\((\d+)(?:,(\d+))?\))?(\sunsigned)?(\szerofill)?/', $real, $result)) {
02144 trigger_error(__('FIXME: Can\'t parse field: ' . $real, true), E_USER_WARNING);
02145 $col = str_replace(array(')', 'unsigned'), '', $real);
02146 $limit = null;
02147
02148 if (strpos($col, '(') !== false) {
02149 list($col, $limit) = explode('(', $col);
02150 }
02151 if ($limit != null) {
02152 return intval($limit);
02153 }
02154 return null;
02155 }
02156
02157 $types = array(
02158 'int' => 1, 'tinyint' => 1, 'smallint' => 1, 'mediumint' => 1, 'integer' => 1, 'bigint' => 1
02159 );
02160
02161 list($real, $type, $length, $offset, $sign, $zerofill) = $result;
02162 $typeArr = $type;
02163 $type = $type[0];
02164 $length = $length[0];
02165 $offset = $offset[0];
02166
02167 $isFloat = in_array($type, array('dec', 'decimal', 'float', 'numeric', 'double'));
02168 if ($isFloat && $offset) {
02169 return $length.','.$offset;
02170 }
02171
02172 if (($real[0] == $type) && (count($real) == 1)) {
02173 return null;
02174 }
02175
02176 if (isset($types[$type])) {
02177 $length += $types[$type];
02178 if (!empty($sign)) {
02179 $length--;
02180 }
02181 } elseif (in_array($type, array('enum', 'set'))) {
02182 $length = 0;
02183 foreach ($typeArr as $key => $enumValue) {
02184 if ($key == 0) {
02185 continue;
02186 }
02187 $tmpLength = strlen($enumValue);
02188 if ($tmpLength > $length) {
02189 $length = $tmpLength;
02190 }
02191 }
02192 }
02193 return intval($length);
02194 }
02195
02196
02197
02198
02199
02200
02201 function boolean($data) {
02202 if ($data === true || $data === false) {
02203 if ($data === true) {
02204 return 1;
02205 }
02206 return 0;
02207 } else {
02208 return !empty($data);
02209 }
02210 }
02211
02212
02213
02214
02215
02216
02217
02218
02219 function insertMulti($table, $fields, $values) {
02220 $table = $this->fullTableName($table);
02221 if (is_array($fields)) {
02222 $fields = join(', ', array_map(array(&$this, 'name'), $fields));
02223 }
02224 $count = count($values);
02225 for ($x = 0; $x < $count; $x++) {
02226 $this->query("INSERT INTO {$table} ({$fields}) VALUES {$values[$x]}");
02227 }
02228 }
02229
02230
02231
02232
02233
02234
02235 function index($model) {
02236 return false;
02237 }
02238
02239
02240
02241
02242
02243
02244
02245
02246 function createSchema($schema, $tableName = null) {
02247 if (!is_a($schema, 'CakeSchema')) {
02248 trigger_error(__('Invalid schema object', true), E_USER_WARNING);
02249 return null;
02250 }
02251 $out = '';
02252
02253 foreach ($schema->tables as $curTable => $columns) {
02254 if (!$tableName || $tableName == $curTable) {
02255 $cols = $colList = $indexes = array();
02256 $primary = null;
02257 $table = $this->fullTableName($curTable);
02258
02259 foreach ($columns as $name => $col) {
02260 if (is_string($col)) {
02261 $col = array('type' => $col);
02262 }
02263 if (isset($col['key']) && $col['key'] == 'primary') {
02264 $primary = $name;
02265 }
02266 if ($name !== 'indexes') {
02267 $col['name'] = $name;
02268 if (!isset($col['type'])) {
02269 $col['type'] = 'string';
02270 }
02271 $cols[] = $this->buildColumn($col);
02272 } else {
02273 $indexes = array_merge($indexes, $this->buildIndex($col, $table));
02274 }
02275 }
02276 if (empty($indexes) && !empty($primary)) {
02277 $col = array('PRIMARY' => array('column' => $primary, 'unique' => 1));
02278 $indexes = array_merge($indexes, $this->buildIndex($col, $table));
02279 }
02280 $columns = $cols;
02281 $out .= $this->renderStatement('schema', compact('table', 'columns', 'indexes')) . "\n\n";
02282 }
02283 }
02284 return $out;
02285 }
02286
02287
02288
02289
02290
02291
02292 function alterSchema($compare, $table = null) {
02293 return false;
02294 }
02295
02296
02297
02298
02299
02300
02301
02302
02303 function dropSchema($schema, $table = null) {
02304 if (!is_a($schema, 'CakeSchema')) {
02305 trigger_error(__('Invalid schema object', true), E_USER_WARNING);
02306 return null;
02307 }
02308 $out = '';
02309
02310 foreach ($schema->tables as $curTable => $columns) {
02311 if (!$table || $table == $curTable) {
02312 $out .= 'DROP TABLE ' . $this->fullTableName($curTable) . ";\n";
02313 }
02314 }
02315 return $out;
02316 }
02317
02318
02319
02320
02321
02322
02323
02324 function buildColumn($column) {
02325 $name = $type = null;
02326 extract(array_merge(array('null' => true), $column));
02327
02328 if (empty($name) || empty($type)) {
02329 trigger_error('Column name or type not defined in schema', E_USER_WARNING);
02330 return null;
02331 }
02332
02333 if (!isset($this->columns[$type])) {
02334 trigger_error("Column type {$type} does not exist", E_USER_WARNING);
02335 return null;
02336 }
02337
02338 $real = $this->columns[$type];
02339 $out = $this->name($name) . ' ' . $real['name'];
02340
02341 if (isset($real['limit']) || isset($real['length']) || isset($column['limit']) || isset($column['length'])) {
02342 if (isset($column['length'])) {
02343 $length = $column['length'];
02344 } elseif (isset($column['limit'])) {
02345 $length = $column['limit'];
02346 } elseif (isset($real['length'])) {
02347 $length = $real['length'];
02348 } else {
02349 $length = $real['limit'];
02350 }
02351 $out .= '(' . $length . ')';
02352 }
02353
02354 if (($column['type'] == 'integer' || $column['type'] == 'float' ) && isset($column['default']) && $column['default'] === '') {
02355 $column['default'] = null;
02356 }
02357
02358 if (isset($column['key']) && $column['key'] == 'primary' && $type == 'integer') {
02359 $out .= ' ' . $this->columns['primary_key']['name'];
02360 } elseif (isset($column['key']) && $column['key'] == 'primary') {
02361 $out .= ' NOT NULL';
02362 } elseif (isset($column['default']) && isset($column['null']) && $column['null'] == false) {
02363 $out .= ' DEFAULT ' . $this->value($column['default'], $type) . ' NOT NULL';
02364 } elseif (isset($column['default'])) {
02365 $out .= ' DEFAULT ' . $this->value($column['default'], $type);
02366 } elseif (isset($column['null']) && $column['null'] == true) {
02367 $out .= ' DEFAULT NULL';
02368 } elseif (isset($column['null']) && $column['null'] == false) {
02369 $out .= ' NOT NULL';
02370 }
02371 return $out;
02372 }
02373
02374
02375
02376
02377
02378
02379
02380 function buildIndex($indexes, $table = null) {
02381 $join = array();
02382 foreach ($indexes as $name => $value) {
02383 $out = '';
02384 if ($name == 'PRIMARY') {
02385 $out .= 'PRIMARY ';
02386 $name = null;
02387 } else {
02388 if (!empty($value['unique'])) {
02389 $out .= 'UNIQUE ';
02390 }
02391 $name = $this->startQuote . $name . $this->endQuote;
02392 }
02393 if (is_array($value['column'])) {
02394 $out .= 'KEY ' . $name . ' (' . join(', ', array_map(array(&$this, 'name'), $value['column'])) . ')';
02395 } else {
02396 $out .= 'KEY ' . $name . ' (' . $this->name($value['column']) . ')';
02397 }
02398 $join[] = $out;
02399 }
02400 return $join;
02401 }
02402
02403
02404
02405
02406
02407
02408
02409 function introspectType($value) {
02410 if (!is_array($value)) {
02411 if ($value === true || $value === false) {
02412 return 'boolean';
02413 }
02414 if (is_float($value) && floatval($value) === $value) {
02415 return 'float';
02416 }
02417 if (is_int($value) && intval($value) === $value) {
02418 return 'integer';
02419 }
02420 if (is_string($value) && strlen($value) > 255) {
02421 return 'text';
02422 }
02423 return 'string';
02424 }
02425
02426 $isAllFloat = $isAllInt = true;
02427 $containsFloat = $containsInt = $containsString = false;
02428 foreach ($value as $key => $valElement) {
02429 $valElement = trim($valElement);
02430 if (!is_float($valElement) && !preg_match('/^[\d]+\.[\d]+$/', $valElement)) {
02431 $isAllFloat = false;
02432 } else {
02433 $containsFloat = true;
02434 continue;
02435 }
02436 if (!is_int($valElement) && !preg_match('/^[\d]+$/', $valElement)) {
02437 $isAllInt = false;
02438 } else {
02439 $containsInt = true;
02440 continue;
02441 }
02442 $containsString = true;
02443 }
02444
02445 if ($isAllFloat) {
02446 return 'float';
02447 }
02448 if ($isAllInt) {
02449 return 'integer';
02450 }
02451
02452 if ($containsInt && !$containsString) {
02453 return 'integer';
02454 }
02455 return 'string';
02456 }
02457 }
02458 ?>