comparison cake/libs/model/datasources/datasource.php @ 0:261e66bd5a0c

hg init
author Shoshi TAMAKI <shoshi@cr.ie.u-ryukyu.ac.jp>
date Sun, 24 Jul 2011 21:08:31 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:261e66bd5a0c
1 <?php
2 /**
3 * DataSource base class
4 *
5 * PHP versions 4 and 5
6 *
7 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
8 * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
9 *
10 * Licensed under The MIT License
11 * Redistributions of files must retain the above copyright notice.
12 *
13 * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
14 * @link http://cakephp.org CakePHP(tm) Project
15 * @package cake
16 * @subpackage cake.cake.libs.model.datasources
17 * @since CakePHP(tm) v 0.10.5.1790
18 * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
19 */
20
21 /**
22 * DataSource base class
23 *
24 * @package cake
25 * @subpackage cake.cake.libs.model.datasources
26 */
27 class DataSource extends Object {
28
29 /**
30 * Are we connected to the DataSource?
31 *
32 * @var boolean
33 * @access public
34 */
35 var $connected = false;
36
37 /**
38 * Print full query debug info?
39 *
40 * @var boolean
41 * @access public
42 */
43 var $fullDebug = false;
44
45 /**
46 * Error description of last query
47 *
48 * @var unknown_type
49 * @access public
50 */
51 var $error = null;
52
53 /**
54 * String to hold how many rows were affected by the last SQL operation.
55 *
56 * @var string
57 * @access public
58 */
59 var $affected = null;
60
61 /**
62 * Number of rows in current resultset
63 *
64 * @var int
65 * @access public
66 */
67 var $numRows = null;
68
69 /**
70 * Time the last query took
71 *
72 * @var int
73 * @access public
74 */
75 var $took = null;
76
77 /**
78 * The starting character that this DataSource uses for quoted identifiers.
79 *
80 * @var string
81 * @access public
82 */
83 var $startQuote = null;
84
85 /**
86 * The ending character that this DataSource uses for quoted identifiers.
87 *
88 * @var string
89 * @access public
90 */
91 var $endQuote = null;
92
93 /**
94 * Result
95 *
96 * @var array
97 * @access protected
98 */
99 var $_result = null;
100
101 /**
102 * Queries count.
103 *
104 * @var int
105 * @access protected
106 */
107 var $_queriesCnt = 0;
108
109 /**
110 * Total duration of all queries.
111 *
112 * @var unknown_type
113 * @access protected
114 */
115 var $_queriesTime = null;
116
117 /**
118 * Log of queries executed by this DataSource
119 *
120 * @var unknown_type
121 * @access protected
122 */
123 var $_queriesLog = array();
124
125 /**
126 * Maximum number of items in query log
127 *
128 * This is to prevent query log taking over too much memory.
129 *
130 * @var int Maximum number of queries in the queries log.
131 * @access protected
132 */
133 var $_queriesLogMax = 200;
134
135 /**
136 * Caches serialzed results of executed queries
137 *
138 * @var array Maximum number of queries in the queries log.
139 * @access protected
140 */
141 var $_queryCache = array();
142
143 /**
144 * The default configuration of a specific DataSource
145 *
146 * @var array
147 * @access protected
148 */
149 var $_baseConfig = array();
150
151 /**
152 * Holds references to descriptions loaded by the DataSource
153 *
154 * @var array
155 * @access private
156 */
157 var $__descriptions = array();
158
159 /**
160 * Holds a list of sources (tables) contained in the DataSource
161 *
162 * @var array
163 * @access protected
164 */
165 var $_sources = null;
166
167 /**
168 * A reference to the physical connection of this DataSource
169 *
170 * @var array
171 * @access public
172 */
173 var $connection = null;
174
175 /**
176 * The DataSource configuration
177 *
178 * @var array
179 * @access public
180 */
181 var $config = array();
182
183 /**
184 * The DataSource configuration key name
185 *
186 * @var string
187 * @access public
188 */
189 var $configKeyName = null;
190
191 /**
192 * Whether or not this DataSource is in the middle of a transaction
193 *
194 * @var boolean
195 * @access protected
196 */
197 var $_transactionStarted = false;
198
199 /**
200 * Whether or not source data like available tables and schema descriptions
201 * should be cached
202 *
203 * @var boolean
204 * @access public
205 */
206 var $cacheSources = true;
207
208 /**
209 * Constructor.
210 *
211 * @param array $config Array of configuration information for the datasource.
212 * @return void.
213 */
214 function __construct($config = array()) {
215 parent::__construct();
216 $this->setConfig($config);
217 }
218
219 /**
220 * Caches/returns cached results for child instances
221 *
222 * @param mixed $data
223 * @return array Array of sources available in this datasource.
224 * @access public
225 */
226 function listSources($data = null) {
227 if ($this->cacheSources === false) {
228 return null;
229 }
230
231 if ($this->_sources !== null) {
232 return $this->_sources;
233 }
234
235 $key = ConnectionManager::getSourceName($this) . '_' . $this->config['database'] . '_list';
236 $key = preg_replace('/[^A-Za-z0-9_\-.+]/', '_', $key);
237 $sources = Cache::read($key, '_cake_model_');
238
239 if (empty($sources)) {
240 $sources = $data;
241 Cache::write($key, $data, '_cake_model_');
242 }
243
244 $this->_sources = $sources;
245 return $sources;
246 }
247
248 /**
249 * Convenience method for DboSource::listSources(). Returns source names in lowercase.
250 *
251 * @param boolean $reset Whether or not the source list should be reset.
252 * @return array Array of sources available in this datasource
253 * @access public
254 */
255 function sources($reset = false) {
256 if ($reset === true) {
257 $this->_sources = null;
258 }
259 return array_map('strtolower', $this->listSources());
260 }
261
262 /**
263 * Returns a Model description (metadata) or null if none found.
264 *
265 * @param Model $model
266 * @return array Array of Metadata for the $model
267 * @access public
268 */
269 function describe(&$model) {
270 if ($this->cacheSources === false) {
271 return null;
272 }
273 $table = $model->tablePrefix . $model->table;
274
275 if (isset($this->__descriptions[$table])) {
276 return $this->__descriptions[$table];
277 }
278 $cache = $this->__cacheDescription($table);
279
280 if ($cache !== null) {
281 $this->__descriptions[$table] =& $cache;
282 return $cache;
283 }
284 return null;
285 }
286
287 /**
288 * Begin a transaction
289 *
290 * @return boolean Returns true if a transaction is not in progress
291 * @access public
292 */
293 function begin(&$model) {
294 return !$this->_transactionStarted;
295 }
296
297 /**
298 * Commit a transaction
299 *
300 * @return boolean Returns true if a transaction is in progress
301 * @access public
302 */
303 function commit(&$model) {
304 return $this->_transactionStarted;
305 }
306
307 /**
308 * Rollback a transaction
309 *
310 * @return boolean Returns true if a transaction is in progress
311 * @access public
312 */
313 function rollback(&$model) {
314 return $this->_transactionStarted;
315 }
316
317 /**
318 * Converts column types to basic types
319 *
320 * @param string $real Real column type (i.e. "varchar(255)")
321 * @return string Abstract column type (i.e. "string")
322 * @access public
323 */
324 function column($real) {
325 return false;
326 }
327
328 /**
329 * Used to create new records. The "C" CRUD.
330 *
331 * To-be-overridden in subclasses.
332 *
333 * @param Model $model The Model to be created.
334 * @param array $fields An Array of fields to be saved.
335 * @param array $values An Array of values to save.
336 * @return boolean success
337 * @access public
338 */
339 function create(&$model, $fields = null, $values = null) {
340 return false;
341 }
342
343 /**
344 * Used to read records from the Datasource. The "R" in CRUD
345 *
346 * To-be-overridden in subclasses.
347 *
348 * @param Model $model The model being read.
349 * @param array $queryData An array of query data used to find the data you want
350 * @return mixed
351 * @access public
352 */
353 function read(&$model, $queryData = array()) {
354 return false;
355 }
356
357 /**
358 * Update a record(s) in the datasource.
359 *
360 * To-be-overridden in subclasses.
361 *
362 * @param Model $model Instance of the model class being updated
363 * @param array $fields Array of fields to be updated
364 * @param array $values Array of values to be update $fields to.
365 * @return boolean Success
366 * @access public
367 */
368 function update(&$model, $fields = null, $values = null) {
369 return false;
370 }
371
372 /**
373 * Delete a record(s) in the datasource.
374 *
375 * To-be-overridden in subclasses.
376 *
377 * @param Model $model The model class having record(s) deleted
378 * @param mixed $id Primary key of the model
379 * @access public
380 */
381 function delete(&$model, $id = null) {
382 if ($id == null) {
383 $id = $model->id;
384 }
385 }
386
387 /**
388 * Returns the ID generated from the previous INSERT operation.
389 *
390 * @param unknown_type $source
391 * @return mixed Last ID key generated in previous INSERT
392 * @access public
393 */
394 function lastInsertId($source = null) {
395 return false;
396 }
397
398 /**
399 * Returns the number of rows returned by last operation.
400 *
401 * @param unknown_type $source
402 * @return integer Number of rows returned by last operation
403 * @access public
404 */
405 function lastNumRows($source = null) {
406 return false;
407 }
408
409 /**
410 * Returns the number of rows affected by last query.
411 *
412 * @param unknown_type $source
413 * @return integer Number of rows affected by last query.
414 * @access public
415 */
416 function lastAffected($source = null) {
417 return false;
418 }
419
420 /**
421 * Check whether the conditions for the Datasource being available
422 * are satisfied. Often used from connect() to check for support
423 * before establishing a connection.
424 *
425 * @return boolean Whether or not the Datasources conditions for use are met.
426 * @access public
427 */
428 function enabled() {
429 return true;
430 }
431
432 /**
433 * Returns true if the DataSource supports the given interface (method)
434 *
435 * @param string $interface The name of the interface (method)
436 * @return boolean True on success
437 * @access public
438 */
439 function isInterfaceSupported($interface) {
440 static $methods = false;
441 if ($methods === false) {
442 $methods = array_map('strtolower', get_class_methods($this));
443 }
444 return in_array(strtolower($interface), $methods);
445 }
446
447 /**
448 * Sets the configuration for the DataSource.
449 * Merges the $config information with the _baseConfig and the existing $config property.
450 *
451 * @param array $config The configuration array
452 * @return void
453 * @access public
454 */
455 function setConfig($config = array()) {
456 $this->config = array_merge($this->_baseConfig, $this->config, $config);
457 }
458
459 /**
460 * Cache the DataSource description
461 *
462 * @param string $object The name of the object (model) to cache
463 * @param mixed $data The description of the model, usually a string or array
464 * @return mixed
465 * @access private
466 */
467 function __cacheDescription($object, $data = null) {
468 if ($this->cacheSources === false) {
469 return null;
470 }
471
472 if ($data !== null) {
473 $this->__descriptions[$object] =& $data;
474 }
475
476 $key = ConnectionManager::getSourceName($this) . '_' . $object;
477 $cache = Cache::read($key, '_cake_model_');
478
479 if (empty($cache)) {
480 $cache = $data;
481 Cache::write($key, $cache, '_cake_model_');
482 }
483
484 return $cache;
485 }
486
487 /**
488 * Replaces `{$__cakeID__$}` and `{$__cakeForeignKey__$}` placeholders in query data.
489 *
490 * @param string $query Query string needing replacements done.
491 * @param array $data Array of data with values that will be inserted in placeholders.
492 * @param string $association Name of association model being replaced
493 * @param unknown_type $assocData
494 * @param Model $model Instance of the model to replace $__cakeID__$
495 * @param Model $linkModel Instance of model to replace $__cakeForeignKey__$
496 * @param array $stack
497 * @return string String of query data with placeholders replaced.
498 * @access public
499 * @todo Remove and refactor $assocData, ensure uses of the method have the param removed too.
500 */
501 function insertQueryData($query, $data, $association, $assocData, &$model, &$linkModel, $stack) {
502 $keys = array('{$__cakeID__$}', '{$__cakeForeignKey__$}');
503
504 foreach ($keys as $key) {
505 $val = null;
506 $type = null;
507
508 if (strpos($query, $key) !== false) {
509 switch ($key) {
510 case '{$__cakeID__$}':
511 if (isset($data[$model->alias]) || isset($data[$association])) {
512 if (isset($data[$model->alias][$model->primaryKey])) {
513 $val = $data[$model->alias][$model->primaryKey];
514 } elseif (isset($data[$association][$model->primaryKey])) {
515 $val = $data[$association][$model->primaryKey];
516 }
517 } else {
518 $found = false;
519 foreach (array_reverse($stack) as $assoc) {
520 if (isset($data[$assoc]) && isset($data[$assoc][$model->primaryKey])) {
521 $val = $data[$assoc][$model->primaryKey];
522 $found = true;
523 break;
524 }
525 }
526 if (!$found) {
527 $val = '';
528 }
529 }
530 $type = $model->getColumnType($model->primaryKey);
531 break;
532 case '{$__cakeForeignKey__$}':
533 foreach ($model->__associations as $id => $name) {
534 foreach ($model->$name as $assocName => $assoc) {
535 if ($assocName === $association) {
536 if (isset($assoc['foreignKey'])) {
537 $foreignKey = $assoc['foreignKey'];
538 $assocModel = $model->$assocName;
539 $type = $assocModel->getColumnType($assocModel->primaryKey);
540
541 if (isset($data[$model->alias][$foreignKey])) {
542 $val = $data[$model->alias][$foreignKey];
543 } elseif (isset($data[$association][$foreignKey])) {
544 $val = $data[$association][$foreignKey];
545 } else {
546 $found = false;
547 foreach (array_reverse($stack) as $assoc) {
548 if (isset($data[$assoc]) && isset($data[$assoc][$foreignKey])) {
549 $val = $data[$assoc][$foreignKey];
550 $found = true;
551 break;
552 }
553 }
554 if (!$found) {
555 $val = '';
556 }
557 }
558 }
559 break 3;
560 }
561 }
562 }
563 break;
564 }
565 if (empty($val) && $val !== '0') {
566 return false;
567 }
568 $query = str_replace($key, $this->value($val, $type), $query);
569 }
570 }
571 return $query;
572 }
573
574 /**
575 * To-be-overridden in subclasses.
576 *
577 * @param Model $model Model instance
578 * @param string $key Key name to make
579 * @return string Key name for model.
580 * @access public
581 */
582 function resolveKey(&$model, $key) {
583 return $model->alias . $key;
584 }
585
586 /**
587 * Closes the current datasource.
588 *
589 * @return void
590 * @access public
591 */
592 function __destruct() {
593 if ($this->_transactionStarted) {
594 $null = null;
595 $this->rollback($null);
596 }
597 if ($this->connected) {
598 $this->close();
599 }
600 }
601 }