2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4 // +----------------------------------------------------------------------+
5 // | Akelos Framework - http://www.akelos.org |
6 // +----------------------------------------------------------------------+
7 // | Copyright (c) 2002-2006, Akelos Media, S.L. & Bermi Ferrer Martinez |
8 // | Released under the GNU Lesser General Public License, see LICENSE.txt|
9 // +----------------------------------------------------------------------+
12 * @package ActiveRecord
14 * @component DbAdapter
15 * @author Bermi Ferrer <bermi a.t akelos c.om> 2004 - 2007
17 * @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org
18 * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html>
21 defined('AK_AVAILABLE_DATABASES') ?
null : define('AK_AVAILABLE_DATABASES', 'mysql,pgsql,sqlite');
23 require_once(AK_LIB_DIR
.DS
.'AkObject.php');
25 class AkDbAdapter
extends AkObject
35 * @param array $database_settings
37 function __construct($database_settings, $auto_connect = false)
39 $this->settings
= $database_settings;
44 $this->logger
=& Ak
::getLogger();
54 $dsn = $this->_constructDsn($this->settings
);
55 require_once(AK_CONTRIB_DIR
.DS
.'adodb'.DS
.'adodb.inc.php');
56 $this->connection
= AK_DEBUG ?
NewADOConnection($dsn) : @NewADOConnection
($dsn);
57 if (!$this->connection
){
58 error_reporting(E_ALL
);
59 if(defined('AK_DATABASE_CONNECTION_FAILURE_CALLBACK') && function_exists(AK_DATABASE_CONNECTION_FAILURE_CALLBACK
)){
60 $fn = AK_DATABASE_CONNECTION_FAILURE_CALLBACK
;
63 if(!AK_PHP5
&& $this->type() == 'sqlite'){
64 trigger_error(Ak
::t("\nWarning, sqlite support is not available by default on PHP4.\n Check your PHP version by running \"env php -v\", and change the first line in your scripts/ so they point to a php5 binary\n\n"),E_USER_WARNING
);
66 trigger_error(Ak
::t("Connection to the database failed. %dsn",
67 array('%dsn'=> AK_DEBUG ?
preg_replace('/\/\/(\w+):(.*)@/i','//$1:******@', urldecode($dsn))."\n" : '')),
70 $this->connection
->debug
= AK_DEBUG
== 2;
71 $this->connection
->SetFetchMode(ADODB_FETCH_ASSOC
);
72 defined('AK_DATABASE_CONNECTION_AVAILABLE') ?
null : define('AK_DATABASE_CONNECTION_AVAILABLE', true);
78 return !empty($this->connection
);
83 * @param array $database_settings
86 function &getInstance($database_specifications = AK_DEFAULT_DATABASE_PROFILE
, $auto_connect = true)
90 $settings_hash = is_string($database_specifications) ?
$database_specifications : AkDbAdapter
::_hash($database_specifications);
92 if (empty($connections[$settings_hash])){
93 global $database_settings;
94 if (is_string($database_specifications)){
95 if (!empty($database_settings[$database_specifications])){
96 $database_specifications = $database_settings[$database_specifications];
97 } elseif(strstr($database_specifications, '://')) {
98 $database_specifications = AkDbAdapter
::_getDbSettingsFromDsn($database_specifications);
99 $settings_hash = AK_ENVIRONMENT
;
101 trigger_error(Ak
::t("Could not find the database profile '%profile_name' in config/config.php.",array('%profile_name'=>$database_specifications)),E_USER_ERROR
);
105 }elseif (!empty($database_settings[$settings_hash])){
106 $database_specifications = $database_settings[$settings_hash];
109 $available_adapters = Ak
::toArray(AK_AVAILABLE_DATABASES
);
110 $class_name = 'AkDbAdapter';
111 $designated_database = strtolower($database_specifications['type']);
112 if (in_array($designated_database, $available_adapters)) {
113 $class_name = 'Ak'.ucfirst($designated_database).'DbAdapter';
114 require_once(AK_LIB_DIR
.DS
.'AkActiveRecord'.DS
.'AkDbAdapters'.DS
.$class_name.'.php');
116 $connections[$settings_hash] =& new $class_name($database_specifications,$auto_connect);
118 return $connections[$settings_hash];
122 * @param array $settings
125 function _hash($settings)
127 if(!is_array($settings)){
128 return AK_ENVIRONMENT
;
130 if (isset($settings['password'])){
131 unset($settings['password']);
133 return join(':',$settings);
136 function &getDictionary()
138 if (empty($this->dictionary
)){
139 if (!$this->connected()){
142 require_once(AK_CONTRIB_DIR
.DS
.'adodb'.DS
.'adodb.inc.php');
143 $this->dictionary
=& NewDataDictionary($this->connection
);
145 return $this->dictionary
;
149 * @param array $database_settings
152 function _constructDsn($database_settings)
154 if(is_string($database_settings)){
155 return $database_settings;
157 $dsn = $database_settings['type'].'://';
158 $dsn .= $database_settings['user'].':'.$database_settings['password'];
159 $dsn .= !empty($database_settings['host']) ?
'@'.$database_settings['host'] : '@localhost';
160 $dsn .= !empty($database_settings['port']) ?
':'.$database_settings['port'] : '';
161 $dsn .= '/'.$database_settings['database_name'];
162 $dsn .= !empty($database_settings['options']) ?
$database_settings['options'] : '';
167 function _getDbSettingsFromDsn($dsn)
169 $settings = $result = parse_url($dsn);
170 $result['type'] = $settings['scheme'];
171 $result['password'] = $settings['pass'];
172 $result['database_name'] = trim($settings['path'],'/');
178 return $this->settings
['type'];
181 function debug($on = 'switch')
183 if ($on == 'switch') {
184 $this->debug
= !$this->debug
;
191 function _log($message)
196 $this->logger
->message($message);
199 function addLimitAndOffset(&$sql,$options)
201 if (isset($options['limit']) && $limit = $options['limit']){
202 $sql .= " LIMIT $limit";
203 if (isset($options['offset']) && $offset = $options['offset']){
204 $sql .= " OFFSET $offset";
210 /* DATABASE STATEMENTS - CRUD */
212 function execute($sql, $message = 'SQL')
214 if (is_array($sql)) {
215 $sql_string = array_shift($sql);
217 } else $sql_string = $sql;
219 $this->_log($message.': '.$sql_string);
220 $result = isset($bindings) ?
$this->connection
->Execute($sql_string, $bindings) : $this->connection
->Execute($sql_string);
223 $error_message = '['.$this->connection
->ErrorNo().'] '.$this->connection
->ErrorMsg();
224 $this->_log('SQL Error: '.$error_message);
225 if ($this->debug || AK_DEBUG
) trigger_error("Tried '$sql_string'. Got: $error_message", E_USER_NOTICE
);
230 function incrementsPrimaryKeyAutomatically()
235 function getLastInsertedId($table,$pk)
237 return $this->connection
->Insert_ID($table,$pk);
240 function getAffectedRows()
242 return $this->connection
->Affected_Rows();
245 function insert($sql,$id=null,$pk=null,$table=null,$message = '')
247 $result = $this->execute($sql,$message);
251 return is_null($id) ?
$this->getLastInsertedId($table,$pk) : $id;
254 function update($sql,$message = '')
256 $result = $this->execute($sql,$message);
257 return ($result) ?
$this->getAffectedRows() : false;
260 function delete($sql,$message = '')
262 $result = $this->execute($sql,$message);
263 return ($result) ?
$this->getAffectedRows() : false;
267 * Returns a single value, the first column from the first row, from a record
269 function selectValue($sql)
271 $result = $this->selectOne($sql);
272 return !is_null($result) ?
array_shift($result) : null;
276 * Returns an array of the values of the first column in a select:
277 * sqlSelectValues("SELECT id FROM companies LIMIT 3") => array(1,2,3)
279 function selectValues($sql)
282 if($results = $this->select($sql)){
283 foreach ($results as $result){
284 $values[] = array_shift($result);
291 * Returns a record array of the first row with the column names as keys and column values
294 function selectOne($sql)
296 $result = $this->select($sql);
297 return !is_null($result) ?
array_shift($result) : null;
303 function selectAll($sql)
305 return $this->select($sql);
309 * Returns an array of record hashes with the column names as keys and
310 * column values as values.
312 function select($sql, $message = '')
314 $result = $this->execute($sql, $message);
320 while ($record = $result->FetchRow()) {
321 $records[] = $record;
329 function startTransaction()
331 return $this->connection
->StartTrans();
334 function stopTransaction()
336 return $this->connection
->CompleteTrans();
339 function failTransaction()
341 return $this->connection
->FailTrans();
344 function hasTransactionFailed()
346 return $this->connection
->HasFailedTrans();
351 function renameColumn($table_name,$column_name,$new_name)
353 trigger_error(Ak
::t('renameColumn is not available for your DbAdapter. Using %db_type.',array('%db_type'=>$this->type())));
358 function availableTables()
360 return $this->connection
->MetaTables();
363 function getColumnDetails($table_name)
365 return $this->connection
->MetaColumns($table_name);
368 function getIndexes($table_name)
370 return $this->connection
->MetaIndexes($table_name);
375 function quote_string($value)
377 return $this->connection
->qstr($value);
380 function quote_datetime($value)
382 return $this->connection
->DBTimeStamp($value);
385 function quote_date($value)
387 return $this->connection
->DBDate($value);
390 // will be moved to postgre
391 function escape_blob($value)
393 return $this->connection
->BlobEncode($value);
396 // will be moved to postgre
397 function unescape_blob($value)
399 return $this->connection
->BlobDecode($value);