PageRenderTime 75ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/cake/cake/libs/model/datasources/dbo/dbo_adodb.php

https://github.com/geeknbar/projet-tut-site-web
PHP | 525 lines | 299 code | 30 blank | 196 comment | 80 complexity | f077894f5328aa1dccc9ad77c90bc544 MD5 | raw file
  1. <?php
  2. /* SVN FILE: $Id$ */
  3. /**
  4. * AdoDB layer for DBO.
  5. *
  6. * Long description for file
  7. *
  8. * PHP versions 4 and 5
  9. *
  10. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  11. * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
  12. *
  13. * Licensed under The MIT License
  14. * Redistributions of files must retain the above copyright notice.
  15. *
  16. * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
  17. * @link http://cakephp.org CakePHP(tm) Project
  18. * @package cake
  19. * @subpackage cake.cake.libs.model.datasources.dbo
  20. * @since CakePHP(tm) v 0.2.9
  21. * @version $Revision$
  22. * @modifiedby $LastChangedBy$
  23. * @lastmodified $Date$
  24. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  25. */
  26. /**
  27. * Include AdoDB files.
  28. */
  29. App::import('Vendor', 'NewADOConnection', array('file' => 'adodb' . DS . 'adodb.inc.php'));
  30. /**
  31. * AdoDB DBO implementation.
  32. *
  33. * Database abstraction implementation for the AdoDB library.
  34. *
  35. * @package cake
  36. * @subpackage cake.cake.libs.model.datasources.dbo
  37. */
  38. class DboAdodb extends DboSource {
  39. /**
  40. * Enter description here...
  41. *
  42. * @var string
  43. */
  44. var $description = "ADOdb DBO Driver";
  45. /**
  46. * ADOConnection object with which we connect.
  47. *
  48. * @var ADOConnection The connection object.
  49. * @access private
  50. */
  51. var $_adodb = null;
  52. /**
  53. * Array translating ADOdb column MetaTypes to cake-supported metatypes
  54. *
  55. * @var array
  56. * @access private
  57. */
  58. var $_adodbColumnTypes = array(
  59. 'string' => 'C',
  60. 'text' => 'X',
  61. 'date' => 'D',
  62. 'timestamp' => 'T',
  63. 'time' => 'T',
  64. 'datetime' => 'T',
  65. 'boolean' => 'L',
  66. 'float' => 'N',
  67. 'integer' => 'I',
  68. 'binary' => 'R',
  69. );
  70. /**
  71. * ADOdb column definition
  72. *
  73. * @var array
  74. */
  75. var $columns = array(
  76. 'primary_key' => array('name' => 'R', 'limit' => 11),
  77. 'string' => array('name' => 'C', 'limit' => '255'),
  78. 'text' => array('name' => 'X'),
  79. 'integer' => array('name' => 'I', 'limit' => '11', 'formatter' => 'intval'),
  80. 'float' => array('name' => 'N', 'formatter' => 'floatval'),
  81. 'timestamp' => array('name' => 'T', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
  82. 'time' => array('name' => 'T', 'format' => 'H:i:s', 'formatter' => 'date'),
  83. 'datetime' => array('name' => 'T', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
  84. 'date' => array('name' => 'D', 'format' => 'Y-m-d', 'formatter' => 'date'),
  85. 'binary' => array('name' => 'B'),
  86. 'boolean' => array('name' => 'L', 'limit' => '1')
  87. );
  88. /**
  89. * Connects to the database using options in the given configuration array.
  90. *
  91. * @param array $config Configuration array for connecting
  92. */
  93. function connect() {
  94. $config = $this->config;
  95. $persistent = strrpos($config['connect'], '|p');
  96. if ($persistent === false) {
  97. $adodb_driver = $config['connect'];
  98. $connect = 'Connect';
  99. } else {
  100. $adodb_driver = substr($config['connect'], 0, $persistent);
  101. $connect = 'PConnect';
  102. }
  103. if (!$this->enabled()) {
  104. return false;
  105. }
  106. $this->_adodb = NewADOConnection($adodb_driver);
  107. $this->_adodbDataDict = NewDataDictionary($this->_adodb, $adodb_driver);
  108. $this->startQuote = $this->_adodb->nameQuote;
  109. $this->endQuote = $this->_adodb->nameQuote;
  110. $this->connected = $this->_adodb->$connect($config['host'], $config['login'], $config['password'], $config['database']);
  111. $this->_adodbMetatyper = &$this->_adodb->execute('Select 1');
  112. return $this->connected;
  113. }
  114. /**
  115. * Check that AdoDB is available.
  116. *
  117. * @return boolean
  118. **/
  119. function enabled() {
  120. return function_exists('NewADOConnection');
  121. }
  122. /**
  123. * Disconnects from database.
  124. *
  125. * @return boolean True if the database could be disconnected, else false
  126. */
  127. function disconnect() {
  128. return $this->_adodb->Close();
  129. }
  130. /**
  131. * Executes given SQL statement.
  132. *
  133. * @param string $sql SQL statement
  134. * @return resource Result resource identifier
  135. */
  136. function _execute($sql) {
  137. global $ADODB_FETCH_MODE;
  138. $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
  139. return $this->_adodb->execute($sql);
  140. }
  141. /**
  142. * Returns a row from current resultset as an array .
  143. *
  144. * @return array The fetched row as an array
  145. */
  146. function fetchRow($sql = null) {
  147. if (!empty($sql) && is_string($sql) && strlen($sql) > 5) {
  148. if (!$this->execute($sql)) {
  149. return null;
  150. }
  151. }
  152. if (!$this->hasResult()) {
  153. return null;
  154. } else {
  155. $resultRow = $this->_result->FetchRow();
  156. $this->resultSet($resultRow);
  157. return $this->fetchResult();
  158. }
  159. }
  160. /**
  161. * Begin a transaction
  162. *
  163. * @param unknown_type $model
  164. * @return boolean True on success, false on fail
  165. * (i.e. if the database/model does not support transactions).
  166. */
  167. function begin(&$model) {
  168. if (parent::begin($model)) {
  169. if ($this->_adodb->BeginTrans()) {
  170. $this->_transactionStarted = true;
  171. return true;
  172. }
  173. }
  174. return false;
  175. }
  176. /**
  177. * Commit a transaction
  178. *
  179. * @param unknown_type $model
  180. * @return boolean True on success, false on fail
  181. * (i.e. if the database/model does not support transactions,
  182. * or a transaction has not started).
  183. */
  184. function commit(&$model) {
  185. if (parent::commit($model)) {
  186. $this->_transactionStarted = false;
  187. return $this->_adodb->CommitTrans();
  188. }
  189. return false;
  190. }
  191. /**
  192. * Rollback a transaction
  193. *
  194. * @param unknown_type $model
  195. * @return boolean True on success, false on fail
  196. * (i.e. if the database/model does not support transactions,
  197. * or a transaction has not started).
  198. */
  199. function rollback(&$model) {
  200. if (parent::rollback($model)) {
  201. return $this->_adodb->RollbackTrans();
  202. }
  203. return false;
  204. }
  205. /**
  206. * Returns an array of tables in the database. If there are no tables, an error is raised and the application exits.
  207. *
  208. * @return array Array of tablenames in the database
  209. */
  210. function listSources() {
  211. $tables = $this->_adodb->MetaTables('TABLES');
  212. if (!count($tables) > 0) {
  213. trigger_error(ERROR_NO_TABLE_LIST, E_USER_NOTICE);
  214. exit;
  215. }
  216. return $tables;
  217. }
  218. /**
  219. * Returns an array of the fields in the table used by the given model.
  220. *
  221. * @param AppModel $model Model object
  222. * @return array Fields in table. Keys are name and type
  223. */
  224. function describe(&$model) {
  225. $cache = parent::describe($model);
  226. if ($cache != null) {
  227. return $cache;
  228. }
  229. $fields = false;
  230. $cols = $this->_adodb->MetaColumns($this->fullTableName($model, false));
  231. foreach ($cols as $column) {
  232. $fields[$column->name] = array(
  233. 'type' => $this->column($column->type),
  234. 'null' => !$column->not_null,
  235. 'length' => $column->max_length,
  236. );
  237. if ($column->has_default) {
  238. $fields[$column->name]['default'] = $column->default_value;
  239. }
  240. if ($column->primary_key == 1) {
  241. $fields[$column->name]['key'] = 'primary';
  242. }
  243. }
  244. $this->__cacheDescription($this->fullTableName($model, false), $fields);
  245. return $fields;
  246. }
  247. /**
  248. * Returns a formatted error message from previous database operation.
  249. *
  250. * @return string Error message
  251. */
  252. function lastError() {
  253. return $this->_adodb->ErrorMsg();
  254. }
  255. /**
  256. * Returns number of affected rows in previous database operation, or false if no previous operation exists.
  257. *
  258. * @return integer Number of affected rows
  259. */
  260. function lastAffected() {
  261. return $this->_adodb->Affected_Rows();
  262. }
  263. /**
  264. * Returns number of rows in previous resultset, or false if no previous resultset exists.
  265. *
  266. * @return integer Number of rows in resultset
  267. */
  268. function lastNumRows() {
  269. return $this->_result ? $this->_result->RecordCount() : false;
  270. }
  271. /**
  272. * Returns the ID generated from the previous INSERT operation.
  273. *
  274. * @return int
  275. *
  276. * @Returns the last autonumbering ID inserted. Returns false if function not supported.
  277. */
  278. function lastInsertId() {
  279. return $this->_adodb->Insert_ID();
  280. }
  281. /**
  282. * Returns a LIMIT statement in the correct format for the particular database.
  283. *
  284. * @param integer $limit Limit of results returned
  285. * @param integer $offset Offset from which to start results
  286. * @return string SQL limit/offset statement
  287. * @todo Please change output string to whatever select your database accepts. adodb doesn't allow us to get the correct limit string out of it.
  288. */
  289. function limit($limit, $offset = null) {
  290. if ($limit) {
  291. $rt = '';
  292. if (!strpos(strtolower($limit), 'limit') || strpos(strtolower($limit), 'limit') === 0) {
  293. $rt = ' LIMIT';
  294. }
  295. if ($offset) {
  296. $rt .= ' ' . $offset . ',';
  297. }
  298. $rt .= ' ' . $limit;
  299. return $rt;
  300. }
  301. return null;
  302. // please change to whatever select your database accepts
  303. // adodb doesn't allow us to get the correct limit string out of it
  304. }
  305. /**
  306. * Converts database-layer column types to basic types
  307. *
  308. * @param string $real Real database-layer column type (i.e. "varchar(255)")
  309. * @return string Abstract column type (i.e. "string")
  310. */
  311. function column($real) {
  312. $metaTypes = array_flip($this->_adodbColumnTypes);
  313. $interpreted_type = $this->_adodbMetatyper->MetaType($real);
  314. if (!isset($metaTypes[$interpreted_type])) {
  315. return 'text';
  316. }
  317. return $metaTypes[$interpreted_type];
  318. }
  319. /**
  320. * Returns a quoted and escaped string of $data for use in an SQL statement.
  321. *
  322. * @param string $data String to be prepared for use in an SQL statement
  323. * @param string $column_type The type of the column into which this data will be inserted
  324. * @param boolean $safe Whether or not numeric data should be handled automagically if no column data is provided
  325. * @return string Quoted and escaped data
  326. */
  327. function value($data, $column = null, $safe = false) {
  328. $parent = parent::value($data, $column, $safe);
  329. if ($parent != null) {
  330. return $parent;
  331. }
  332. if ($data === null) {
  333. return 'NULL';
  334. }
  335. if ($data === '') {
  336. return "''";
  337. }
  338. return $this->_adodb->qstr($data);
  339. }
  340. /**
  341. * Generates the fields list of an SQL query.
  342. *
  343. * @param Model $model
  344. * @param string $alias Alias tablename
  345. * @param mixed $fields
  346. * @return array
  347. */
  348. function fields(&$model, $alias = null, $fields = array(), $quote = true) {
  349. if (empty($alias)) {
  350. $alias = $model->alias;
  351. }
  352. $fields = parent::fields($model, $alias, $fields, false);
  353. if (!$quote) {
  354. return $fields;
  355. }
  356. $count = count($fields);
  357. if ($count >= 1 && $fields[0] != '*' && strpos($fields[0], 'COUNT(*)') === false) {
  358. for ($i = 0; $i < $count; $i++) {
  359. if (!preg_match('/^.+\\(.*\\)/', $fields[$i]) && !preg_match('/\s+AS\s+/', $fields[$i])) {
  360. $prepend = '';
  361. if (strpos($fields[$i], 'DISTINCT') !== false) {
  362. $prepend = 'DISTINCT ';
  363. $fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i]));
  364. }
  365. if (strrpos($fields[$i], '.') === false) {
  366. $fields[$i] = $prepend . $this->name($alias) . '.' . $this->name($fields[$i]) . ' AS ' . $this->name($alias . '__' . $fields[$i]);
  367. } else {
  368. $build = explode('.', $fields[$i]);
  369. $fields[$i] = $prepend . $this->name($build[0]) . '.' . $this->name($build[1]) . ' AS ' . $this->name($build[0] . '__' . $build[1]);
  370. }
  371. }
  372. }
  373. }
  374. return $fields;
  375. }
  376. /**
  377. * Build ResultSets and map data
  378. *
  379. * @param array $results
  380. */
  381. function resultSet(&$results) {
  382. $num_fields = count($results);
  383. $fields = array_keys($results);
  384. $this->results =& $results;
  385. $this->map = array();
  386. $index = 0;
  387. $j = 0;
  388. while ($j < $num_fields) {
  389. $columnName = $fields[$j];
  390. if (strpos($columnName, '__')) {
  391. $parts = explode('__', $columnName);
  392. $this->map[$index++] = array($parts[0], $parts[1]);
  393. } else {
  394. $this->map[$index++] = array(0, $columnName);
  395. }
  396. $j++;
  397. }
  398. }
  399. /**
  400. * Fetches the next row from the current result set
  401. *
  402. * @return unknown
  403. */
  404. function fetchResult() {
  405. if (!empty($this->results)) {
  406. $row = $this->results;
  407. $this->results = null;
  408. } else {
  409. $row = $this->_result->FetchRow();
  410. }
  411. if (empty($row)) {
  412. return false;
  413. }
  414. $resultRow = array();
  415. $fields = array_keys($row);
  416. $count = count($fields);
  417. $i = 0;
  418. for ($i = 0; $i < $count; $i++) { //$row as $index => $field) {
  419. list($table, $column) = $this->map[$i];
  420. $resultRow[$table][$column] = $row[$fields[$i]];
  421. }
  422. return $resultRow;
  423. }
  424. /**
  425. * Generate a database-native column schema string
  426. *
  427. * @param array $column An array structured like the following: array('name'=>'value', 'type'=>'value'[, options]),
  428. * where options can be 'default', 'length', or 'key'.
  429. * @return string
  430. */
  431. function buildColumn($column) {
  432. $name = $type = null;
  433. extract(array_merge(array('null' => true), $column));
  434. if (empty($name) || empty($type)) {
  435. trigger_error('Column name or type not defined in schema', E_USER_WARNING);
  436. return null;
  437. }
  438. //$metaTypes = array_flip($this->_adodbColumnTypes);
  439. if (!isset($this->_adodbColumnTypes[$type])) {
  440. trigger_error("Column type {$type} does not exist", E_USER_WARNING);
  441. return null;
  442. }
  443. $metaType = $this->_adodbColumnTypes[$type];
  444. $concreteType = $this->_adodbDataDict->ActualType($metaType);
  445. $real = $this->columns[$type];
  446. //UUIDs are broken so fix them.
  447. if ($type == 'string' && isset($real['length']) && $real['length'] == 36) {
  448. $concreteType = 'CHAR';
  449. }
  450. $out = $this->name($name) . ' ' . $concreteType;
  451. if (isset($real['limit']) || isset($real['length']) || isset($column['limit']) || isset($column['length'])) {
  452. if (isset($column['length'])) {
  453. $length = $column['length'];
  454. } elseif (isset($column['limit'])) {
  455. $length = $column['limit'];
  456. } elseif (isset($real['length'])) {
  457. $length = $real['length'];
  458. } else {
  459. $length = $real['limit'];
  460. }
  461. $out .= '(' . $length . ')';
  462. }
  463. $_notNull = $_default = $_autoInc = $_constraint = $_unsigned = false;
  464. if (isset($column['key']) && $column['key'] == 'primary' && $type == 'integer') {
  465. $_constraint = '';
  466. $_autoInc = true;
  467. } elseif (isset($column['key']) && $column['key'] == 'primary') {
  468. $_notNull = '';
  469. } elseif (isset($column['default']) && isset($column['null']) && $column['null'] == false) {
  470. $_notNull = true;
  471. $_default = $column['default'];
  472. } elseif ( isset($column['null']) && $column['null'] == true) {
  473. $_notNull = false;
  474. $_default = 'NULL';
  475. }
  476. if (isset($column['default']) && $_default == false) {
  477. $_default = $this->value($column['default']);
  478. }
  479. if (isset($column['null']) && $column['null'] == false) {
  480. $_notNull = true;
  481. }
  482. //use concrete instance of DataDict to make the suffixes for us.
  483. $out .= $this->_adodbDataDict->_CreateSuffix($out, $metaType, $_notNull, $_default, $_autoInc, $_constraint, $_unsigned);
  484. return $out;
  485. }
  486. /**
  487. * Checks if the result is valid
  488. *
  489. * @return boolean True if the result is valid, else false
  490. */
  491. function hasResult() {
  492. return is_object($this->_result) && !$this->_result->EOF;
  493. }
  494. }
  495. ?>