root/trunk/lib/AkActiveRecord/AkDbAdapter.php

Revision 1436, 14.2 kB (checked in by bermi, 5 months ago)

By Julio Montoya. FIxing typo.

Line 
1 <?php
2
3 // +----------------------------------------------------------------------+
4 // | Akelos Framework - http://www.akelos.org                             |
5 // +----------------------------------------------------------------------+
6 // | Released under the GNU Lesser General Public License, see LICENSE.txt|
7 // +----------------------------------------------------------------------+
8
9 /**
10  * @package ActiveRecord
11  * @subpackage Base
12  * @component DbAdapter
13  * @author Bermi Ferrer <bermi a.t bermilabs c.om>
14  * @author Kaste
15  * @author Arno Schneider <arno a.t bermilabs c.om>
16  * @copyright Copyright (c) 2002-2009, The Akelos Team http://www.akelos.org
17  * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html>
18  */
19
20
21 defined('AK_AVAILABLE_DATABASES') ? null : define('AK_AVAILABLE_DATABASES', 'mysql,pgsql,sqlite');
22
23 require_once(AK_LIB_DIR.DS.'AkObject.php');
24
25 class AkDbAdapter extends AkObject
26 {
27
28     public $connection;
29     public $settings;
30     public $dictionary;
31     public $debug=false;
32     public $logger;
33
34     /**
35      * @param array $database_settings
36      */
37     public function __construct($database_settings, $auto_connect = false)
38     {
39         $this->settings = $database_settings;
40         if ($auto_connect){
41             $this->connect();
42         }
43         if (AK_LOG_EVENTS){
44             $this->logger =& Ak::getLogger();
45         }
46     }
47
48     public function __destruct()
49     {
50     }
51
52     public function connect($die_on_error=true)
53     {
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
58         if (!$this->connection){
59             error_reporting(E_ALL);
60             if(defined('AK_DATABASE_CONNECTION_FAILURE_CALLBACK') && function_exists(AK_DATABASE_CONNECTION_FAILURE_CALLBACK)){
61                 $fn = AK_DATABASE_CONNECTION_FAILURE_CALLBACK;
62                 $fn();
63             }
64             trigger_error(Ak::t("Connection to the database failed. %dsn",
65             array('%dsn'=> AK_DEBUG ? preg_replace('/\/\/(\w+):(.*)@/i','//$1:******@', urldecode($dsn))."\n" : '')),
66             ($die_on_error?E_USER_ERROR:E_USER_WARNING));
67         } else {
68             $this->connection->debug = AK_DEBUG == 2;
69             $this->connection->SetFetchMode(ADODB_FETCH_ASSOC);
70             defined('AK_DATABASE_CONNECTION_AVAILABLE') ? null : define('AK_DATABASE_CONNECTION_AVAILABLE', true);
71         }
72     }
73
74     public function connected()
75     {
76         return !empty($this->connection);
77     }
78
79
80     /**
81      * @static
82      * @param array $database_settings
83      * @return AkDbAdapter
84      */
85     static public function &getInstance($database_specifications = AK_DEFAULT_DATABASE_PROFILE, $auto_connect = true)
86     {
87         $settings_hash = is_string($database_specifications) ? $database_specifications : AkDbAdapter::_hash($database_specifications);
88         $static_var_name = 'AkDbAdapter_getInstance_'.$settings_hash;
89
90         if (!$Connection = Ak::getStaticVar($static_var_name)){
91             if (empty($database_specifications)) {
92                 $settings_hash = AK_ENVIRONMENT;
93                 $database_specifications = Ak::getSettings('database', false, $settings_hash);
94             } else if (is_string($database_specifications)){
95
96                 $environment_settings = Ak::getSettings('database', false, $database_specifications);
97
98                 if (!empty($environment_settings)){
99                     $database_specifications = $environment_settings;
100                 } elseif(strstr($database_specifications, '://')) {
101                     $database_specifications = AkDbAdapter::_getDbSettingsFromDsn($database_specifications);
102                     $settings_hash = AK_ENVIRONMENT;
103                 } else {
104                     global $database_settings;
105                     if (isset($database_settings) && !file_exists(AK_CONFIG_DIR.DS.'database.yml')) {
106                         trigger_error(Ak::t("You are still using the old config/config.php database configuration. Please upgrade to use the config/database.yml configuration."), E_USER_NOTICE);
107                     }
108                     if (!file_exists(AK_CONFIG_DIR.DS.'database.yml')) {
109                         trigger_error(Ak::t("Could not find the database configuration file in %dbconfig.",array('%dbconfig'=>AK_CONFIG_DIR.DS.'database.yml')),E_USER_ERROR);
110                     } else {
111                         trigger_error(Ak::t("Could not find the database profile '%profile_name' in config/database.yml.",array('%profile_name'=>$database_specifications)),E_USER_ERROR);
112                     }
113
114
115                     $return = false;
116                     return $return;
117                 }
118             }elseif (!empty($database_settings[$settings_hash])){
119                 $database_specifications = $database_settings[$settings_hash];
120             }
121             $available_adapters = Ak::toArray(AK_AVAILABLE_DATABASES);
122             $class_name = 'AkDbAdapter';
123             $designated_database = strtolower($database_specifications['type']);
124             if (in_array($designated_database, $available_adapters)) {
125                 $class_name = 'Ak'.ucfirst($designated_database).'DbAdapter';
126                 require_once(AK_LIB_DIR.DS.'AkActiveRecord'.DS.'AkDbAdapters'.DS.$class_name.'.php');
127             }
128             $Connection = new $class_name($database_specifications,$auto_connect);
129             Ak::setStaticVar($static_var_name, $Connection);
130         }
131         return $Connection;
132     }
133
134     /**
135      * @param array $settings
136      * @return string
137      */
138     public function _hash($settings)
139     {
140         if(!is_array($settings)){
141             return AK_ENVIRONMENT;
142         }
143         if (isset($settings['password'])){
144             unset($settings['password']);
145         }
146         return join(':',$settings);
147     }
148
149     public function &getDictionary()
150     {
151         if (empty($this->dictionary)){
152             if (!$this->connected()){
153                 $this->connect();
154             }
155             require_once(AK_CONTRIB_DIR.DS.'adodb'.DS.'adodb.inc.php');
156             $this->dictionary =& NewDataDictionary($this->connection);
157         }
158         return $this->dictionary;
159     }
160
161     /**
162      * @param array $database_settings
163      * @return string
164      */
165     public function _constructDsn($database_settings)
166     {
167         if(is_string($database_settings)){
168             return $database_settings;
169         }
170         $dsn  = $database_settings['type'].'://';
171         $dsn .= $database_settings['user'].':'.$database_settings['password'];
172         $dsn .= !empty($database_settings['host']) ? '@'.$database_settings['host'] : '@localhost';
173         $dsn .= !empty($database_settings['port']) ? ':'.$database_settings['port'] : '';
174         $dsn .= '/'.$database_settings['database_name'];
175         $dsn .= !empty($database_settings['options']) ? $database_settings['options'] : '';
176         return $dsn;
177
178     }
179
180     public function _getDbSettingsFromDsn($dsn)
181     {
182         $settings = $result = parse_url($dsn);
183         $result['type'] = $settings['scheme'];
184         $result['password'] = $settings['pass'];
185         $result['database_name'] = trim($settings['path'],'/');
186         return $result;
187     }
188
189     public function type()
190     {
191         return $this->settings['type'];
192     }
193
194     public function debug($on = 'switch')
195     {
196         if ($on == 'switch') {
197             $this->debug = !$this->debug;
198         }else{
199             $this->debug = $on;
200         }
201         return $this->debug;
202     }
203
204     public function _log($message)
205     {
206         if (!AK_LOG_EVENTS){
207             return;
208         }
209         $this->logger->message($message);
210     }
211
212     public function addLimitAndOffset(&$sql,$options)
213     {
214         if (isset($options['limit']) && $limit = $options['limit']){
215             $sql .= " LIMIT $limit";
216             if (isset($options['offset']) && $offset = $options['offset']){
217                 $sql .= " OFFSET $offset";
218             }
219         }
220         return $sql;
221     }
222
223     /* DATABASE STATEMENTS - CRUD */
224
225     public function execute($sql, $message = 'SQL')
226     {
227         if (is_array($sql)) {
228             $sql_string = array_shift($sql);
229             $bindings = $sql;
230         } else $sql_string = $sql;
231
232         $this->_log($message.': '.$sql_string);
233         $result = isset($bindings) ? $this->connection->Execute($sql_string, $bindings) : $this->connection->Execute($sql_string);
234
235         if (!$result){
236             $error_message = '['.$this->connection->ErrorNo().'] '.$this->connection->ErrorMsg();
237             $this->_log('SQL Error: '.$error_message);
238             if ($this->debug || AK_DEBUG) trigger_error("Tried '$sql_string'. Got: $error_message", E_USER_NOTICE);
239         }
240         return $result;
241     }
242
243     public function incrementsPrimaryKeyAutomatically()
244     {
245         return true;
246     }
247
248     public function getLastInsertedId($table,$pk)
249     {
250         return $this->connection->Insert_ID($table,$pk);
251     }
252
253     public function getAffectedRows()
254     {
255         return $this->connection->Affected_Rows();
256     }
257
258     public function insert($sql,$id=null,$pk=null,$table=null,$message = '')
259     {
260         $result = $this->execute($sql,$message);
261         if (!$result){
262             return false;
263         }
264         return is_null($id) ? $this->getLastInsertedId($table,$pk) : $id;
265     }
266
267     public function update($sql,$message = '')
268     {
269         $result = $this->execute($sql,$message);
270         return ($result) ? $this->getAffectedRows() : false;
271     }
272
273     public function delete($sql,$message = '')
274     {
275         $result = $this->execute($sql,$message);
276         return ($result) ? $this->getAffectedRows() : false;
277     }
278
279     /**
280     * Returns a single value, the first column from the first row, from a record
281     */
282     public function selectValue($sql)
283     {
284         $result = $this->selectOne($sql);
285         return !is_null($result) ? array_shift($result) : null;
286     }
287
288     /**
289      * Returns an array of the values of the first column in a select:
290      *   sqlSelectValues("SELECT id FROM companies LIMIT 3") => array(1,2,3)
291      */
292     public function selectValues($sql)
293     {
294         $values = array();
295         if($results = $this->select($sql)){
296             foreach ($results as $result){
297                 $values[] = array_shift($result);
298             }
299         }
300         return $values;
301     }
302
303     /**
304      * Returns a record array of the first row with the column names as keys and column values
305      * as values.
306      */
307     public function selectOne($sql)
308     {
309         $result = $this->select($sql);
310         return  !is_null($result) ? array_shift($result) : null;
311     }
312
313     /**
314      * alias for select
315      */
316     public function selectAll($sql)
317     {
318         return $this->select($sql);
319     }
320
321     /**
322     * Returns an array of record hashes with the column names as keys and
323     * column values as values.
324     */
325     public function select($sql, $message = '')
326     {
327         $result = $this->execute($sql, $message);
328         if (!$result){
329             return array();
330         }
331
332         $records = array();
333         while ($record = $result->FetchRow()) {
334             $records[] = $record;
335         }
336         $result->Close();
337         return $records;
338     }
339
340     /* TRANSACTIONS */
341
342     public function startTransaction()
343     {
344         return $this->connection->StartTrans();
345     }
346
347     public function stopTransaction()
348     {
349         return $this->connection->CompleteTrans();
350     }
351
352     public function failTransaction()
353     {
354         if(AK_DEBUG && !empty($this->connection->debug)){
355             Ak::trace(ak_backtrace(), null, null, null, false);
356         }
357         return $this->connection->FailTrans();
358     }
359
360     public function hasTransactionFailed()
361     {
362         return $this->connection->HasFailedTrans();
363     }
364
365     /* SCHEMA */
366
367     public function renameColumn($table_name,$column_name,$new_name)
368     {
369         trigger_error(Ak::t('renameColumn is not available for your DbAdapter. Using %db_type.',array('%db_type'=>$this->type())));
370     }
371
372     /* META */
373
374     /**
375      * caching the meta info
376      *
377      * @return unknown
378      */
379     public function availableTables($force_lookup = false)
380     {
381         $available_tables = array();
382         !AK_TEST_MODE && $available_tables = Ak::getStaticVar('available_tables');
383         if(!$force_lookup && empty($available_tables)){
384             if (($available_tables = AkDbSchemaCache::get('available_tables')) === false) {
385                 if(empty($available_tables)){
386                     $available_tables = $this->connection->MetaTables();
387                 }
388                 AkDbSchemaCache::set('available_tables', $available_tables);
389                 !AK_TEST_MODE && Ak::setStaticVar('available_tables', $available_tables);
390             }
391         }
392         $available_tables = $force_lookup ? $this->connection->MetaTables() : $available_tables;
393         $force_lookup && !AK_TEST_MODE && Ak::setStaticVar('available_tables', $available_tables);
394         return $available_tables;
395     }
396
397     public function tableExists($table_name)
398     {
399         // First try if cached
400         $available_tables = $this->availableTables();
401         if(!in_array($table_name,(array)$available_tables)){
402             // Force lookup and refresh cache
403             $available_tables = $this->availableTables(true);
404             return in_array($table_name,(array)$available_tables);
405         }
406         return true;
407     }
408
409     /**
410      * caching the meta info
411      *
412      * @param unknown_type $table_name
413      * @return unknown
414      */
415
416     public function getColumnDetails($table_name)
417     {
418         return $this->connection->MetaColumns($table_name);
419     }
420
421     /**
422      * caching the meta info
423      *
424      * @param unknown_type $table_name
425      * @return unknown
426      */
427     public function getIndexes($table_name)
428     {
429         return $this->connection->MetaIndexes($table_name);
430     }
431
432     /* QUOTING */
433
434     public function quote_string($value)
435     {
436         return $this->connection->qstr($value);
437     }
438
439     public function quote_datetime($value)
440     {
441         return $this->connection->DBTimeStamp($value);
442     }
443
444     public function quote_date($value)
445     {
446         return $this->connection->DBDate($value);
447     }
448
449     // will be moved to postgre
450     public function escape_blob($value)
451     {
452         return $this->connection->BlobEncode($value);
453     }
454
455     // will be moved to postgre
456     public function unescape_blob($value)
457     {
458         return $this->connection->BlobDecode($value);
459     }
460
461 }
462
463 ?>
Note: See TracBrowser for help on using the browser.