Subversion Repositories svnkaklik

Rev

Details | Last modification | View Log

Rev Author Line No. Line
36 kaklik 1
<?php
2
/*
3
 
4
@version V4.80 8 Mar 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
5
  Latest version is available at http://adodb.sourceforge.net
6
 
7
  Released under both BSD license and Lesser GPL library license. 
8
  Whenever there is any discrepancy between the two licenses, 
9
  the BSD license will take precedence.
10
 
11
  Active Record implementation. Superset of Zend Framework's.
12
 
13
  Version 0.02
14
*/
15
 
16
global $_ADODB_ACTIVE_DBS;
17
 
18
// array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
19
$_ADODB_ACTIVE_DBS = array();
20
 
21
 
22
class ADODB_Active_DB {
23
	var $db; // ADOConnection
24
	var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
25
}
26
 
27
class ADODB_Active_Table {
28
	var $name; // table name
29
	var $flds; // assoc array of adofieldobjs, indexed by fieldname
30
	var $keys; // assoc array of primary keys, indexed by fieldname
31
}
32
 
33
// returns index into $_ADODB_ACTIVE_DBS
34
function ADODB_SetDatabaseAdapter(&$db)
35
{
36
	global $_ADODB_ACTIVE_DBS;
37
 
38
		foreach($_ADODB_ACTIVE_DBS as $k => $d) {
39
			if ($d->db == $db) return $k;
40
		}
41
 
42
		$obj = new ADODB_Active_DB();
43
		$obj->db =& $db;
44
		$obj->tables = array();
45
 
46
		$_ADODB_ACTIVE_DBS[] = $obj;
47
 
48
		return sizeof($_ADODB_ACTIVE_DBS)-1;
49
}
50
 
