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
00028
00029 uses('set');
00030
00031
00032
00033
00034
00035
00036
00037
00038 class DboSource extends DataSource {
00039
00040
00041
00042
00043
00044 var $description = "Database Data Source";
00045
00046
00047
00048
00049
00050 var $index = array('PRI'=> 'primary', 'MUL'=> 'index', 'UNI'=>'unique');
00051
00052
00053
00054
00055
00056 var $startQuote = null;
00057
00058
00059
00060
00061
00062 var $endQuote = null;
00063
00064
00065
00066
00067
00068 var $alias = 'AS ';
00069
00070
00071
00072
00073
00074 var $goofyLimit = false;
00075
00076
00077
00078
00079
00080 var $__bypass = false;
00081
00082
00083
00084
00085
00086 var $__sqlOps = array('like', 'ilike', 'or', 'not', 'in', 'between', 'regexp', 'similar to');
00087
00088
00089
00090 function __construct($config = null, $autoConnect = true) {
00091 $this->debug = Configure::read() > 0;
00092 $this->fullDebug = Configure::read() > 1;
00093 parent::__construct($config);
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 if ($config != null) {
00110 $this->config = array_merge($this->_baseConfig, $config);
00111 }
00112 return $this->connect();
00113 }
00114
00115
00116
00117
00118
00119
00120 function value($data, $column = null) {
00121 if (is_array($data)) {
00122 $out = array();
00123 $keys = array_keys($data);
00124 $count = count($data);
00125 for ($i = 0; $i < $count; $i++) {
00126 $out[$keys[$i]] = $this->value($data[$keys[$i]]);
00127 }
00128 return $out;
00129 } elseif (in_array($data, array('{$__cakeID__$}', '{$__cakeForeignKey__$}'), true)) {
00130 return $data;
00131 }
00132 return null;
00133 }
00134
00135
00136
00137
00138
00139
00140 function rawQuery($sql) {
00141 $this->took = $this->error = $this->numRows = false;
00142 return $this->execute($sql);
00143 }
00144
00145
00146
00147
00148
00149
00150
00151
00152 function execute($sql) {
00153 $t = getMicrotime();
00154 $this->_result = $this->_execute($sql);
00155 $this->affected = $this->lastAffected();
00156 $this->took = round((getMicrotime() - $t) * 1000, 0);
00157 $this->error = $this->lastError();
00158 $this->numRows = $this->lastNumRows($this->_result);
00159
00160 if ($this->fullDebug && Configure::read() > 1) {
00161 $this->logQuery($sql);
00162 }
00163
00164 if ($this->error) {
00165 $this->showQuery($sql);
00166 return false;
00167 } else {
00168 return $this->_result;
00169 }
00170 }
00171
00172
00173
00174
00175
00176 function query() {
00177 $args = func_get_args();
00178 $fields = null;
00179 $order = null;
00180 $limit = null;
00181 $page = null;
00182 $recursive = null;
00183
00184 if (count($args) == 1) {
00185 return $this->fetchAll($args[0]);
00186
00187 } elseif (count($args) > 1 && (strpos(strtolower($args[0]), 'findby') === 0 || strpos(strtolower($args[0]), 'findallby') === 0)) {
00188 $params = $args[1];
00189
00190 if (strpos(strtolower($args[0]), 'findby') === 0) {
00191 $all = false;
00192 $field = Inflector::underscore(preg_replace('/findBy/i', '', $args[0]));
00193 } else {
00194 $all = true;
00195 $field = Inflector::underscore(preg_replace('/findAllBy/i', '', $args[0]));
00196 }
00197
00198 $or = (strpos($field, '_or_') !== false);
00199 if ($or) {
00200 $field = explode('_or_', $field);
00201 } else {
00202 $field = explode('_and_', $field);
00203 }
00204 $off = count($field) - 1;
00205
00206 if (isset($params[1 + $off])) {
00207 $fields = $params[1 + $off];
00208 }
00209
00210 if (isset($params[2 + $off])) {
00211 $order = $params[2 + $off];
00212 }
00213
00214 if (!array_key_exists(0, $params)) {
00215 return false;
00216 }
00217
00218 $c = 0;
00219 $query = array();
00220 foreach ($field as $f) {
00221 if (!is_array($params[$c]) && !empty($params[$c]) && $params[$c] !== true && $params[$c] !== false) {
00222 $query[$args[2]->alias . '.' . $f] = '= ' . $params[$c];
00223 } else {
00224 $query[$args[2]->alias . '.' . $f] = $params[$c];
00225 }
00226 $c++;
00227 }
00228
00229 if ($or) {
00230 $query = array('OR' => $query);
00231 }
00232
00233 if ($all) {
00234
00235 if (isset($params[3 + $off])) {
00236 $limit = $params[3 + $off];
00237 }
00238
00239 if (isset($params[4 + $off])) {
00240 $page = $params[4 + $off];
00241 }
00242
00243 if (isset($params[5 + $off])) {
00244 $recursive = $params[5 + $off];
00245 }
00246 return $args[2]->findAll($query, $fields, $order, $limit, $page, $recursive);
00247 } else {
00248 if (isset($params[3 + $off])) {
00249 $recursive = $params[3 + $off];
00250 }
00251 return $args[2]->find($query, $fields, $order, $recursive);
00252 }
00253 } else {
00254 if (isset($args[1]) && $args[1] === true) {
00255 return $this->fetchAll($args[0], true);
00256 }
00257 return $this->fetchAll($args[0], false);
00258 }
00259 }
00260
00261
00262
00263
00264
00265 function fetchRow($sql = null) {
00266
00267 if (!empty($sql) && is_string($sql) && strlen($sql) > 5) {
00268 if (!$this->execute($sql)) {
00269 return null;
00270 }
00271 }
00272
00273 if (is_resource($this->_result) || is_object($this->_result)) {
00274 $this->resultSet($this->_result);
00275 $resultRow = $this->fetchResult();
00276 return $resultRow;
00277 } else {
00278 return null;
00279 }
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289 function fetchAll($sql, $cache = true, $modelName = null) {
00290 if ($cache && isset($this->_queryCache[$sql])) {
00291 if (preg_match('/^\s*select/i', $sql)) {
00292 return $this->_queryCache[$sql];
00293 }
00294 }
00295
00296 if ($this->execute($sql)) {
00297 $out = array();
00298
00299 while ($item = $this->fetchRow()) {
00300 $out[] = $item;
00301 }
00302
00303 if ($cache) {
00304 if (strpos(trim(strtolower($sql)), 'select') !== false) {
00305 $this->_queryCache[$sql] = $out;
00306 }
00307 }
00308 return $out;
00309
00310 } else {
00311 return false;
00312 }
00313 }
00314
00315
00316
00317
00318
00319
00320
00321 function field($name, $sql) {
00322 $data = $this->fetchRow($sql);
00323
00324 if (!isset($data[$name]) || empty($data[$name])) {
00325 return false;
00326 } else {
00327 return $data[$name];
00328 }
00329 }
00330
00331
00332
00333
00334
00335
00336
00337 function name($data) {
00338 if (preg_match_all('/([^(]*)\((.*)\)(.*)/', $data, $fields)) {
00339 $fields = Set::extract($fields, '{n}.0');
00340 if (!empty($fields[1])) {
00341 if (!empty($fields[2])) {
00342 return $fields[1] . '(' . $this->name($fields[2]) . ')' . $fields[3];
00343 } else {
00344 return $fields[1] . '()' . $fields[3];
00345 }
00346 }
00347 }
00348 if ($data == '*') {
00349 return '*';
00350 }
00351 $data = $this->startQuote . str_replace('.', $this->endQuote . '.' . $this->startQuote, $data) . $this->endQuote;
00352 $data = str_replace($this->startQuote . $this->startQuote, $this->startQuote, $data);
00353
00354 if (!empty($this->endQuote) && $this->endQuote == $this->startQuote) {
00355 $oddMatches = substr_count($data, $this->endQuote);
00356 if ($oddMatches % 2 == 1) {
00357 $data = trim($data, $this->endQuote);
00358 }
00359 }
00360 return str_replace($this->endQuote . $this->endQuote, $this->endQuote, $data);
00361 }
00362
00363
00364
00365
00366
00367 function isConnected() {
00368 return $this->connected;
00369 }
00370
00371
00372
00373
00374
00375 function showLog($sorted = false) {
00376 if ($sorted) {
00377 $log = sortByKey($this->_queriesLog, 'took', 'desc', SORT_NUMERIC);
00378 } else {
00379 $log = $this->_queriesLog;
00380 }
00381
00382 if ($this->_queriesCnt > 1) {
00383 $text = 'queries';
00384 } else {
00385 $text = 'query';
00386 }
00387
00388 if (php_sapi_name() != 'cli') {
00389 print ("<table class=\"cakeSqlLog\" id=\"cakeSqlLog_" . preg_replace('/[^A-Za-z0-9_]/', '_', uniqid(time(), true)) . "\" summary=\"Cake SQL Log\" cellspacing=\"0\" border = \"0\">\n<caption>{$this->_queriesCnt} {$text} took {$this->_queriesTime} ms</caption>\n");
00390 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");
00391
00392 foreach ($log as $k => $i) {
00393 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");
00394 }
00395 print ("</tbody></table>\n");
00396 } else {
00397 foreach ($log as $k => $i) {
00398 print (($k + 1) . ". {$i['query']} {$i['error']}\n");
00399 }
00400 }
00401 }
00402
00403
00404
00405
00406
00407
00408 function logQuery($sql) {
00409 $this->_queriesCnt++;
00410 $this->_queriesTime += $this->took;
00411 $this->_queriesLog[] = array('query' => $sql,
00412 'error' => $this->error,
00413 'affected' => $this->affected,
00414 'numRows' => $this->numRows,
00415 'took' => $this->took
00416 );
00417 if (count($this->_queriesLog) > $this->_queriesLogMax) {
00418 array_pop($this->_queriesLog);
00419 }
00420 if ($this->error) {
00421 return false;
00422 }
00423 }
00424
00425
00426
00427
00428
00429
00430 function showQuery($sql) {
00431 $error = $this->error;
00432 if (strlen($sql) > 200 && !$this->fullDebug && Configure::read() > 1) {
00433 $sql = substr($sql, 0, 200) . '[...]';
00434 }
00435
00436 if (($this->debug || $error) && Configure::read() > 0) {
00437 e("<p style = \"text-align:left\"><b>Query:</b> {$sql} ");
00438 if ($error) {
00439 trigger_error("<span style = \"color:Red;text-align:left\"><b>SQL Error:</b> {$this->error}</span>", E_USER_WARNING);
00440 } else {
00441 e("<small>[Aff:{$this->affected} Num:{$this->numRows} Took:{$this->took}ms]</small>");
00442 }
00443 print ('</p>');
00444 }
00445 }
00446
00447
00448
00449
00450
00451
00452
00453 function fullTableName($model, $quote = true) {
00454 if (is_object($model)) {
00455 $table = $model->tablePrefix . $model->table;
00456 } elseif (isset($this->config['prefix'])) {
00457 $table = $this->config['prefix'] . strval($model);
00458 } else {
00459 $table = strval($model);
00460 }
00461 if ($quote) {
00462 return $this->name($table);
00463 }
00464 return $table;
00465 }
00466
00467
00468
00469
00470
00471
00472
00473
00474 function create(&$model, $fields = null, $values = null) {
00475 $fieldInsert = array();
00476 $valueInsert = array();
00477 $id = null;
00478
00479 if ($fields == null) {
00480 unset($fields, $values);
00481 $fields = array_keys($model->data);
00482 $values = array_values($model->data);
00483 }
00484 $count = count($fields);
00485
00486 for ($i = 0; $i < $count; $i++) {
00487 $fieldInsert[] = $this->name($fields[$i]);
00488 if ($fields[$i] == $model->primaryKey) {
00489 $id = $values[$i];
00490 }
00491 }
00492 $count = count($values);
00493
00494 for ($i = 0; $i < $count; $i++) {
00495 $valueInsert[] = $this->value($values[$i], $model->getColumnType($fields[$i]));
00496 }
00497
00498 if ($this->execute('INSERT INTO ' . $this->fullTableName($model) . ' (' . join(',', $fieldInsert). ') VALUES (' . join(',', $valueInsert) . ')')) {
00499 if (empty($id)) {
00500 $id = $this->lastInsertId($this->fullTableName($model, false), $model->primaryKey);
00501 }
00502 $model->setInsertID($id);
00503 $model->id = $id;
00504 return true;
00505 } else {
00506 $model->onError();
00507 return false;
00508 }
00509 }
00510
00511
00512
00513
00514
00515
00516
00517
00518 function read(&$model, $queryData = array(), $recursive = null) {
00519
00520 $this->__scrubQueryData($queryData);
00521 $null = null;
00522 $array = array();
00523 $linkedModels = array();
00524 $this->__bypass = false;
00525
00526 if ($recursive === null && isset($queryData['recursive'])) {
00527 $recursive = $queryData['recursive'];
00528 }
00529
00530 if (!is_null($recursive)) {
00531 $_recursive = $model->recursive;
00532 $model->recursive = $recursive;
00533 }
00534
00535 if (!empty($queryData['fields'])) {
00536 $this->__bypass = true;
00537 $queryData['fields'] = $this->fields($model, null, $queryData['fields']);
00538 } else {
00539 $queryData['fields'] = $this->fields($model);
00540 }
00541
00542 foreach ($model->__associations as $type) {
00543 foreach ($model->{$type} as $assoc => $assocData) {
00544 if ($model->recursive > -1) {
00545 $linkModel =& $model->{$assoc};
00546
00547 $external = isset($assocData['external']);
00548 if ($model->alias == $linkModel->alias && $type != 'hasAndBelongsToMany' && $type != 'hasMany') {
00549 if (true === $this->generateSelfAssociationQuery($model, $linkModel, $type, $assoc, $assocData, $queryData, $external, $null)) {
00550 $linkedModels[] = $type . '/' . $assoc;
00551 }
00552 } else {
00553 if ($model->useDbConfig == $linkModel->useDbConfig) {
00554 if (true === $this->generateAssociationQuery($model, $linkModel, $type, $assoc, $assocData, $queryData, $external, $null)) {
00555 $linkedModels[] = $type . '/' . $assoc;
00556 }
00557 }
00558 }
00559 }
00560 }
00561 }
00562
00563 $query = $this->generateAssociationQuery($model, $null, null, null, null, $queryData, false, $null);
00564 $resultSet = $this->fetchAll($query, $model->cacheQueries, $model->alias);
00565
00566 if ($resultSet === false) {
00567 $model->onError();
00568 return false;
00569 }
00570
00571 $filtered = $this->__filterResults($resultSet, $model);
00572
00573 if ($model->recursive > 0) {
00574 foreach ($model->__associations as $type) {
00575 foreach ($model->{$type} as $assoc => $assocData) {
00576 $db = null;
00577 $linkModel =& $model->{$assoc};
00578
00579 if (!in_array($type . '/' . $assoc, $linkedModels)) {
00580 if ($model->useDbConfig == $linkModel->useDbConfig) {
00581 $db =& $this;
00582 } else {
00583 $db =& ConnectionManager::getDataSource($linkModel->useDbConfig);
00584 }
00585 } elseif ($model->recursive > 1 && ($type == 'belongsTo' || $type == 'hasOne')) {
00586
00587 $db =& $this;
00588 } else {
00589 unset ($db);
00590 }
00591
00592 if (isset($db) && $db != null) {
00593 $stack = array($assoc);
00594 $db->queryAssociation($model, $linkModel, $type, $assoc, $assocData, $array, true, $resultSet, $model->recursive - 1, $stack);
00595 unset($db);
00596 }
00597 }
00598 }
00599 $this->__filterResults($resultSet, $model, $filtered);
00600 }
00601
00602 if (!is_null($recursive)) {
00603 $model->recursive = $_recursive;
00604 }
00605 return $resultSet;
00606 }
00607
00608
00609
00610
00611
00612
00613
00614
00615 function __filterResults(&$results, &$model, $filtered = array()) {
00616
00617 $filtering = array();
00618 $associations = array_merge($model->belongsTo, $model->hasOne, $model->hasMany, $model->hasAndBelongsToMany);
00619 $count = count($results);
00620
00621 for ($i = 0; $i < $count; $i++) {
00622 if (is_array($results[$i])) {
00623 $keys = array_keys($results[$i]);
00624 $count2 = count($keys);
00625
00626 for ($j = 0; $j < $count2; $j++) {
00627 $className = $key = $keys[$j];
00628
00629 if ($model->alias != $className && !in_array($key, $filtered)) {
00630 if (!in_array($key, $filtering)) {
00631 $filtering[] = $key;
00632 }
00633
00634 if (isset($model->{$className}) && is_object($model->{$className})) {
00635 $data = $model->{$className}->afterFind(array(array($key => $results[$i][$key])), false);
00636 }
00637 if (isset($data[0][$key])) {
00638 $results[$i][$key] = $data[0][$key];
00639 }
00640 }
00641 }
00642 }
00643 }
00644 return $filtering;
00645 }
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660 function queryAssociation(&$model, &$linkModel, $type, $association, $assocData, &$queryData, $external = false, &$resultSet, $recursive, $stack) {
00661
00662 if ($query = $this->generateAssociationQuery($model, $linkModel, $type, $association, $assocData, $queryData, $external, $resultSet)) {
00663 if (!isset($resultSet) || !is_array($resultSet)) {
00664 if (Configure::read() > 0) {
00665 e('<div style = "font: Verdana bold 12px; color: #FF0000">SQL Error in model ' . $model->alias . ': ');
00666 if (isset($this->error) && $this->error != null) {
00667 e($this->error);
00668 }
00669 e('</div>');
00670 }
00671 return null;
00672 }
00673 $count = count($resultSet);
00674
00675 if ($type === 'hasMany' && (!isset($assocData['limit']) || empty($assocData['limit']))) {
00676 $ins = $fetch = array();
00677 for ($i = 0; $i < $count; $i++) {
00678 if ($in = $this->insertQueryData('{$__cakeID__$}', $resultSet[$i], $association, $assocData, $model, $linkModel, $stack)) {
00679 $ins[] = $in;
00680 }
00681 }
00682
00683 if (!empty($ins)) {
00684 $query = r('{$__cakeID__$}', join(', ', $ins), $query);
00685 $fetch = $this->fetchAll($query, $model->cacheQueries, $model->alias);
00686 }
00687
00688 if (!empty($fetch) && is_array($fetch)) {
00689 if ($recursive > 0) {
00690
00691 foreach ($linkModel->__associations as $type1) {
00692 foreach ($linkModel->{$type1} as $assoc1 => $assocData1) {
00693
00694 $deepModel =& $linkModel->{$assocData1['className']};
00695 if ($deepModel->alias != $model->alias) {
00696 $tmpStack = $stack;
00697 $tmpStack[] = $assoc1;
00698 if ($linkModel->useDbConfig == $deepModel->useDbConfig) {
00699 $db =& $this;
00700 } else {
00701 $db =& ConnectionManager::getDataSource($deepModel->useDbConfig);
00702 }
00703 $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack);
00704 }
00705 }
00706 }
00707 }
00708 }
00709 return $this->__mergeHasMany($resultSet, $fetch, $association, $model, $linkModel, $recursive);
00710 }
00711 for ($i = 0; $i < $count; $i++) {
00712
00713 $row =& $resultSet[$i];
00714 $q = $this->insertQueryData($query, $resultSet[$i], $association, $assocData, $model, $linkModel, $stack);
00715
00716 if ($q != false) {
00717 $fetch = $this->fetchAll($q, $model->cacheQueries, $model->alias);
00718 } else {
00719 $fetch = null;
00720 }
00721
00722 if (!empty($fetch) && is_array($fetch)) {
00723 if ($recursive > 0) {
00724
00725 foreach ($linkModel->__associations as $type1) {
00726 foreach ($linkModel->{$type1} as $assoc1 => $assocData1) {
00727
00728 $deepModel =& $linkModel->{$assocData1['className']};
00729 if ($deepModel->alias != $model->alias) {
00730 $tmpStack = $stack;
00731 $tmpStack[] = $assoc1;
00732 if ($linkModel->useDbConfig == $deepModel->useDbConfig) {
00733 $db =& $this;
00734 } else {
00735 $db =& ConnectionManager::getDataSource($deepModel->useDbConfig);
00736 }
00737 $db->queryAssociation($linkModel, $deepModel, $type1, $assoc1, $assocData1, $queryData, true, $fetch, $recursive - 1, $tmpStack);
00738 }
00739 }
00740 }
00741 }
00742 $this->__mergeAssociation($resultSet[$i], $fetch, $association, $type);
00743 $resultSet[$i][$association] = $linkModel->afterfind($resultSet[$i][$association]);
00744
00745 } else {
00746 $tempArray[0][$association] = false;
00747 $this->__mergeAssociation($resultSet[$i], $tempArray, $association, $type);
00748 }
00749 }
00750 }
00751 }
00752
00753 function __mergeHasMany(&$resultSet, $merge, $association, &$model, &$linkModel) {
00754 foreach ($resultSet as $i => $value) {
00755 $count = 0;
00756 $merged[$association] = array();
00757 foreach ($merge as $j => $data) {
00758 if (isset($value[$model->alias]) && $value[$model->alias][$model->primaryKey] === $data[$association][$model->hasMany[$association]['foreignKey']]) {
00759 if (count($data) > 1) {
00760 $data = array_merge($data[$association], $data);
00761 unset($data[$association]);
00762 foreach ($data as $key => $name) {
00763 if (is_numeric($key)) {
00764 $data[$association][] = $name;
00765 unset($data[$key]);
00766 }
00767 }
00768 $merged[$association][] = $data;
00769 } else {
00770 $merged[$association][] = $data[$association];
00771 }
00772 }
00773 $count++;
00774 }
00775 if (isset($value[$model->alias])) {
00776 $resultSet[$i] = Set::pushDiff($resultSet[$i], $merged);
00777 unset($merged);
00778 }
00779 }
00780 }
00781
00782
00783
00784
00785
00786
00787
00788
00789 function __mergeAssociation(&$data, $merge, $association, $type) {
00790
00791 if (isset($merge[0]) && !isset($merge[0][$association])) {
00792 $association = Inflector::pluralize($association);
00793 }
00794
00795 if ($type == 'belongsTo' || $type == 'hasOne') {
00796 if (isset($merge[$association])) {
00797 $data[$association] = $merge[$association][0];
00798 } else {
00799 if (count($merge[0][$association]) > 1) {
00800 foreach ($merge[0] as $assoc => $data2) {
00801 if ($assoc != $association) {
00802 $merge[0][$association][$assoc] = $data2;
00803 }
00804 }
00805 }
00806 if (!isset($data[$association])) {
00807 if ($merge[0][$association] != null) {
00808 $data[$association] = $merge[0][$association];
00809 } else {
00810 $data[$association] = array();
00811 }
00812 } else {
00813 if (is_array($merge[0][$association])) {
00814 foreach ($data[$association] as $k => $v) {
00815 if (!is_array($v)) {
00816 $dataAssocTmp[$k] = $v;
00817 }
00818 }
00819
00820 foreach ($merge[0][$association] as $k => $v) {
00821 if (!is_array($v)) {
00822 $mergeAssocTmp[$k] = $v;
00823 }
00824 }
00825
00826 if (array_keys($merge[0]) === array_keys($data)) {
00827 $data[$association][$association] = $merge[0][$association];
00828 } else {
00829 $diff = Set::diff($dataAssocTmp, $mergeAssocTmp);
00830 $data[$association] = array_merge($merge[0][$association], $diff);
00831 }
00832 }
00833 }
00834 }
00835 } else {
00836 if ($merge[0][$association] === false) {
00837 if (!isset($data[$association])) {
00838 $data[$association] = array();
00839 }
00840 } else {
00841 foreach ($merge as $i => $row) {
00842 if (count($row) == 1) {
00843 $data[$association][] = $row[$association];
00844 } else {
00845 $tmp = array_merge($row[$association], $row);
00846 unset($tmp[$association]);
00847 $data[$association][] = $tmp;
00848 }
00849 }
00850 }
00851 }
00852 }
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866 function generateSelfAssociationQuery(&$model, &$linkModel, $type, $association = null, $assocData = array(), &$queryData, $external = false, &$resultSet) {
00867 $alias = $association;
00868 if (empty($alias) && !empty($linkModel)) {
00869 $alias = $linkModel->alias;
00870 }
00871
00872 if (!isset($queryData['selfJoin'])) {
00873 $queryData['selfJoin'] = array();
00874
00875 $self = array(
00876 'fields' => $this->fields($model, null, $queryData['fields']),
00877 'joins' => array(array(
00878 'table' => $this->fullTableName($linkModel),
00879 'alias' => $alias,
00880 'type' => 'LEFT',
00881 'conditions' => array(
00882 $model->escapeField($assocData['foreignKey']) => '{$__cakeIdentifier[' . "{$alias}.{$linkModel->primaryKey}" . ']__$}'))
00883 ),
00884 'table' => $this->fullTableName($model),
00885 'alias' => $model->alias,
00886 'limit' => $queryData['limit'],
00887 'offset' => $queryData['offset'],
00888 'conditions'=> $queryData['conditions'],
00889 'order' => $queryData['order']
00890 );
00891
00892 if (!empty($assocData['conditions'])) {
00893 $self['joins'][0]['conditions'] = trim($this->conditions(array_merge($self['joins'][0]['conditions'], (array)$assocData['conditions']), true, false));
00894 }
00895
00896 if (!empty($queryData['joins'])) {
00897 foreach ($queryData['joins'] as $join) {
00898 $self['joins'][] = $join;
00899 }
00900 }
00901
00902 if ($this->__bypass === false) {
00903 $self['fields'] = array_merge($self['fields'], $this->fields($linkModel, $alias, (isset($assocData['fields']) ? $assocData['fields'] : '')));
00904 }
00905
00906 if (!in_array($self, $queryData['selfJoin'])) {
00907 $queryData['selfJoin'][] = $self;
00908 return true;
00909 }
00910
00911 } elseif (isset($linkModel)) {
00912 return $this->generateAssociationQuery($model, $linkModel, $type, $association, $assocData, $queryData, $external, $resultSet);
00913
00914 } else {
00915 $result = $queryData['selfJoin'][0];
00916 if (!empty($queryData['joins'])) {
00917 foreach ($queryData['joins'] as $join) {
00918 if (!in_array($join, $result['joins'])) {
00919 $result['joins'][] = $join;
00920 }
00921 }
00922 }
00923 if (!empty($queryData['conditions'])) {
00924 $result['conditions'] = trim($this->conditions(array_merge((array)$result['conditions'], $assocData['conditions']), true, false));
00925 }
00926 if (!empty($queryData['fields'])) {
00927 $result['fields'] = array_unique(array_merge($result['fields'], $queryData['fields']));
00928 }
00929 $sql = $this->buildStatement($result, $model);
00930 return $sql;
00931 }
00932 }
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946 function generateAssociationQuery(&$model, &$linkModel, $type, $association = null, $assocData = array(), &$queryData, $external = false, &$resultSet) {
00947 $this->__scrubQueryData($queryData);
00948 $this->__scrubQueryData($assocData);
00949 $joinedOnSelf = false;
00950
00951 if (empty($queryData['fields'])) {
00952 $queryData['fields'] = $this->fields($model, $model->alias);
00953 } elseif (!empty($model->hasMany) && $model->recursive > -1) {
00954 $assocFields = $this->fields($model, $model->alias, array("{$model->alias}.{$model->primaryKey}"));
00955 $passedFields = $this->fields($model, $model->alias, $queryData['fields']);
00956
00957 if (count($passedFields) === 1) {
00958 $match = strpos($passedFields[0], $assocFields[0]);
00959 $match1 = strpos($passedFields[0], 'COUNT(');
00960 if ($match === false && $match1 === false) {
00961 $queryData['fields'] = array_unique(array_merge($passedFields, $assocFields));
00962 } else {
00963 $queryData['fields'] = $passedFields;
00964 }
00965 } else {
00966 $queryData['fields'] = array_unique(array_merge($passedFields, $assocFields));
00967 }
00968 unset($assocFields, $passedFields);
00969 }
00970
00971 if ($linkModel == null) {
00972 if (array_key_exists('selfJoin', $queryData)) {
00973 return $this->generateSelfAssociationQuery($model, $linkModel, $type, $association, $assocData, $queryData, $external, $resultSet);
00974 } else {
00975 return $this->buildStatement(array(
00976 'fields' => array_unique($queryData['fields']),
00977 'table' => $this->fullTableName($model),
00978 'alias' => $model->alias,
00979 'limit' => $queryData['limit'],
00980 'offset' => $queryData['offset'],
00981 'joins' => $queryData['joins'],
00982 'conditions' => $queryData['conditions'],
00983 'order' => $queryData['order']), $model
00984 );
00985 }
00986 }
00987 $alias = $association;
00988
00989 if ($model->alias == $linkModel->alias) {
00990 $joinedOnSelf = true;
00991 }
00992
00993 if ($external && isset($assocData['finderQuery'])) {
00994 if (!empty($assocData['finderQuery'])) {
00995 return $assocData['finderQuery'];
00996 }
00997 }
00998
00999 if ((!$external && in_array($type, array('hasOne', 'belongsTo')) && $this->__bypass === false) || $external) {
01000 $fields = $this->fields($linkModel, $alias, $assocData['fields']);
01001 } else {
01002 $fields = array();
01003 }
01004 $limit = '';
01005
01006 if (isset($assocData['limit'])) {
01007 if ((!isset($assocData['offset']) || (empty($assocData['offset']))) && isset($assocData['page'])) {
01008 $assocData['offset'] = ($assocData['page'] - 1) * $assocData['limit'];
01009 } elseif (!isset($assocData['offset'])) {
01010 $assocData['offset'] = null;
01011 }
01012 $limit = $this->limit($assocData['limit'], $assocData['offset']);
01013 }
01014
01015 switch($type) {
01016 case 'hasOne':
01017 case 'belongsTo':
01018 if ($external) {
01019 if ($type == 'hasOne') {
01020 $conditions = $this->__mergeConditions($assocData['conditions'], array("{$alias}.{$assocData['foreignKey']}" => '{$__cakeID__$}'));
01021 } elseif ($type == 'belongsTo') {
01022 $conditions = $this->__mergeConditions($assocData['conditions'], array("{$alias}.{$linkModel->primaryKey}" => '{$__cakeForeignKey__$}'));
01023 }
01024 $query = array_merge($assocData, array(
01025 'conditions' => $conditions,
01026 'table' => $this->fullTableName($linkModel),
01027 'fields' => $fields,
01028 'alias' => $alias
01029 ));
01030
01031 if ($type == 'belongsTo') {
01032
01033
01034 $query = array_merge($query, array('order' => $assocData['order'], 'limit' => $limit));
01035 }
01036 } else {
01037 if ($type == 'hasOne') {
01038 $conditions = $this->__mergeConditions($assocData['conditions'], array("{$alias}.{$assocData['foreignKey']}" => '{$__cakeIdentifier[' . "{$model->alias}.{$model->primaryKey}" . ']__$}'));
01039 } elseif ($type == 'belongsTo') {
01040 $conditions = $this->__mergeConditions($assocData['conditions'], array("{$model->alias}.{$assocData['foreignKey']}" => '{$__cakeIdentifier[' . "{$alias}.{$linkModel->primaryKey}" . ']__$}'));
01041 }
01042
01043 $join = array(
01044 'table' => $this->fullTableName($linkModel),
01045 'alias' => $alias,
01046 'type' => 'LEFT',
01047 'conditions' => trim($this->conditions($conditions, true, false))
01048 );
01049
01050 $queryData['fields'] = array_merge($queryData['fields'], $fields);
01051
01052 if (!empty($assocData['order'])) {
01053 $hasCount = false;
01054 foreach ($queryData['fields'] as $field) {
01055 if (stripos($field, 'COUNT(*)') !== false) {
01056 $hasCount = true;
01057 break;
01058 }
01059 }
01060
01061 $putOrderByFields = true;
01062 if ($hasCount) {
01063 $orders = spliti(' ASC| DESC|,', $assocData['order']);
01064 foreach ($orders as $order) {
01065 $order = trim($order);
01066 if (!empty($order) && !in_array($order, $queryData['fields'])) {
01067 $putOrderByFields = false;
01068 break;
01069 }
01070 }
01071 }
01072
01073 if ($putOrderByFields) {
01074 $queryData['order'][] = $assocData['order'];
01075 }
01076 }
01077
01078 if (!in_array($join, $queryData['joins'])) {
01079 $queryData['joins'][] = $join;
01080 }
01081 return true;
01082 }
01083 break;
01084 case 'hasMany':
01085 $assocData['fields'] = array_unique(array_merge(
01086 $this->fields($linkModel, $alias, $assocData['fields']),
01087 $this->fields($linkModel, $alias, array("{$alias}.{$assocData['foreignKey']}"))
01088 ));
01089
01090 $query = array(
01091 'conditions' => $this->__mergeConditions(array("{$alias}.{$assocData['foreignKey']}" => array('{$__cakeID__$}')), $assocData['conditions']),
01092 'fields' => $assocData['fields'],
01093 'table' => $this->fullTableName($linkModel),
01094 'alias' => $alias,
01095 'order' => $assocData['order'],
01096 'limit' => $limit
01097 );
01098 break;
01099 case 'hasAndBelongsToMany':
01100 $joinTbl = $this->fullTableName($assocData['joinTable']);
01101 $joinFields = array();
01102 $joinAssoc = null;
01103 $joinAlias = $joinTbl;
01104
01105 if (isset($assocData['with']) && !empty($assocData['with'])) {
01106 $joinAssoc = $joinAlias = $model->{$assocData['with']}->name;
01107 $joinFields = $model->{$assocData['with']}->loadInfo();
01108 $joinFields = $joinFields->extract('{n}.name');
01109
01110 if (is_array($joinFields) && !empty($joinFields) && count($joinFields) > 2) {
01111 $joinFields = $this->fields($model->{$assocData['with']}, $model->{$assocData['with']}->name, $joinFields);
01112 } else {
01113 $joinFields = array();
01114 $joinAssoc = null;
01115 $joinAlias = $joinTbl;
01116 }
01117 }
01118
01119 $query = array(
01120 'conditions' => $assocData['conditions'],
01121 'limit' => $limit,
01122 'table' => $this->fullTableName($linkModel),
01123 'alias' => $alias,
01124 'fields' => array_merge($this->fields($linkModel, $alias, $assocData['fields']), $joinFields),
01125 'order' => $assocData['order'],
01126 'joins' => array(array(
01127 'table' => $joinTbl,
01128 'alias' => $joinAssoc,
01129 'conditions' => array(
01130 array("{$joinAlias}.{$assocData['foreignKey']}" => '{$__cakeID__$}'),
01131 array("{$joinAlias}.{$assocData['associationForeignKey']}" => '{$__cakeIdentifier['."{$alias}.{$linkModel->primaryKey}".']__$}')
01132 ))
01133 )
01134 );
01135 break;
01136 }
01137 if (isset($query)) {
01138 return $this->buildStatement($query, $model);
01139 }
01140 return null;
01141 }
01142
01143 function buildJoinStatement($join) {
01144 $data = array_merge(array(
01145 'type' => null,
01146 'alias' => null,
01147 'table' => 'join_table',
01148 'conditions' => array()
01149 ), $join);
01150
01151 if (!empty($data['alias'])) {
01152 $data['alias'] = $this->alias . $this->name($data['alias']);
01153 }
01154 if (!empty($data['conditions'])) {
01155 $data['conditions'] = trim($this->conditions($data['conditions'], true, false));
01156 }
01157 return $this->renderJoinStatement($data);
01158 }
01159
01160 function buildStatement($query, $model) {
01161 $query = array_merge(array('offset' => null, 'joins' => array()), $query);
01162 if (!empty($query['joins'])) {
01163 for ($i = 0; $i < count($query['joins']); $i++) {
01164 if (is_array($query['joins'][$i])) {
01165 $query['joins'][$i] = $this->buildJoinStatement($query['joins'][$i]);
01166 }
01167 }
01168 }
01169 return $this->renderStatement(array(
01170 'conditions' => $this->conditions($query['conditions']),
01171 'fields' => join(', ', $query['fields']),
01172 'table' => $query['table'],
01173 'alias' => $this->alias . $this->name($query['alias']),
01174 'order' => $this->order($query['order']),
01175 'limit' => $this->limit($query['limit'], $query['offset']),
01176 'joins' => join(' ', $query['joins'])
01177 ));
01178 }
01179
01180 function renderJoinStatement($data) {
01181 extract($data);
01182 return trim("{$type} JOIN {$table} {$alias} ON ({$conditions})");
01183 }
01184
01185 function renderStatement($data) {
01186 extract($data);
01187 return "SELECT {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$order} {$limit}";
01188 }
01189
01190
01191
01192
01193
01194 function __mergeConditions($query, $assoc) {
01195 if (!empty($assoc)) {
01196 if (is_array($query)) {
01197 return array_merge((array)$assoc, $query);
01198 } else {
01199 if (!empty($query)) {
01200 $query = array($query);
01201 if (is_array($assoc)) {
01202 $query = array_merge($query, $assoc);
01203 } else {
01204 $query[] = $assoc;
01205 }
01206 return $query;
01207 } else {
01208 return $assoc;
01209 }
01210 }
01211 }
01212 return $query;
01213 }
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223 function update(&$model, $fields = array(), $values = null, $conditions = null) {
01224 $updates = array();
01225
01226 if ($values == null) {
01227 $combined = $fields;
01228 } else {
01229 $combined = array_combine($fields, $values);
01230 }
01231
01232 foreach ($combined as $field => $value) {
01233 if ($value === null) {
01234 $updates[] = $this->name($field) . ' = NULL';
01235 } else {
01236 $update = $this->name($field) . ' = ';
01237 if ($conditions == null) {
01238 $update .= $this->value($value, $model->getColumnType($field));
01239 } else {
01240 $update .= $value;
01241 }
01242 $updates[] = $update;
01243 }
01244 }
01245 $conditions = $this->defaultConditions($model, $conditions);
01246
01247 if ($conditions === false) {
01248 return false;
01249 }
01250
01251 $fields = join(',', $updates);
01252 $table = $this->fullTableName($model);
01253
01254 $conditions = $this->conditions($conditions);
01255
01256 if (!$this->execute("UPDATE {$table} SET {$fields} {$conditions}")) {
01257 $model->onError();
01258 return false;
01259 }
01260 return true;
01261 }
01262
01263
01264
01265
01266
01267
01268
01269 function delete(&$model, $conditions = null) {
01270 $query = $this->defaultConditions($model, $conditions);
01271
01272 if ($query === false) {
01273 return false;
01274 }
01275
01276 $table = $this->fullTableName($model);
01277 $conditions = $this->conditions($query);
01278
01279 if ($this->execute("DELETE FROM {$table} {$conditions}") === false) {
01280 $model->onError();
01281 return false;
01282 }
01283 return true;
01284 }
01285
01286
01287
01288
01289
01290
01291
01292 function defaultConditions(&$model, $conditions) {
01293 if (!empty($conditions)) {
01294 return $conditions;
01295 }
01296 if (!$model->exists()) {
01297 return false;
01298 }
01299 return array($model->primaryKey => (array)$model->getID());
01300 }
01301
01302
01303
01304
01305
01306
01307
01308
01309 function resolveKey($model, $key, $assoc = null) {
01310 if (empty($assoc)) {
01311 $assoc = $model->alias;
01312 }
01313 if (!strpos('.', $key)) {
01314 return $this->name($model->alias) . '.' . $this->name($key);
01315 }
01316 return $key;
01317 }
01318
01319
01320
01321
01322
01323
01324 function getColumnType(&$model, $field) {
01325 return $model->getColumnType($field);
01326 }
01327
01328
01329
01330
01331
01332 function __scrubQueryData(&$data) {
01333 foreach (array('conditions', 'fields', 'joins', 'order', 'limit', 'offset') as $key) {
01334 if (!isset($data[$key]) || empty($data[$key])) {
01335 $data[$key] = array();
01336 }
01337 }
01338 }
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348 function fields(&$model, $alias = null, $fields = array(), $quote = true) {
01349 if (empty($alias)) {
01350 $alias = $model->alias;
01351 }
01352
01353 if (!is_array($fields)) {
01354 if (!empty($fields)) {
01355 $depth = 0;
01356 $offset = 0;
01357 $buffer = '';
01358 $results = array();
01359 $length = strlen($fields);
01360
01361 while ($offset <= $length) {
01362 $tmpOffset = -1;
01363 $offsets = array(strpos($fields, ',', $offset), strpos($fields, '(', $offset), strpos($fields, ')', $offset));
01364 for ($i = 0; $i < 3; $i++) {
01365 if ($offsets[$i] !== false && ($offsets[$i] < $tmpOffset || $tmpOffset == -1)) {
01366 $tmpOffset = $offsets[$i];
01367 }
01368 }
01369 if ($tmpOffset !== -1) {
01370 $buffer .= substr($fields, $offset, ($tmpOffset - $offset));
01371 if ($fields{$tmpOffset} == ',' && $depth == 0) {
01372 $results[] = $buffer;
01373 $buffer = '';
01374 } else {
01375 $buffer .= $fields{$tmpOffset};
01376 }
01377 if ($fields{$tmpOffset} == '(') {
01378 $depth++;
01379 }
01380 if ($fields{$tmpOffset} == ')') {
01381 $depth--;
01382 }
01383 $offset = ++$tmpOffset;
01384 } else {
01385 $results[] = $buffer . substr($fields, $offset);
01386 $offset = $length + 1;
01387 }
01388 }
01389 if (empty($results) && !empty($buffer)) {
01390 $results[] = $buffer;
01391 }
01392
01393 if (!empty($results)) {
01394 $fields = array_map('trim', $results);
01395 } else {
01396 $fields = array();
01397 }
01398 }
01399 }
01400 if (empty($fields)) {
01401 $fieldData = $model->loadInfo();
01402 $fields = $fieldData->extract('{n}.name');
01403 } else {
01404 $fields = array_filter($fields);
01405 }
01406
01407 if (!$quote) {
01408 return $fields;
01409 }
01410 $count = count($fields);
01411
01412 if ($count >= 1 && !in_array($fields[0], array('*', 'COUNT(*)'))) {
01413 for ($i = 0; $i < $count; $i++) {
01414 if (!preg_match('/^.+\\(.*\\)/', $fields[$i])) {
01415 $prepend = '';
01416
01417 if (strpos($fields[$i], 'DISTINCT') !== false) {
01418 $prepend = 'DISTINCT ';
01419 $fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i]));
01420 }
01421 $dot = strpos($fields[$i], '.');
01422
01423 if ($dot === false) {
01424 $fields[$i] = $prepend . $this->name($alias) . '.' . $this->name($fields[$i]);
01425 } else {
01426 $comma = strpos($fields[$i], ',');
01427 if ($comma === false) {
01428 $build = explode('.', $fields[$i]);
01429 if (!Set::numeric($build)) {
01430 $fields[$i] = $prepend . $this->name($build[0]) . '.' . $this->name($build[1]);
01431 }
01432 } else {
01433 $comma = explode(',', $fields[$i]);
01434 foreach ($comma as $string) {
01435 $build = explode('.', $string);
01436 if (!Set::numeric($build)) {
01437 $value[] = $prepend . $this->name(trim($build[0])) . '.' . $this->name(trim($build[1]));
01438 }
01439 }
01440 $fields[$i] = implode(', ', $value);
01441 }
01442 }
01443 } elseif (preg_match('/\(([\.\w]+)\)/', $fields[$i], $field)) {
01444 if (isset($field[1])) {
01445 if (strpos($field[1], '.') === false) {
01446 $field[1] = $this->name($alias) . '.' . $this->name($field[1]);
01447 } else {
01448 $field[0] = explode('.', $field[1]);
01449 if (!Set::numeric($field[0])) {
01450 $field[0] = join('.', array_map(array($this, 'name'), $field[0]));
01451 $fields[$i] = preg_replace('/\(' . $field[1] . '\)/', '(' . $field[0] . ')', $fields[$i], 1);
01452 }
01453 }
01454 }
01455 }
01456 }
01457 }
01458 return $fields;
01459 }
01460
01461
01462
01463
01464
01465
01466 function conditions($conditions, $quoteValues = true, $where = true) {
01467 $clause = $out = '';
01468 if (is_string($conditions) || empty($conditions) || $conditions === true) {
01469 if (empty($conditions) || trim($conditions) == '' || $conditions === true) {
01470 if ($where) {
01471 return ' WHERE 1 = 1';
01472 }
01473 return '1 = 1';
01474 }
01475 if (!preg_match('/^WHERE\\x20|^GROUP\\x20BY\\x20|^HAVING\\x20|^ORDER\\x20BY\\x20/i', $conditions, $match)) {
01476 if ($where) {
01477 $clause = ' WHERE ';
01478 }
01479 }
01480 if (trim($conditions) == '') {
01481 $conditions = ' 1 = 1';
01482 } else {
01483 $conditions = $this->__quoteFields($conditions);
01484 }
01485 return $clause . $conditions;
01486 } else {
01487 if ($where) {
01488 $clause = ' WHERE ';
01489 }
01490 if (!empty($conditions)) {
01491 $out = $this->conditionKeysToString($conditions, $quoteValues);
01492 }
01493 if (empty($out) || empty($conditions)) {
01494 return $clause . ' 1 = 1';
01495 }
01496 return $clause . join(' AND ', $out);
01497 }
01498 }
01499
01500
01501
01502
01503
01504
01505 function conditionKeysToString($conditions, $quoteValues = true) {
01506 $c = 0;
01507 $data = $not = null;
01508 $out = array();
01509 $bool = array('and', 'or', 'not', 'and not', 'or not', 'xor', '||', '&&');
01510 $join = ' AND ';
01511
01512 foreach ($conditions as $key => $value) {
01513 if (is_numeric($key) && empty($value)) {
01514 continue;
01515 } elseif (is_numeric($key) && is_string($value)) {
01516 $out[] = $not . $this->__quoteFields($value);
01517 } elseif (in_array(strtolower(trim($key)), $bool)) {
01518 $join = ' ' . strtoupper($key) . ' ';
01519 $value = $this->conditionKeysToString($value, $quoteValues);
01520 if (strpos($join, 'NOT') !== false) {
01521 if (strtoupper(trim($key)) == 'NOT') {
01522 $key = 'AND ' . $key;
01523 }
01524 $not = 'NOT ';
01525 } else {
01526 $not = null;
01527 }
01528 $out[] = $not . '((' . join(') ' . strtoupper($key) . ' (', $value) . '))';
01529 } else {
01530 if (is_string($value) && preg_match('/^\{\$__cakeIdentifier\[(.*)\]__\$}$/', $value, $identifier) && isset($identifier[1])) {
01531 $data .= $this->name($key) . ' = ' . $this->name($identifier[1]);
01532 } elseif (is_array($value) && !empty($value)) {
01533 $keys = array_keys($value);
01534 if ($keys[0] === 0) {
01535 $data = $this->name($key) . ' IN (';
01536 if (strpos($value[0], '-!') === 0) {
01537 $value[0] = str_replace('-!', '', $value[0]);
01538 $data .= $value[0];
01539 $data .= ')';
01540 } else {
01541 if ($quoteValues) {
01542 foreach ($value as $valElement) {
01543 $data .= $this->value($valElement) . ', ';
01544 }
01545 }
01546 $data[strlen($data) - 2] = ')';
01547 }
01548 } else {
01549 $ret = $this->conditionKeysToString($value, $quoteValues);
01550 if (count($ret) > 1) {
01551 $out[] = '(' . join(') AND (', $ret) . ')';
01552 } elseif (isset($ret[0])) {
01553 $out[] = $ret[0];
01554 }
01555 }
01556 } elseif (is_numeric($key) && !empty($value)) {
01557 $data = $this->__quoteFields($value);
01558 } elseif ($value === null || (is_array($value) && empty($value))) {
01559 $data = $this->name($key) . ' IS NULL';
01560 } elseif ($value === false || $value === true) {
01561 $data = $this->name($key) . " = " . $this->value($value, 'boolean');
01562 } elseif ($value === '') {
01563 $data = $this->name($key) . " = ''";
01564 } elseif (preg_match('/^([a-z]+\\([a-z0-9]*\\)\\x20+|(?:' . join('\\x20)|(?:', $this->__sqlOps) . '\\x20)|<[>=]?(?![^>]+>)\\x20?|[>=!]{1,3}(?!<)\\x20?)?(.*)/is', $value, $match)) {
01565 if (preg_match('/(\\x20[\\w]*\\x20)/', $key, $regs)) {
01566 $clause = $regs['1'];
01567 $key = preg_replace('/' . $regs['1'] . '/', '', $key);
01568 }
01569
01570 $not = false;
01571 $mValue = trim($match['1']);
01572 if (empty($match['1'])) {
01573 $match['1'] = ' = ';
01574 } elseif (empty($mValue)) {
01575 $match['1'] = ' = ';
01576 $match['2'] = $match['0'];
01577 } elseif (!isset($match['2'])) {
01578 $match['1'] = ' = ';
01579 $match['2'] = $match['0'];
01580 } elseif (strtolower($mValue) == 'not') {
01581 $not = $this->conditionKeysToString(array($mValue => array($key => $match[2])), $quoteValues);
01582 }
01583
01584 if ($not) {
01585 $data = $not[0];
01586 } elseif (strpos($match['2'], '-!') === 0) {
01587 $match['2'] = str_replace('-!', '', $match['2']);
01588 $data = $this->name($key) . ' ' . $match['1'] . ' ' . $match['2'];
01589 } else {
01590 if (!empty($match['2']) && $quoteValues) {
01591 if (!preg_match('/[A-Za-z]+\\([a-z0-9]*\\),?\\x20+/', $match['2'])) {
01592 $match['2'] = $this->value($match['2']);
01593 }
01594 $match['2'] = str_replace(' AND ', "' AND '", $match['2']);
01595 }
01596 $data = $this->__quoteFields($key);
01597 if ($data === $key) {
01598 $data = $this->name($key) . ' ' . $match['1'] . ' ' . $match['2'];
01599 } else {
01600 $data = $data . ' ' . $match['1'] . ' ' . $match['2'];
01601 }
01602 }
01603 }
01604
01605 if ($data != null) {
01606 $out[] = $data;
01607 $data = null;
01608 }
01609 }
01610 $c++;
01611 }
01612 return $out;
01613 }
01614
01615
01616
01617
01618
01619
01620
01621 function __quoteFields($conditions) {
01622 $start = null;
01623 $end = null;
01624 $original = $conditions;
01625
01626 if (!empty($this->startQuote)) {
01627 $start = preg_quote($this->startQuote);
01628 }
01629
01630 if (!empty($this->endQuote)) {
01631 $end = preg_quote($this->endQuote);
01632 }
01633 $conditions = str_replace(array($start, $end), '', $conditions);
01634 preg_match_all('/(?:[\'\"][^\'\"\\\]*(?:\\\.[^\'\"\\\]*)*[\'\"])|([a-z0-9_' . $start . $end . ']*\\.[a-z0-9_' . $start . $end . ']*)/i', $conditions, $replace, PREG_PATTERN_ORDER);
01635
01636 if (isset($replace['1']['0'])) {
01637 $pregCount = count($replace['1']);
01638
01639 for ($i = 0; $i < $pregCount; $i++) {
01640 if (!empty($replace['1'][$i]) && !is_numeric($replace['1'][$i])) {
01641 $conditions = preg_replace('/\b' . preg_quote($replace['1'][$i]) . '\b/', $this->name($replace['1'][$i]), $conditions);
01642 }
01643 }
01644 return $conditions;
01645 }
01646 return $original;
01647 }
01648
01649
01650
01651
01652
01653
01654
01655 function limit($limit, $offset = null) {
01656 if ($limit) {
01657 $rt = '';
01658 if (!strpos(strtolower($limit), 'limit') || strpos(strtolower($limit), 'limit') === 0) {
01659 $rt = ' LIMIT';
01660 }
01661
01662 if ($offset) {
01663 $rt .= ' ' . $offset . ',';
01664 }
01665
01666 $rt .= ' ' . $limit;
01667 return $rt;
01668 }
01669 return null;
01670 }
01671
01672
01673
01674
01675
01676
01677
01678 function order($keys, $direction = 'ASC') {
01679 if (is_string($keys) && strpos($keys, ',') && !preg_match('/\(.+\,.+\)/', $keys)) {
01680 $keys = explode(',', $keys);
01681 array_map('trim', $keys);
01682 }
01683
01684 if (is_array($keys)) {
01685 foreach ($keys as $key => $val) {
01686 if (is_numeric($key) && empty($val)) {
01687 unset ($keys[$key]);
01688 }
01689 }
01690 }
01691
01692 if (empty($keys) || (is_array($keys) && count($keys) && isset($keys[0]) && empty($keys[0]))) {
01693 return '';
01694 }
01695
01696 if (is_array($keys)) {
01697 if (Set::countDim($keys) > 1) {
01698 $new = array();
01699
01700 foreach ($keys as $val) {
01701 $val = $this->order($val);
01702 $new[] = $val;
01703 }
01704
01705 $keys = $new;
01706 }
01707
01708 foreach ($keys as $key => $value) {
01709 if (is_numeric($key)) {
01710 $value = ltrim(str_replace('ORDER BY ', '', $this->order($value)));
01711 $key = $value;
01712
01713 if (!preg_match('/\\x20ASC|\\x20DESC/i', $key)) {
01714 $value = ' ' . $direction;
01715 } else {
01716 $value = '';
01717 }
01718 } else {
01719 $value = ' ' . $value;
01720 }
01721
01722 if (!preg_match('/^.+\\(.*\\)/', $key) && !strpos($key, ',')) {
01723 $dir = '';
01724 $hasDir = preg_match('/\\x20ASC|\\x20DESC/i', $key, $dir);
01725
01726 if ($hasDir) {
01727 $dir = $dir[0];
01728 $key = preg_replace('/\\x20ASC|\\x20DESC/i', '', $key);
01729 } else {
01730 $dir = '';
01731 }
01732 $key = trim($this->name(trim($key)) . ' ' . trim($dir));
01733 }
01734 $order[] = $this->order($key . $value);
01735 }
01736
01737 return ' ORDER BY ' . trim(str_replace('ORDER BY', '', join(',', $order)));
01738 } else {
01739 $keys = preg_replace('/ORDER\\x20BY/i', '', $keys);
01740
01741 if (strpos($keys, '.')) {
01742 preg_match_all('/([a-zA-Z0-9_]{1,})\\.([a-zA-Z0-9_]{1,})/', $keys, $result,
01743 PREG_PATTERN_ORDER);
01744 $pregCount = count($result['0']);
01745
01746 for ($i = 0; $i < $pregCount; $i++) {
01747 $keys = preg_replace('/' . $result['0'][$i] . '/', $this->name($result['0'][$i]), $keys);
01748 }
01749
01750 if (preg_match('/\\x20ASC|\\x20DESC/i', $keys)) {
01751 return ' ORDER BY ' . $keys;
01752 } else {
01753 return ' ORDER BY ' . $keys . ' ' . $direction;
01754 }
01755 } elseif (preg_match('/(\\x20ASC|\\x20DESC)/i', $keys, $match)) {
01756 $direction = $match['1'];
01757 $keys = preg_replace('/' . $match['1'] . '/', '', $keys);
01758 return ' ORDER BY ' . $keys . $direction;
01759 } else {
01760 $direction = ' ' . $direction;
01761 }
01762 return ' ORDER BY ' . $keys . $direction;
01763 }
01764 }
01765
01766
01767
01768
01769
01770 function close() {
01771 if (Configure::read() > 1) {
01772 $this->showLog();
01773 }
01774 $this->disconnect();
01775 }
01776
01777
01778
01779
01780
01781
01782
01783 function hasAny($model, $sql) {
01784 $sql = $this->conditions($sql);
01785 $out = $this->fetchRow("SELECT COUNT(" . $model->primaryKey . ") " . $this->alias . "count FROM " . $this->fullTableName($model) . ' ' . ($sql ? ' ' . $sql : 'WHERE 1 = 1'));
01786
01787 if (is_array($out)) {
01788 return $out[0]['count'];
01789 }
01790 return false;
01791 }
01792
01793
01794
01795
01796
01797
01798 function length($real) {
01799 $col = str_replace(array(')', 'unsigned'), '', $real);
01800 $limit = null;
01801
01802 if (strpos($col, '(') !== false) {
01803 list($col, $limit) = explode('(', $col);
01804 }
01805
01806 if ($limit != null) {
01807 return intval($limit);
01808 }
01809 return null;
01810 }
01811
01812
01813
01814
01815
01816
01817 function boolean($data) {
01818 if ($data === true || $data === false) {
01819 if ($data === true) {
01820 return 1;
01821 }
01822 return 0;
01823 }
01824
01825 if (!empty($data)) {
01826 return true;
01827 }
01828 return false;
01829 }
01830
01831
01832
01833
01834 function __destruct() {
01835 if ($this->_transactionStarted) {
01836 $null = null;
01837 $this->rollback($null);
01838 }
01839 parent::__destruct();
01840 }
01841
01842
01843
01844
01845
01846
01847
01848 function insertMulti($table, $fields, $values) {
01849 $values = implode(', ', $values);
01850 $this->query("INSERT INTO {$table} ({$fields}) VALUES {$values}");
01851 }
01852
01853
01854
01855
01856
01857
01858 function index($model) {
01859 return false;
01860 }
01861
01862
01863
01864
01865
01866
01867
01868
01869 function createSchema($schema, $table = null) {
01870 return false;
01871 }
01872
01873
01874
01875
01876
01877
01878 function alterSchema($compare, $table = null) {
01879 return false;
01880 }
01881
01882
01883
01884
01885
01886
01887
01888
01889 function dropSchema($schema, $table = null) {
01890 return false;
01891 }
01892
01893
01894
01895
01896
01897
01898
01899 function buildColumn($column) {
01900 return false;
01901 }
01902
01903
01904
01905
01906
01907
01908 function buildIndex($indexes) {
01909 return false;
01910 }
01911
01912
01913
01914
01915
01916
01917
01918 function introspectType($value) {
01919 if (!is_array($value)) {
01920 if ($value === true || $value === false) {
01921 return 'boolean';
01922 }
01923 if (is_float($value) && floatval($value) === $value) {
01924 return 'float';
01925 }
01926 if (is_int($value) && intval($value) === $value) {
01927 return 'integer';
01928 }
01929 if (is_string($value) && strlen($value) > 255) {
01930 return 'text';
01931 }
01932 return 'string';
01933 }
01934
01935 $isAllFloat = $isAllInt = true;
01936 $containsFloat = $containsInt = $containsString = false;
01937 foreach ($value as $key => $valElement) {
01938 $valElement = trim($valElement);
01939 if (!is_float($valElement) && !preg_match('/^[\d]+\.[\d]+$/', $valElement)) {
01940 $isAllFloat = false;
01941 } else {
01942 $containsFloat = true;
01943 continue;
01944 }
01945 if (!is_int($valElement) && !preg_match('/^[\d]+$/', $valElement)) {
01946 $isAllInt = false;
01947 } else {
01948 $containsInt = true;
01949 continue;
01950 }
01951 $containsString = true;
01952 }
01953
01954 if ($isAllFloat) {
01955 return 'float';
01956 }
01957 if ($isAllInt) {
01958 return 'integer';
01959 }
01960
01961 if ($containsInt && !$containsString) {
01962 return 'integer';
01963 }
01964 return 'string';
01965 }
01966 }
01967 ?>