1173 |
jp_milcent |
1 |
<?php
|
|
|
2 |
/**
|
|
|
3 |
* Generation tools for DB_DataObject
|
|
|
4 |
*
|
|
|
5 |
* PHP versions 4 and 5
|
|
|
6 |
*
|
|
|
7 |
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
|
|
8 |
* that is available through the world-wide-web at the following URI:
|
|
|
9 |
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
|
|
10 |
* the PHP License and are unable to obtain it through the web, please
|
|
|
11 |
* send a note to license@php.net so we can mail you a copy immediately.
|
|
|
12 |
*
|
|
|
13 |
* @category Database
|
|
|
14 |
* @package DB_DataObject
|
|
|
15 |
* @author Alan Knowles <alan@akbkhome.com>
|
|
|
16 |
* @copyright 1997-2005 The PHP Group
|
|
|
17 |
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
|
|
18 |
* @version CVS: $Id: Generator.php,v 1.1 2006-12-14 15:04:28 jp_milcent Exp $
|
|
|
19 |
* @link http://pear.php.net/package/DB_DataObject
|
|
|
20 |
*/
|
|
|
21 |
|
|
|
22 |
/**
|
|
|
23 |
*
|
|
|
24 |
* Config _$ptions
|
|
|
25 |
* [DB_DataObject_Generator]
|
|
|
26 |
* ; optional default = DB/DataObject.php
|
|
|
27 |
* extends_location =
|
|
|
28 |
* ; optional default = DB_DataObject
|
|
|
29 |
* extends =
|
|
|
30 |
* ; alter the extends field when updating a class (defaults to only replacing DB_DataObject)
|
|
|
31 |
* generator_class_rewrite = ANY|specific_name // default is DB_DataObject
|
|
|
32 |
*
|
|
|
33 |
*/
|
|
|
34 |
|
|
|
35 |
/**
|
|
|
36 |
* Needed classes
|
|
|
37 |
*/
|
|
|
38 |
require_once 'DB/DataObject.php';
|
|
|
39 |
//require_once('Config.php');
|
|
|
40 |
|
|
|
41 |
/**
|
|
|
42 |
* Generator class
|
|
|
43 |
*
|
|
|
44 |
* @package DB_DataObject
|
|
|
45 |
*/
|
|
|
46 |
class DB_DataObject_Generator extends DB_DataObject
|
|
|
47 |
{
|
|
|
48 |
/* =========================================================== */
|
|
|
49 |
/* Utility functions - for building db config files */
|
|
|
50 |
/* =========================================================== */
|
|
|
51 |
|
|
|
52 |
/**
|
|
|
53 |
* Array of table names
|
|
|
54 |
*
|
|
|
55 |
* @var array
|
|
|
56 |
* @access private
|
|
|
57 |
*/
|
|
|
58 |
var $tables;
|
|
|
59 |
|
|
|
60 |
/**
|
|
|
61 |
* associative array table -> array of table row objects
|
|
|
62 |
*
|
|
|
63 |
* @var array
|
|
|
64 |
* @access private
|
|
|
65 |
*/
|
|
|
66 |
var $_definitions;
|
|
|
67 |
|
|
|
68 |
/**
|
|
|
69 |
* active table being output
|
|
|
70 |
*
|
|
|
71 |
* @var string
|
|
|
72 |
* @access private
|
|
|
73 |
*/
|
|
|
74 |
var $table; // active tablename
|
|
|
75 |
|
|
|
76 |
|
|
|
77 |
/**
|
|
|
78 |
* The 'starter' = call this to start the process
|
|
|
79 |
*
|
|
|
80 |
* @access public
|
|
|
81 |
* @return none
|
|
|
82 |
*/
|
|
|
83 |
function start()
|
|
|
84 |
{
|
|
|
85 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
86 |
$databases = array();
|
|
|
87 |
foreach($options as $k=>$v) {
|
|
|
88 |
if (substr($k,0,9) == 'database_') {
|
|
|
89 |
$databases[substr($k,9)] = $v;
|
|
|
90 |
}
|
|
|
91 |
}
|
|
|
92 |
|
|
|
93 |
if (@$options['database']) {
|
|
|
94 |
require_once 'DB.php';
|
|
|
95 |
$dsn = DB::parseDSN($options['database']);
|
|
|
96 |
if (!isset($database[$dsn['database']])) {
|
|
|
97 |
$databases[$dsn['database']] = $options['database'];
|
|
|
98 |
}
|
|
|
99 |
}
|
|
|
100 |
|
|
|
101 |
foreach($databases as $databasename => $database) {
|
|
|
102 |
if (!$database) {
|
|
|
103 |
continue;
|
|
|
104 |
}
|
|
|
105 |
$this->debug("CREATING FOR $databasename\n");
|
|
|
106 |
$class = get_class($this);
|
|
|
107 |
$t = new $class;
|
|
|
108 |
$t->_database_dsn = $database;
|
|
|
109 |
|
|
|
110 |
|
|
|
111 |
$t->_database = $databasename;
|
|
|
112 |
$dsn = DB::parseDSN($database);
|
|
|
113 |
if (($dsn['phptype'] == 'sqlite') && is_file($databasename)) {
|
|
|
114 |
$t->_database = basename($t->_database);
|
|
|
115 |
}
|
|
|
116 |
$t->_createTableList();
|
|
|
117 |
|
|
|
118 |
foreach(get_class_methods($class) as $method) {
|
|
|
119 |
if (substr($method,0,8 ) != 'generate') {
|
|
|
120 |
continue;
|
|
|
121 |
}
|
|
|
122 |
$this->debug("calling $method");
|
|
|
123 |
$t->$method();
|
|
|
124 |
}
|
|
|
125 |
}
|
|
|
126 |
$this->debug("DONE\n\n");
|
|
|
127 |
}
|
|
|
128 |
|
|
|
129 |
/**
|
|
|
130 |
* Output File was config object, now just string
|
|
|
131 |
* Used to generate the Tables
|
|
|
132 |
*
|
|
|
133 |
* @var string outputbuffer for table definitions
|
|
|
134 |
* @access private
|
|
|
135 |
*/
|
|
|
136 |
var $_newConfig;
|
|
|
137 |
|
|
|
138 |
/**
|
|
|
139 |
* Build a list of tables;
|
|
|
140 |
* Currently this is very Mysql Specific - ideas for more generic stiff welcome
|
|
|
141 |
*
|
|
|
142 |
* @access private
|
|
|
143 |
* @return none
|
|
|
144 |
*/
|
|
|
145 |
function _createTableList()
|
|
|
146 |
{
|
|
|
147 |
$this->_connect();
|
|
|
148 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
149 |
|
|
|
150 |
$__DB= &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
|
|
|
151 |
|
|
|
152 |
// try getting a list of schema tables first. (postgres)
|
|
|
153 |
$__DB->expectError(DB_ERROR_UNSUPPORTED);
|
|
|
154 |
$this->tables = $__DB->getListOf('schema.tables');
|
|
|
155 |
$__DB->popExpect();
|
|
|
156 |
|
|
|
157 |
if (empty($this->tables) || is_a($this->tables , 'PEAR_Error')) {
|
|
|
158 |
//if that fails fall back to clasic tables list.
|
|
|
159 |
$this->tables = $__DB->getListOf('tables');
|
|
|
160 |
}
|
|
|
161 |
if (is_a($this->tables , 'PEAR_Error')) {
|
|
|
162 |
return PEAR::raiseError($this->tables->toString(), null, PEAR_ERROR_DIE);
|
|
|
163 |
}
|
|
|
164 |
// build views as well if asked to.
|
|
|
165 |
if (!empty($options['build_views'])) {
|
|
|
166 |
$views = $__DB->getListOf('views');
|
|
|
167 |
if (is_a($views,'PEAR_Error')) {
|
|
|
168 |
return PEAR::raiseError(
|
|
|
169 |
'Error getting Views (check the PEAR bug database for the fix to DB), ' .
|
|
|
170 |
$views->toString(),
|
|
|
171 |
null,
|
|
|
172 |
PEAR_ERROR_DIE
|
|
|
173 |
);
|
|
|
174 |
}
|
|
|
175 |
$this->tables = array_merge ($this->tables, $views);
|
|
|
176 |
}
|
|
|
177 |
|
|
|
178 |
// declare a temporary table to be filled with matching tables names
|
|
|
179 |
$tmp_table = array();
|
|
|
180 |
|
|
|
181 |
|
|
|
182 |
foreach($this->tables as $table) {
|
|
|
183 |
if (isset($options['generator_include_regex']) &&
|
|
|
184 |
!preg_match($options['generator_include_regex'],$table)) {
|
|
|
185 |
continue;
|
|
|
186 |
} else if (isset($options['generator_exclude_regex']) &&
|
|
|
187 |
preg_match($options['generator_exclude_regex'],$table)) {
|
|
|
188 |
continue;
|
|
|
189 |
}
|
|
|
190 |
// postgres strip the schema bit from the
|
|
|
191 |
if (!empty($options['generator_strip_schema'])) {
|
|
|
192 |
$bits = explode('.', $table,2);
|
|
|
193 |
$table = $bits[0];
|
|
|
194 |
if (count($bits) > 1) {
|
|
|
195 |
$table = $bits[1];
|
|
|
196 |
}
|
|
|
197 |
}
|
|
|
198 |
|
|
|
199 |
$defs = $__DB->tableInfo($table);
|
|
|
200 |
if (is_a($defs,'PEAR_Error')) {
|
|
|
201 |
echo $defs->toString();
|
|
|
202 |
exit;
|
|
|
203 |
}
|
|
|
204 |
// cast all definitions to objects - as we deal with that better.
|
|
|
205 |
|
|
|
206 |
|
|
|
207 |
|
|
|
208 |
foreach($defs as $def) {
|
|
|
209 |
if (!is_array($def)) {
|
|
|
210 |
continue;
|
|
|
211 |
}
|
|
|
212 |
|
|
|
213 |
$this->_definitions[$table][] = (object) $def;
|
|
|
214 |
|
|
|
215 |
}
|
|
|
216 |
// we find a matching table, just store it into a temporary array
|
|
|
217 |
$tmp_table[] = $table;
|
|
|
218 |
|
|
|
219 |
|
|
|
220 |
}
|
|
|
221 |
// the temporary table array is now the right one (tables names matching
|
|
|
222 |
// with regex expressions have been removed)
|
|
|
223 |
$this->tables = $tmp_table;
|
|
|
224 |
//print_r($this->_definitions);
|
|
|
225 |
}
|
|
|
226 |
|
|
|
227 |
/**
|
|
|
228 |
* Auto generation of table data.
|
|
|
229 |
*
|
|
|
230 |
* it will output to db_oo_{database} the table definitions
|
|
|
231 |
*
|
|
|
232 |
* @access private
|
|
|
233 |
* @return none
|
|
|
234 |
*/
|
|
|
235 |
function generateDefinitions()
|
|
|
236 |
{
|
|
|
237 |
$this->debug("Generating Definitions file: ");
|
|
|
238 |
if (!$this->tables) {
|
|
|
239 |
$this->debug("-- NO TABLES -- \n");
|
|
|
240 |
return;
|
|
|
241 |
}
|
|
|
242 |
|
|
|
243 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
244 |
|
|
|
245 |
|
|
|
246 |
//$this->_newConfig = new Config('IniFile');
|
|
|
247 |
$this->_newConfig = '';
|
|
|
248 |
foreach($this->tables as $this->table) {
|
|
|
249 |
$this->_generateDefinitionsTable();
|
|
|
250 |
}
|
|
|
251 |
$this->_connect();
|
|
|
252 |
// dont generate a schema if location is not set
|
|
|
253 |
// it's created on the fly!
|
|
|
254 |
if (!@$options['schema_location'] && @!$options["ini_{$this->_database}"] ) {
|
|
|
255 |
return;
|
|
|
256 |
}
|
|
|
257 |
$base = @$options['schema_location'];
|
|
|
258 |
if (isset($options["ini_{$this->_database}"])) {
|
|
|
259 |
$file = $options["ini_{$this->_database}"];
|
|
|
260 |
} else {
|
|
|
261 |
$file = "{$base}/{$this->_database}.ini";
|
|
|
262 |
}
|
|
|
263 |
|
|
|
264 |
if (!file_exists(dirname($file))) {
|
|
|
265 |
require_once 'System.php';
|
|
|
266 |
System::mkdir(array('-p','-m',0755,dirname($file)));
|
|
|
267 |
}
|
|
|
268 |
$this->debug("Writing ini as {$file}\n");
|
|
|
269 |
touch($file);
|
|
|
270 |
//print_r($this->_newConfig);
|
|
|
271 |
$fh = fopen($file,'w');
|
|
|
272 |
fwrite($fh,$this->_newConfig);
|
|
|
273 |
fclose($fh);
|
|
|
274 |
//$ret = $this->_newConfig->writeInput($file,false);
|
|
|
275 |
|
|
|
276 |
//if (PEAR::isError($ret) ) {
|
|
|
277 |
// return PEAR::raiseError($ret->message,null,PEAR_ERROR_DIE);
|
|
|
278 |
// }
|
|
|
279 |
}
|
|
|
280 |
|
|
|
281 |
/**
|
|
|
282 |
* The table geneation part
|
|
|
283 |
*
|
|
|
284 |
* @access private
|
|
|
285 |
* @return tabledef and keys array.
|
|
|
286 |
*/
|
|
|
287 |
function _generateDefinitionsTable()
|
|
|
288 |
{
|
|
|
289 |
global $_DB_DATAOBJECT;
|
|
|
290 |
|
|
|
291 |
$defs = $this->_definitions[$this->table];
|
|
|
292 |
$this->_newConfig .= "\n[{$this->table}]\n";
|
|
|
293 |
$keys_out = "\n[{$this->table}__keys]\n";
|
|
|
294 |
$keys_out_primary = '';
|
|
|
295 |
$keys_out_secondary = '';
|
|
|
296 |
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) {
|
|
|
297 |
echo "TABLE STRUCTURE FOR {$this->table}\n";
|
|
|
298 |
print_r($defs);
|
|
|
299 |
}
|
|
|
300 |
$DB = $this->getDatabaseConnection();
|
|
|
301 |
$dbtype = $DB->phptype;
|
|
|
302 |
|
|
|
303 |
$ret = array(
|
|
|
304 |
'table' => array(),
|
|
|
305 |
'keys' => array(),
|
|
|
306 |
);
|
|
|
307 |
|
|
|
308 |
$ret_keys_primary = array();
|
|
|
309 |
$ret_keys_secondary = array();
|
|
|
310 |
|
|
|
311 |
|
|
|
312 |
|
|
|
313 |
foreach($defs as $t) {
|
|
|
314 |
|
|
|
315 |
$n=0;
|
|
|
316 |
|
|
|
317 |
switch (strtoupper($t->type)) {
|
|
|
318 |
|
|
|
319 |
case 'INT':
|
|
|
320 |
case 'INT2': // postgres
|
|
|
321 |
case 'INT4': // postgres
|
|
|
322 |
case 'INT8': // postgres
|
|
|
323 |
case 'SERIAL4': // postgres
|
|
|
324 |
case 'SERIAL8': // postgres
|
|
|
325 |
case 'INTEGER':
|
|
|
326 |
case 'TINYINT':
|
|
|
327 |
case 'SMALLINT':
|
|
|
328 |
case 'MEDIUMINT':
|
|
|
329 |
case 'BIGINT':
|
|
|
330 |
$type = DB_DATAOBJECT_INT;
|
|
|
331 |
if ($t->len == 1) {
|
|
|
332 |
$type += DB_DATAOBJECT_BOOL;
|
|
|
333 |
}
|
|
|
334 |
break;
|
|
|
335 |
|
|
|
336 |
case 'REAL':
|
|
|
337 |
case 'DOUBLE':
|
|
|
338 |
case 'FLOAT':
|
|
|
339 |
case 'FLOAT8': // double precision (postgres)
|
|
|
340 |
case 'DECIMAL':
|
|
|
341 |
case 'NUMERIC':
|
|
|
342 |
case 'NUMBER': // oci8
|
|
|
343 |
$type = DB_DATAOBJECT_INT; // should really by FLOAT!!! / MONEY...
|
|
|
344 |
break;
|
|
|
345 |
|
|
|
346 |
case 'YEAR':
|
|
|
347 |
$type = DB_DATAOBJECT_INT;
|
|
|
348 |
break;
|
|
|
349 |
|
|
|
350 |
case 'BIT':
|
|
|
351 |
case 'BOOL':
|
|
|
352 |
case 'BOOLEAN':
|
|
|
353 |
|
|
|
354 |
$type = DB_DATAOBJECT_BOOL;
|
|
|
355 |
// postgres needs to quote '0'
|
|
|
356 |
if ($dbtype == 'pgsql') {
|
|
|
357 |
$type += DB_DATAOBJECT_STR;
|
|
|
358 |
}
|
|
|
359 |
break;
|
|
|
360 |
|
|
|
361 |
case 'STRING':
|
|
|
362 |
case 'CHAR':
|
|
|
363 |
case 'VARCHAR':
|
|
|
364 |
case 'VARCHAR2':
|
|
|
365 |
case 'TINYTEXT':
|
|
|
366 |
|
|
|
367 |
case 'ENUM':
|
|
|
368 |
case 'SET': // not really but oh well
|
|
|
369 |
case 'TIMESTAMPTZ': // postgres
|
|
|
370 |
case 'BPCHAR': // postgres
|
|
|
371 |
case 'INTERVAL': // postgres (eg. '12 days')
|
|
|
372 |
|
|
|
373 |
case 'CIDR': // postgres IP net spec
|
|
|
374 |
case 'INET': // postgres IP
|
|
|
375 |
case 'MACADDR': // postgress network Mac address.
|
|
|
376 |
|
|
|
377 |
|
|
|
378 |
$type = DB_DATAOBJECT_STR;
|
|
|
379 |
break;
|
|
|
380 |
|
|
|
381 |
case 'TEXT':
|
|
|
382 |
case 'MEDIUMTEXT':
|
|
|
383 |
case 'LONGTEXT':
|
|
|
384 |
|
|
|
385 |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_TXT;
|
|
|
386 |
break;
|
|
|
387 |
|
|
|
388 |
|
|
|
389 |
case 'DATE':
|
|
|
390 |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE;
|
|
|
391 |
break;
|
|
|
392 |
|
|
|
393 |
case 'TIME':
|
|
|
394 |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_TIME;
|
|
|
395 |
break;
|
|
|
396 |
|
|
|
397 |
|
|
|
398 |
case 'DATETIME':
|
|
|
399 |
|
|
|
400 |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME;
|
|
|
401 |
break;
|
|
|
402 |
|
|
|
403 |
case 'TIMESTAMP': // do other databases use this???
|
|
|
404 |
|
|
|
405 |
$type = ($dbtype == 'mysql') ?
|
|
|
406 |
DB_DATAOBJECT_MYSQLTIMESTAMP :
|
|
|
407 |
DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME;
|
|
|
408 |
break;
|
|
|
409 |
|
|
|
410 |
|
|
|
411 |
case 'TINYBLOB':
|
|
|
412 |
case 'BLOB': /// these should really be ignored!!!???
|
|
|
413 |
case 'MEDIUMBLOB':
|
|
|
414 |
case 'LONGBLOB':
|
|
|
415 |
case 'BYTEA': // postgres blob support..
|
|
|
416 |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_BLOB;
|
|
|
417 |
break;
|
|
|
418 |
|
|
|
419 |
|
|
|
420 |
}
|
|
|
421 |
|
|
|
422 |
|
|
|
423 |
if (!strlen(trim($t->name))) {
|
|
|
424 |
continue;
|
|
|
425 |
}
|
|
|
426 |
|
|
|
427 |
if (preg_match('/not_null/i',$t->flags)) {
|
|
|
428 |
$type += DB_DATAOBJECT_NOTNULL;
|
|
|
429 |
}
|
|
|
430 |
|
|
|
431 |
$write_ini = true;
|
|
|
432 |
if (in_array($t->name,array('null','yes','no','true','false'))) {
|
|
|
433 |
echo "*****************************************************************\n".
|
|
|
434 |
"** WARNING **\n".
|
|
|
435 |
"** Found column '{$t->name}', which is invalid in an .ini file **\n".
|
|
|
436 |
"** This line will not be writen to the file - you will have **\n".
|
|
|
437 |
"** define the keys()/method manually. **\n".
|
|
|
438 |
"*****************************************************************\n";
|
|
|
439 |
$write_ini = false;
|
|
|
440 |
} else {
|
|
|
441 |
$this->_newConfig .= "{$t->name} = $type\n";
|
|
|
442 |
}
|
|
|
443 |
|
|
|
444 |
$ret['table'][$t->name] = $type;
|
|
|
445 |
// i've no idea if this will work well on other databases?
|
|
|
446 |
// only use primary key or nextval(), cause the setFrom blocks you setting all key items...
|
|
|
447 |
// if no keys exist fall back to using unique
|
|
|
448 |
//echo "\n{$t->name} => {$t->flags}\n";
|
|
|
449 |
if (preg_match("/(auto_increment|nextval\()/i",rawurldecode($t->flags))) {
|
|
|
450 |
// native sequences = 2
|
|
|
451 |
if ($write_ini) {
|
|
|
452 |
$keys_out_primary .= "{$t->name} = N\n";
|
|
|
453 |
}
|
|
|
454 |
$ret_keys_primary[$t->name] = 'N';
|
|
|
455 |
|
|
|
456 |
} else if (preg_match("/(primary|unique)/i",$t->flags)) {
|
|
|
457 |
// keys.. = 1
|
|
|
458 |
if ($write_ini) {
|
|
|
459 |
$keys_out_secondary .= "{$t->name} = K\n";
|
|
|
460 |
}
|
|
|
461 |
$ret_keys_secondary[$t->name] = 'K';
|
|
|
462 |
}
|
|
|
463 |
|
|
|
464 |
|
|
|
465 |
}
|
|
|
466 |
|
|
|
467 |
$this->_newConfig .= $keys_out . (empty($keys_out_primary) ? $keys_out_secondary : $keys_out_primary);
|
|
|
468 |
$ret['keys'] = empty($keys_out_primary) ? $ret_keys_secondary : $ret_keys_primary;
|
|
|
469 |
|
|
|
470 |
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) {
|
|
|
471 |
print_r(array("dump for {$this->table}", $ret));
|
|
|
472 |
}
|
|
|
473 |
|
|
|
474 |
return $ret;
|
|
|
475 |
|
|
|
476 |
|
|
|
477 |
}
|
|
|
478 |
|
|
|
479 |
/*
|
|
|
480 |
* building the class files
|
|
|
481 |
* for each of the tables output a file!
|
|
|
482 |
*/
|
|
|
483 |
function generateClasses()
|
|
|
484 |
{
|
|
|
485 |
//echo "Generating Class files: \n";
|
|
|
486 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
487 |
$base = $options['class_location'];
|
|
|
488 |
if (strpos($base,'%s') !== false) {
|
|
|
489 |
$base = dirname($base);
|
|
|
490 |
}
|
|
|
491 |
|
|
|
492 |
|
|
|
493 |
if (!file_exists($base)) {
|
|
|
494 |
require_once 'System.php';
|
|
|
495 |
System::mkdir(array('-p',$base));
|
|
|
496 |
}
|
|
|
497 |
$class_prefix = $options['class_prefix'];
|
|
|
498 |
if ($extends = @$options['extends']) {
|
|
|
499 |
$this->_extends = $extends;
|
|
|
500 |
$this->_extendsFile = $options['extends_location'];
|
|
|
501 |
}
|
|
|
502 |
|
|
|
503 |
foreach($this->tables as $this->table) {
|
|
|
504 |
$this->table = trim($this->table);
|
|
|
505 |
$this->classname = $class_prefix.preg_replace('/[^A-Z0-9]/i','_',ucfirst($this->table));
|
|
|
506 |
$i = '';
|
|
|
507 |
|
|
|
508 |
if (strpos($options['class_location'],'%s') !== false) {
|
|
|
509 |
$outfilename = sprintf($options['class_location'], preg_replace('/[^A-Z0-9]/i','_',ucfirst($this->table)));
|
|
|
510 |
} else {
|
|
|
511 |
$outfilename = "{$base}/".preg_replace('/[^A-Z0-9]/i','_',ucfirst($this->table)).".php";
|
|
|
512 |
}
|
|
|
513 |
$oldcontents = '';
|
|
|
514 |
if (file_exists($outfilename)) {
|
|
|
515 |
// file_get_contents???
|
|
|
516 |
$oldcontents = implode('',file($outfilename));
|
|
|
517 |
}
|
|
|
518 |
$out = $this->_generateClassTable($oldcontents);
|
|
|
519 |
$this->debug( "writing $this->classname\n");
|
|
|
520 |
$fh = fopen($outfilename, "w");
|
|
|
521 |
fputs($fh,$out);
|
|
|
522 |
fclose($fh);
|
|
|
523 |
}
|
|
|
524 |
//echo $out;
|
|
|
525 |
}
|
|
|
526 |
|
|
|
527 |
/**
|
|
|
528 |
* class being extended (can be overridden by [DB_DataObject_Generator] extends=xxxx
|
|
|
529 |
*
|
|
|
530 |
* @var string
|
|
|
531 |
* @access private
|
|
|
532 |
*/
|
|
|
533 |
var $_extends = 'DB_DataObject';
|
|
|
534 |
|
|
|
535 |
/**
|
|
|
536 |
* line to use for require('DB/DataObject.php');
|
|
|
537 |
*
|
|
|
538 |
* @var string
|
|
|
539 |
* @access private
|
|
|
540 |
*/
|
|
|
541 |
var $_extendsFile = "DB/DataObject.php";
|
|
|
542 |
|
|
|
543 |
/**
|
|
|
544 |
* class being generated
|
|
|
545 |
*
|
|
|
546 |
* @var string
|
|
|
547 |
* @access private
|
|
|
548 |
*/
|
|
|
549 |
var $_className;
|
|
|
550 |
|
|
|
551 |
/**
|
|
|
552 |
* The table class geneation part - single file.
|
|
|
553 |
*
|
|
|
554 |
* @access private
|
|
|
555 |
* @return none
|
|
|
556 |
*/
|
|
|
557 |
function _generateClassTable($input = '')
|
|
|
558 |
{
|
|
|
559 |
// title = expand me!
|
|
|
560 |
$foot = "";
|
|
|
561 |
$head = "<?php\n/**\n * Table Definition for {$this->table}\n */\n";
|
|
|
562 |
// requires
|
|
|
563 |
$head .= "require_once '{$this->_extendsFile}';\n\n";
|
|
|
564 |
// add dummy class header in...
|
|
|
565 |
// class
|
|
|
566 |
$head .= "class {$this->classname} extends {$this->_extends} \n{";
|
|
|
567 |
|
|
|
568 |
$body = "\n ###START_AUTOCODE\n";
|
|
|
569 |
$body .= " /* the code below is auto generated do not remove the above tag */\n\n";
|
|
|
570 |
// table
|
|
|
571 |
$padding = (30 - strlen($this->table));
|
|
|
572 |
if ($padding < 2) $padding =2;
|
|
|
573 |
$p = str_repeat(' ',$padding) ;
|
|
|
574 |
|
|
|
575 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
576 |
|
|
|
577 |
|
|
|
578 |
$var = (substr(phpversion(),0,1) > 4) ? 'public' : 'var';
|
|
|
579 |
$body .= " {$var} \$__table = '{$this->table}'; {$p}// table name\n";
|
|
|
580 |
|
|
|
581 |
|
|
|
582 |
// if we are using the option database_{databasename} = dsn
|
|
|
583 |
// then we should add var $_database = here
|
|
|
584 |
// as database names may not always match..
|
|
|
585 |
|
|
|
586 |
if (isset($options["database_{$this->_database}"])) {
|
|
|
587 |
$body .= " {$var} \$_database = '{$this->_database}'; {$p}// database name (used with database_{*} config)\n";
|
|
|
588 |
}
|
|
|
589 |
|
|
|
590 |
$var = (substr(phpversion(),0,1) > 4) ? 'public' : 'var';
|
|
|
591 |
if (!empty($options['generator_novars'])) {
|
|
|
592 |
$var = '//'.$var;
|
|
|
593 |
}
|
|
|
594 |
|
|
|
595 |
$defs = $this->_definitions[$this->table];
|
|
|
596 |
|
|
|
597 |
// show nice information!
|
|
|
598 |
$connections = array();
|
|
|
599 |
$sets = array();
|
|
|
600 |
foreach($defs as $t) {
|
|
|
601 |
if (!strlen(trim($t->name))) {
|
|
|
602 |
continue;
|
|
|
603 |
}
|
|
|
604 |
$padding = (30 - strlen($t->name));
|
|
|
605 |
if ($padding < 2) $padding =2;
|
|
|
606 |
$p = str_repeat(' ',$padding) ;
|
|
|
607 |
|
|
|
608 |
$body .=" {$var} \${$t->name}; {$p}// {$t->type}({$t->len}) {$t->flags}\n";
|
|
|
609 |
|
|
|
610 |
// can not do set as PEAR::DB table info doesnt support it.
|
|
|
611 |
//if (substr($t->Type,0,3) == "set")
|
|
|
612 |
// $sets[$t->Field] = "array".substr($t->Type,3);
|
|
|
613 |
$body .= $this->derivedHookVar($t,$padding);
|
|
|
614 |
}
|
|
|
615 |
|
|
|
616 |
// THIS IS TOTALLY BORKED old FC creation
|
|
|
617 |
// IT WILL BE REMOVED!!!!! in DataObjects 1.6
|
|
|
618 |
// grep -r __clone * to find all it's uses
|
|
|
619 |
// and replace them with $x = clone($y);
|
|
|
620 |
// due to the change in the PHP5 clone design.
|
|
|
621 |
|
|
|
622 |
if ( substr(phpversion(),0,1) < 5) {
|
|
|
623 |
$body .= "\n";
|
|
|
624 |
$body .= " /* ZE2 compatibility trick*/\n";
|
|
|
625 |
$body .= " function __clone() { return \$this;}\n";
|
|
|
626 |
}
|
|
|
627 |
|
|
|
628 |
// simple creation tools ! (static stuff!)
|
|
|
629 |
$body .= "\n";
|
|
|
630 |
$body .= " /* Static get */\n";
|
|
|
631 |
$body .= " function staticGet(\$k,\$v=NULL) { return DB_DataObject::staticGet('{$this->classname}',\$k,\$v); }\n";
|
|
|
632 |
|
|
|
633 |
// generate getter and setter methods
|
|
|
634 |
$body .= $this->_generateGetters($input);
|
|
|
635 |
$body .= $this->_generateSetters($input);
|
|
|
636 |
|
|
|
637 |
/*
|
|
|
638 |
theoretically there is scope here to introduce 'list' methods
|
|
|
639 |
based up 'xxxx_up' column!!! for heiracitcal trees..
|
|
|
640 |
*/
|
|
|
641 |
|
|
|
642 |
// set methods
|
|
|
643 |
//foreach ($sets as $k=>$v) {
|
|
|
644 |
// $kk = strtoupper($k);
|
|
|
645 |
// $body .=" function getSets{$k}() { return {$v}; }\n";
|
|
|
646 |
//}
|
|
|
647 |
$body .= $this->derivedHookFunctions();
|
|
|
648 |
|
|
|
649 |
$body .= "\n /* the code above is auto generated do not remove the tag below */";
|
|
|
650 |
$body .= "\n ###END_AUTOCODE\n";
|
|
|
651 |
|
|
|
652 |
|
|
|
653 |
// stubs..
|
|
|
654 |
|
|
|
655 |
if (!empty($options['generator_add_validate_stubs'])) {
|
|
|
656 |
foreach($defs as $t) {
|
|
|
657 |
if (!strlen(trim($t->name))) {
|
|
|
658 |
continue;
|
|
|
659 |
}
|
|
|
660 |
$validate_fname = 'validate' . ucfirst(strtolower($t->name));
|
|
|
661 |
// dont re-add it..
|
|
|
662 |
if (preg_match('/\s+function\s+' . $validate_fname . '\s*\(/i', $input)) {
|
|
|
663 |
continue;
|
|
|
664 |
}
|
|
|
665 |
$body .= "\n function {$validate_fname}()\n {\n return false;\n }\n";
|
|
|
666 |
}
|
|
|
667 |
}
|
|
|
668 |
|
|
|
669 |
|
|
|
670 |
|
|
|
671 |
|
|
|
672 |
$foot .= "}\n";
|
|
|
673 |
$full = $head . $body . $foot;
|
|
|
674 |
|
|
|
675 |
if (!$input) {
|
|
|
676 |
return $full;
|
|
|
677 |
}
|
|
|
678 |
if (!preg_match('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n)/s',$input)) {
|
|
|
679 |
return $full;
|
|
|
680 |
}
|
|
|
681 |
if (!preg_match('/(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s',$input)) {
|
|
|
682 |
return $full;
|
|
|
683 |
}
|
|
|
684 |
|
|
|
685 |
|
|
|
686 |
/* this will only replace extends DB_DataObject by default,
|
|
|
687 |
unless use set generator_class_rewrite to ANY or a name*/
|
|
|
688 |
|
|
|
689 |
$class_rewrite = 'DB_DataObject';
|
|
|
690 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
691 |
if (!($class_rewrite = @$options['generator_class_rewrite'])) {
|
|
|
692 |
$class_rewrite = 'DB_DataObject';
|
|
|
693 |
}
|
|
|
694 |
if ($class_rewrite == 'ANY') {
|
|
|
695 |
$class_rewrite = '[a-z_]+';
|
|
|
696 |
}
|
|
|
697 |
|
|
|
698 |
$input = preg_replace(
|
|
|
699 |
'/(\n|\r\n)class\s*[a-z0-9_]+\s*extends\s*' .$class_rewrite . '\s*\{(\n|\r\n)/si',
|
|
|
700 |
"\nclass {$this->classname} extends {$this->_extends} \n{\n",
|
|
|
701 |
$input);
|
|
|
702 |
|
|
|
703 |
return preg_replace(
|
|
|
704 |
'/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s',
|
|
|
705 |
$body,$input);
|
|
|
706 |
}
|
|
|
707 |
|
|
|
708 |
/**
|
|
|
709 |
* hook to add extra methods to all classes
|
|
|
710 |
*
|
|
|
711 |
* called once for each class, use with $this->table and
|
|
|
712 |
* $this->_definitions[$this->table], to get data out of the current table,
|
|
|
713 |
* use it to add extra methods to the default classes.
|
|
|
714 |
*
|
|
|
715 |
* @access public
|
|
|
716 |
* @return string added to class eg. functions.
|
|
|
717 |
*/
|
|
|
718 |
function derivedHookFunctions()
|
|
|
719 |
{
|
|
|
720 |
// This is so derived generator classes can generate functions
|
|
|
721 |
// It MUST NOT be changed here!!!
|
|
|
722 |
return "";
|
|
|
723 |
}
|
|
|
724 |
|
|
|
725 |
/**
|
|
|
726 |
* hook for var lines
|
|
|
727 |
* called each time a var line is generated, override to add extra var
|
|
|
728 |
* lines
|
|
|
729 |
*
|
|
|
730 |
* @param object t containing type,len,flags etc. from tableInfo call
|
|
|
731 |
* @param int padding number of spaces
|
|
|
732 |
* @access public
|
|
|
733 |
* @return string added to class eg. functions.
|
|
|
734 |
*/
|
|
|
735 |
function derivedHookVar(&$t,$padding)
|
|
|
736 |
{
|
|
|
737 |
// This is so derived generator classes can generate variabels
|
|
|
738 |
// It MUST NOT be changed here!!!
|
|
|
739 |
return "";
|
|
|
740 |
}
|
|
|
741 |
|
|
|
742 |
|
|
|
743 |
/**
|
|
|
744 |
* getProxyFull - create a class definition on the fly and instantate it..
|
|
|
745 |
*
|
|
|
746 |
* similar to generated files - but also evals the class definitoin code.
|
|
|
747 |
*
|
|
|
748 |
*
|
|
|
749 |
* @param string database name
|
|
|
750 |
* @param string table name of table to create proxy for.
|
|
|
751 |
*
|
|
|
752 |
*
|
|
|
753 |
* @return object Instance of class. or PEAR Error
|
|
|
754 |
* @access public
|
|
|
755 |
*/
|
|
|
756 |
function getProxyFull($database,$table) {
|
|
|
757 |
|
|
|
758 |
if ($err = $this->fillTableSchema($database,$table)) {
|
|
|
759 |
return $err;
|
|
|
760 |
}
|
|
|
761 |
|
|
|
762 |
|
|
|
763 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
764 |
$class_prefix = $options['class_prefix'];
|
|
|
765 |
|
|
|
766 |
if ($extends = @$options['extends']) {
|
|
|
767 |
$this->_extends = $extends;
|
|
|
768 |
$this->_extendsFile = $options['extends_location'];
|
|
|
769 |
}
|
|
|
770 |
|
|
|
771 |
|
|
|
772 |
$classname = $this->classname = $class_prefix.preg_replace('/[^A-Z0-9]/i','_',ucfirst(trim($this->table)));
|
|
|
773 |
|
|
|
774 |
$out = $this->_generateClassTable();
|
|
|
775 |
//echo $out;
|
|
|
776 |
eval('?>'.$out);
|
|
|
777 |
return new $classname;
|
|
|
778 |
|
|
|
779 |
}
|
|
|
780 |
|
|
|
781 |
/**
|
|
|
782 |
* fillTableSchema - set the database schema on the fly
|
|
|
783 |
*
|
|
|
784 |
*
|
|
|
785 |
*
|
|
|
786 |
* @param string database name
|
|
|
787 |
* @param string table name of table to create schema info for
|
|
|
788 |
*
|
|
|
789 |
* @return none | PEAR::error()
|
|
|
790 |
* @access public
|
|
|
791 |
*/
|
|
|
792 |
function fillTableSchema($database,$table) {
|
|
|
793 |
global $_DB_DATAOBJECT;
|
|
|
794 |
$this->_database = $database;
|
|
|
795 |
|
|
|
796 |
$this->_connect();
|
|
|
797 |
$table = trim($table);
|
|
|
798 |
|
|
|
799 |
$__DB= &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
|
|
|
800 |
|
|
|
801 |
$defs = $__DB->tableInfo($table);
|
|
|
802 |
if (PEAR::isError($defs)) {
|
|
|
803 |
return $defs;
|
|
|
804 |
}
|
|
|
805 |
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) {
|
|
|
806 |
$this->debug("getting def for $database/$table",'fillTable');
|
|
|
807 |
$this->debug(print_r($defs,true),'defs');
|
|
|
808 |
}
|
|
|
809 |
// cast all definitions to objects - as we deal with that better.
|
|
|
810 |
|
|
|
811 |
|
|
|
812 |
foreach($defs as $def) {
|
|
|
813 |
if (is_array($def)) {
|
|
|
814 |
$this->_definitions[$table][] = (object) $def;
|
|
|
815 |
}
|
|
|
816 |
}
|
|
|
817 |
|
|
|
818 |
$this->table = trim($table);
|
|
|
819 |
$ret = $this->_generateDefinitionsTable();
|
|
|
820 |
|
|
|
821 |
$_DB_DATAOBJECT['INI'][$database][$table] = $ret['table'];
|
|
|
822 |
$_DB_DATAOBJECT['INI'][$database][$table.'__keys'] = $ret['keys'];
|
|
|
823 |
return false;
|
|
|
824 |
|
|
|
825 |
}
|
|
|
826 |
|
|
|
827 |
/**
|
|
|
828 |
* Generate getter methods for class definition
|
|
|
829 |
*
|
|
|
830 |
* @param string $input Existing class contents
|
|
|
831 |
* @return string
|
|
|
832 |
* @access public
|
|
|
833 |
*/
|
|
|
834 |
function _generateGetters($input) {
|
|
|
835 |
|
|
|
836 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
837 |
$getters = '';
|
|
|
838 |
|
|
|
839 |
// only generate if option is set to true
|
|
|
840 |
if (empty($options['generate_getters'])) {
|
|
|
841 |
return '';
|
|
|
842 |
}
|
|
|
843 |
|
|
|
844 |
// remove auto-generated code from input to be able to check if the method exists outside of the auto-code
|
|
|
845 |
$input = preg_replace('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', '', $input);
|
|
|
846 |
|
|
|
847 |
$getters .= "\n\n";
|
|
|
848 |
$defs = $this->_definitions[$this->table];
|
|
|
849 |
|
|
|
850 |
// loop through properties and create getter methods
|
|
|
851 |
foreach ($defs = $defs as $t) {
|
|
|
852 |
|
|
|
853 |
// build mehtod name
|
|
|
854 |
$methodName = 'get' . ucfirst($t->name);
|
|
|
855 |
|
|
|
856 |
if (!strlen(trim($t->name)) || preg_match("/function[\s]+[&]?$methodName\(/i", $input)) {
|
|
|
857 |
continue;
|
|
|
858 |
}
|
|
|
859 |
|
|
|
860 |
$getters .= " /**\n";
|
|
|
861 |
$getters .= " * Getter for \${$t->name}\n";
|
|
|
862 |
$getters .= " *\n";
|
|
|
863 |
$getters .= (stristr($t->flags, 'multiple_key')) ? " * @return object\n"
|
|
|
864 |
: " * @return {$t->type}\n";
|
|
|
865 |
$getters .= " * @access public\n";
|
|
|
866 |
$getters .= " */\n";
|
|
|
867 |
$getters .= (substr(phpversion(),0,1) > 4) ? ' public '
|
|
|
868 |
: ' ';
|
|
|
869 |
$getters .= "function $methodName() {\n";
|
|
|
870 |
$getters .= " return \$this->{$t->name};\n";
|
|
|
871 |
$getters .= " }\n\n";
|
|
|
872 |
}
|
|
|
873 |
|
|
|
874 |
|
|
|
875 |
return $getters;
|
|
|
876 |
}
|
|
|
877 |
|
|
|
878 |
|
|
|
879 |
/**
|
|
|
880 |
* Generate setter methods for class definition
|
|
|
881 |
*
|
|
|
882 |
* @param string Existing class contents
|
|
|
883 |
* @return string
|
|
|
884 |
* @access public
|
|
|
885 |
*/
|
|
|
886 |
function _generateSetters($input) {
|
|
|
887 |
|
|
|
888 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
889 |
$setters = '';
|
|
|
890 |
|
|
|
891 |
// only generate if option is set to true
|
|
|
892 |
if (empty($options['generate_setters'])) {
|
|
|
893 |
return '';
|
|
|
894 |
}
|
|
|
895 |
|
|
|
896 |
// remove auto-generated code from input to be able to check if the method exists outside of the auto-code
|
|
|
897 |
$input = preg_replace('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', '', $input);
|
|
|
898 |
|
|
|
899 |
$setters .= "\n";
|
|
|
900 |
$defs = $this->_definitions[$this->table];
|
|
|
901 |
|
|
|
902 |
// loop through properties and create setter methods
|
|
|
903 |
foreach ($defs = $defs as $t) {
|
|
|
904 |
|
|
|
905 |
// build mehtod name
|
|
|
906 |
$methodName = 'set' . ucfirst($t->name);
|
|
|
907 |
|
|
|
908 |
if (!strlen(trim($t->name)) || preg_match("/function[\s]+[&]?$methodName\(/i", $input)) {
|
|
|
909 |
continue;
|
|
|
910 |
}
|
|
|
911 |
|
|
|
912 |
$setters .= " /**\n";
|
|
|
913 |
$setters .= " * Setter for \${$t->name}\n";
|
|
|
914 |
$setters .= " *\n";
|
|
|
915 |
$setters .= " * @param mixed input value\n";
|
|
|
916 |
$setters .= " * @access public\n";
|
|
|
917 |
$setters .= " */\n";
|
|
|
918 |
$setters .= (substr(phpversion(),0,1) > 4) ? ' public '
|
|
|
919 |
: ' ';
|
|
|
920 |
$setters .= "function $methodName(\$value) {\n";
|
|
|
921 |
$setters .= " \$this->{$t->name} = \$value;\n";
|
|
|
922 |
$setters .= " }\n\n";
|
|
|
923 |
}
|
|
|
924 |
|
|
|
925 |
|
|
|
926 |
return $setters;
|
|
|
927 |
}
|
|
|
928 |
|
|
|
929 |
}
|