51
class ADODB_Active_Record {
52
	var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
53
	var $_table; // tablename
54
	var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
55
	var $_where; // where clause set in Load()
56
	var $_saved = false; // indicates whether data is already inserted.
57
	var $_lasterr = false; // last error message
58
 
59
	// should be static
60
	function SetDatabaseAdapter(&$db) 
61
	{
62
		return ADODB_SetDatabaseAdapter($db);
63
	}
64
 
65
	// php4 constructor
66
	function ADODB_Active_Record($table = false, $pkeyarr=false, $db=false)
67
	{
68
		ADODB_Active_Record::__construct($table,$pkeyarr,$db);
69
	}
70
 
71
	// php5 constructor
72
	function __construct($table = false, $pkeyarr=false, $db=false)
73
	{
74
	global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
75
 
76
		if ($db == false && is_object($pkeyarr)) {
77
			$db = $pkeyarr;
78
			$pkeyarr = false;
79
		}
80
 
81
		if (!$table) $table = $this->_pluralize(get_class($this));
82
 
83
		if ($db) {
84
			$this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
85
		} else
86
			$this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
87
 
88
 
89
		if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
90
 
91
		$this->_table = $table;
92
		$this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
93
		$this->UpdateActiveTable($pkeyarr);
94
	}
95
 
96
	function _pluralize($table)
97
	{
98
		$ut = strtoupper($table);
99
		$len = strlen($table);
100
		$lastc = $ut[$len-1];
101
		$lastc2 = substr($ut,$len-2);
102
		switch ($lastc) {
103
		case 'S':
104
			return $table.'es';	
105
		case 'Y':
106
			return substr($table,0,$len-1).'ies';
107
		case 'X':	
108
			return $table.'es';
109
		case 'H': 
110
			if ($lastc2 == 'CH' || $lastc2 == 'SH')
111
				return $table.'es';
112
		default:
113
			return $table.'s';
114
		}
115
	}
116
 
117
	//////////////////////////////////
118
 
119
	// update metadata
120
	function UpdateActiveTable($pkeys=false,$forceUpdate=false)
121
	{
122
	global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
123
 
124
		$activedb =& $_ADODB_ACTIVE_DBS[$this->_dbat];
125
 
126
		$table = $this->_table;
127
		$tables = $activedb->tables;
128
		$tableat = $this->_tableat;
129
		if (!$forceUpdate && !empty($tables[$tableat])) {
130
			$tobj =& $tables[$tableat];
131
			foreach($tobj->flds as $name => $fld) 
132
				$this->$name = null;
133
			return;
134
		}
135
 
136
		$activetab = new ADODB_Active_Table();
137
		$activetab->name = $table;
138
 
139
		$db =& $activedb->db;
140
 
141
		$cols = $db->MetaColumns($table);
142
		if (!$cols) {
143
			$this->Error("Invalid table name: $table",'UpdateActiveTable'); 
144
			return false;
145
		}
146
		$fld = reset($cols);
147
		if (!$pkeys) {
148
			if (isset($fld->primary_key)) {
149
				$pkeys = array();
150
				foreach($cols as $name => $fld) {
151
					if (!empty($fld->primary_key)) $pkeys[] = $name;
152
				}
153
			} else	
154
				$pkeys = $this->GetPrimaryKeys($db, $table);
155
		}
156
		if (empty($pkeys)) {
157
			$this->Error("No primary key found for table $table",'UpdateActiveTable');
158
			return false;
159
		}
160
 
161
		$attr = array();
162
		$keys = array();
163
 
164
		switch($ADODB_ASSOC_CASE) {
165
		case 0:
166
			foreach($cols as $name => $fldobj) {
167
				$name = strtolower($name);
168
				$this->$name = null;
169
				$attr[$name] = $fldobj;
170
			}
171
			foreach($pkeys as $k => $name) {
172
				$keys[strtolower($name)] = strtolower($name);
173
			}
174
			break;
175
 
176
		case 1: 
177
			foreach($cols as $name => $fldobj) {
178
				$name = strtoupper($name);
179
				$this->$name = null;
180
				$attr[$name] = $fldobj;
181
			}
182
 
183
			foreach($pkeys as $k => $name) {
184
				$keys[strtoupper($name)] = strtoupper($name);
185
			}
186
			break;
187
		default:
188
			foreach($cols as $name => $fldobj) {
189
				$name = ($name);
190
				$this->$name = null;
191
				$attr[$name] = $fldobj;
192
			}
193
			foreach($pkeys as $k => $name) {
194
				$keys[$name] = ($name);
195
			}
196
			break;
197
		}
198
 
199
		$activetab->keys = $keys;
200
		$activetab->flds = $attr;
201
		$activedb->tables[$table] = $activetab;
202
	}
203
 
204
	function GetPrimaryKeys(&$db, $table)
205
	{
206
		return $db->MetaPrimaryKeys($table);
207
	}
208
 
209
	// error handler for both PHP4+5. 
210
	function Error($err,$fn)
211
	{
212
	global $_ADODB_ACTIVE_DBS;
213
 
214
		$fn = get_class($this).'::'.$fn;
215
		$this->_lasterr = $fn.': '.$err;
216
 
217
		if ($this->_dbat < 0) $db = false;
218
		else {
219
			$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
220
			$db =& $activedb->db;
221
		}
222
 
223
		if (function_exists('adodb_throw')) {	
224
			if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
225
			else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
226
		} else
227
			if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
228
 
229
	}
230
 
231
	// return last error message
232
	function ErrorMsg()
233
	{
234
		if (!function_exists('adodb_throw')) {
235
			if ($this->_dbat < 0) $db = false;
236
			else $db = $this->DB();
237
 
238
			// last error could be database error too
239
			if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
240
		}
241
		return $this->_lasterr;
242
	}
243
 
244
	// retrieve ADOConnection from _ADODB_Active_DBs
245
	function &DB()
246
	{
247
	global $_ADODB_ACTIVE_DBS;
248
 
249
		if ($this->_dbat < 0) {
250
			$false = false;
251
			$this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
252
			return $false;
253
		}
254
		$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
255
		$db =& $activedb->db;
256
		return $db;
257
	}
258
 
259
	// retrieve ADODB_Active_Table
260
	function &TableInfo()
261
	{
262
	global $_ADODB_ACTIVE_DBS;
263
 
264
		$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
265
		$table =& $activedb->tables[$this->_tableat];
266
		return $table;
267
	}
268
 
269
	// set a numeric array (using natural table field ordering) as object properties
270
	function Set(&$row)
271
	{
272
		$db =& $this->DB();
273
 
274
		if (!$row) {
275
			$this->_saved = false;		
276
			return false;
277
		}
278
 
279
		$this->_saved = true;
280
 
281
		$table =& $this->TableInfo();
282
		if (sizeof($table->flds) != sizeof($row)) {
283
			$this->Error("Table structure of $this->_table has changed","Load");
284
			return false;
285
		}
286
 
287
		$cnt = 0;
288
		foreach($table->flds as $name=>$fld) {
289
			$this->$name = $row[$cnt];
290
			$cnt += 1;
291
		}
292
		#$this->_original =& $row;
293
		return true;
294
	}
295
 
296
	// get last inserted id for INSERT
297
	function LastInsertID(&$db,$fieldname)
298
	{
299
		if ($db->hasInsertID)
300
			$val = $db->Insert_ID($this->_table,$fieldname);
301
		else
302
			$val = false;
303
 
304
		if (is_null($val) || $val === false) {
305
			// this might not work reliably in multi-user environment
306
			return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
307
		}
308
		return $val;
309
	}
310
 
311
	// quote data in where clause
312
	function doquote(&$db, $val,$t)
313
	{
314
		switch($t) {
315
		case 'D':
316
		case 'T':
317
			if (empty($val)) return 'null';
318
 
319
		case 'C':
320
		case 'X':
321
			if (is_null($val)) return 'null';
322
 
323
			if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") { 
324
				return $db->qstr($val);
325
				break;
326
			}
327
		default:
328
			return $val;
329
			break;
330
		}
331
	}
332
 
333
	// generate where clause for an UPDATE/SELECT
334
	function GenWhere(&$db, &$table)
335
	{
336
		$keys = $table->keys;
337
		$parr = array();
338
 
339
		foreach($keys as $k) {
340
			$f = $table->flds[$k];
341
			if ($f) {
342
				$parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
343
			}
344
		}
345
		return implode(' and ', $parr);
346
	}
347
 
348
 
349
	//------------------------------------------------------------ Public functions below
350
 
351
	function Load($where,$bindarr=false)
352
	{
353
		$db =& $this->DB(); if (!$db) return false;
354
		$this->_where = $where;
355
 
356
		$save = $db->SetFetchMode(ADODB_FETCH_NUM);
357
		$row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);
358
		$db->SetFetchMode($save);
359
 
360
		return $this->Set($row);
361
	}
362
 
363
	// false on error
364
	function Save()
365
	{
366
		if ($this->_saved) $ok = $this->Update();
367
		else $ok = $this->Insert();
368
 
369
		return $ok;
370
	}
371
 
372
	// false on error
373
	function Insert()
374
	{
375
		$db =& $this->DB(); if (!$db) return false;
376
		$cnt = 0;
377
		$table =& $this->TableInfo();
378
 
379
		foreach($table->flds as $name=>$fld) {
380
			$val = $this->$name;
381
			/*
382
			if (is_null($val)) {
383
				if (isset($fld->not_null) && $fld->not_null) {
384
					if (isset($fld->default_value) && strlen($fld->default_value)) continue;
385
					else $this->Error("Cannot insert null into $name","Insert");
386
				}
387
			}*/
388
 
389
			$valarr[] = $val;
390
			$names[] = $name;
391
			$valstr[] = $db->Param($cnt);
392
			$cnt += 1;
393
		}
394
 
395
		$sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
396
		$ok = $db->Execute($sql,$valarr);
397
 
398
		if ($ok) {
399
			$this->_saved = true;
400
			$autoinc = false;
401
			foreach($table->keys as $k) {
402
				if (is_null($this->$k)) {
403
					$autoinc = true;
404
					break;
405
				}
406
			}
407
			if ($autoinc && sizeof($table->keys) == 1) {
408
				$k = reset($table->keys);
409
				$this->$k = $this->LastInsertID($db,$k);
410
			}
411
		}
412
 
413
		#$this->_original =& $valarr;
414
		return !empty($ok);
415
	}
416
 
417
	function Delete()
418
	{
419
		$db =& $this->DB(); if (!$db) return false;
420
		$table =& $this->TableInfo();
421
 
422
		$where = $this->GenWhere($db,$table);
423
		$sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
424
		$db->Execute($sql);
425
	}
426
 
427
 
428
	// returns 0 on error, 1 on update, 2 on insert
429
	function Replace()
430
	{
431
	global $ADODB_ASSOC_CASE;
432
 
433
		$db =& $this->DB(); if (!$db) return false;
434
		$table =& $this->TableInfo();
435
 
436
		$pkey = $table->keys;
437
 
438
		foreach($table->flds as $name=>$fld) {
439
			$val = $this->$name;
440
			/*
441
			if (is_null($val)) {
442
				if (isset($fld->not_null) && $fld->not_null) {
443
					if (isset($fld->default_value) && strlen($fld->default_value)) continue;
444
					else {
445
						$this->Error("Cannot update null into $name","Replace");
446
						return false;
447
					}
448
				}
449
			}*/
450
			$t = $db->MetaType($fld->type);
451
			$arr[$name] = $this->doquote($db,$val,$t);
452
			$valarr[] = $val;
453
		}
454
 
455
		if (!is_array($pkey)) $pkey = array($pkey);
456
 
457
 
458
		if ($ADODB_ASSOC_CASE == 0) 
459
			foreach($pkey as $k => $v)
460
				$pkey[$k] = strtolower($v);
461
		elseif ($ADODB_ASSOC_CASE == 0) 
462
			foreach($pkey as $k => $v)
463
				$pkey[$k] = strtoupper($v);
464
 
465
		$ok = $db->Replace($this->_table,$arr,$pkey);
466
		if ($ok) {
467
			$this->_saved = true; // 1= update 2=insert
468
			if ($ok == 2) {
469
				$autoinc = false;
470
				foreach($table->keys as $k) {
471
					if (is_null($this->$k)) {
472
						$autoinc = true;
473
						break;
474
					}
475
				}
476
				if ($autoinc && sizeof($table->keys) == 1) {
477
					$k = reset($table->keys);
478
					$this->$k = $this->LastInsertID($db,$k);
479
				}
480
			}
481
 
482
			#$this->_original =& $valarr;
483
		} 
484
		return $ok;
485
	}
486
 
487
	// returns false on error
488
	function Update()
489
	{
490
		$db =& $this->DB(); if (!$db) return false;
491
		$table =& $this->TableInfo();
492
 
493
		$where = $this->GenWhere($db, $table);
494
 
495
		if (!$where) {
496
			$this->error("Where missing for table $table", "Update");
497
			return false;
498
		}
499
		$cnt = 0;
500
		foreach($table->flds as $name=>$fld) {
501
			if (isset($table->keys[$name])) continue;
502
 
503
			$val = $this->$name;
504
 
505
			if (is_null($val)) {
506
				if (isset($fld->not_null) && $fld->not_null) {
507
					if (isset($fld->default_value) && strlen($fld->default_value)) continue;
508
					else {
509
						$this->Error("Cannot set field $name to NULL","Update");
510
						return false;
511
					}
512
				}
513
			}
514
			$valarr[] = $val;
515
			$pairs[] = $name.'='.$db->Param($cnt);
516
			$cnt += 1;
517
		}
518
 
519
		#$this->_original =& $valarr;
520
 
521
		$sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
522
		$ok = $db->Execute($sql,$valarr);
523
 
524
		return !empty($ok);
525
	}
526
 
527
	function GetAttributeNames()
528
	{
529
		$table =& $this->TableInfo();
530
		if (!$table) return false;
531
		return array_keys($table->flds);
532
	}
533
 
534
};
535
 
536
?>