| 1 |
lars |
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.01 of the PHP license
|
|
|
8 |
* that is available through the world-wide-web at the following URI:
|
|
|
9 |
* http://www.php.net/license/3_01.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-2006 The PHP Group
|
|
|
17 |
* @license http://www.php.net/license/3_01.txt PHP License 3.01
|
|
|
18 |
* @version CVS: $Id: Generator.php 315531 2011-08-26 02:21:29Z alan_k $
|
|
|
19 |
* @link http://pear.php.net/package/DB_DataObject
|
|
|
20 |
*/
|
|
|
21 |
|
|
|
22 |
/*
|
|
|
23 |
* Security Notes:
|
|
|
24 |
* This class uses eval to create classes on the fly.
|
|
|
25 |
* The table name and database name are used to check the database before writing the
|
|
|
26 |
* class definitions, we now check for quotes and semi-colon's in both variables
|
|
|
27 |
* so I cant see how it would be possible to generate code even if
|
|
|
28 |
* for some crazy reason you took the classname and table name from User Input.
|
|
|
29 |
*
|
|
|
30 |
* If you consider that wrong, or can prove it.. let me know!
|
|
|
31 |
*/
|
|
|
32 |
|
|
|
33 |
/**
|
|
|
34 |
*
|
|
|
35 |
* Config _$ptions
|
|
|
36 |
* [DB_DataObject]
|
|
|
37 |
* ; optional default = DB/DataObject.php
|
|
|
38 |
* extends_location =
|
|
|
39 |
* ; optional default = DB_DataObject
|
|
|
40 |
* extends =
|
|
|
41 |
* ; alter the extends field when updating a class (defaults to only replacing DB_DataObject)
|
|
|
42 |
* generator_class_rewrite = ANY|specific_name // default is DB_DataObject
|
|
|
43 |
*
|
|
|
44 |
*/
|
|
|
45 |
|
|
|
46 |
/**
|
|
|
47 |
* Needed classes
|
|
|
48 |
* We lazy load here, due to problems with the tests not setting up include path correctly.
|
|
|
49 |
* FIXME!
|
|
|
50 |
*/
|
|
|
51 |
class_exists('DB_DataObject') ? '' : require_once 'DB/DataObject.php';
|
|
|
52 |
//require_once('Config.php');
|
|
|
53 |
|
|
|
54 |
/**
|
|
|
55 |
* Generator class
|
|
|
56 |
*
|
|
|
57 |
* @package DB_DataObject
|
|
|
58 |
*/
|
|
|
59 |
class DB_DataObject_Generator extends DB_DataObject
|
|
|
60 |
{
|
|
|
61 |
/* =========================================================== */
|
|
|
62 |
/* Utility functions - for building db config files */
|
|
|
63 |
/* =========================================================== */
|
|
|
64 |
|
|
|
65 |
/**
|
|
|
66 |
* Array of table names
|
|
|
67 |
*
|
|
|
68 |
* @var array
|
|
|
69 |
* @access private
|
|
|
70 |
*/
|
|
|
71 |
var $tables;
|
|
|
72 |
|
|
|
73 |
/**
|
|
|
74 |
* associative array table -> array of table row objects
|
|
|
75 |
*
|
|
|
76 |
* @var array
|
|
|
77 |
* @access private
|
|
|
78 |
*/
|
|
|
79 |
var $_definitions;
|
|
|
80 |
|
|
|
81 |
/**
|
|
|
82 |
* active table being output
|
|
|
83 |
*
|
|
|
84 |
* @var string
|
|
|
85 |
* @access private
|
|
|
86 |
*/
|
|
|
87 |
var $table; // active tablename
|
|
|
88 |
|
|
|
89 |
|
|
|
90 |
/**
|
|
|
91 |
* The 'starter' = call this to start the process
|
|
|
92 |
*
|
|
|
93 |
* @access public
|
|
|
94 |
* @return none
|
|
|
95 |
*/
|
|
|
96 |
function start()
|
|
|
97 |
{
|
|
|
98 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
99 |
$db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
|
|
|
100 |
|
|
|
101 |
$databases = array();
|
|
|
102 |
foreach($options as $k=>$v) {
|
|
|
103 |
if (substr($k,0,9) == 'database_') {
|
|
|
104 |
$databases[substr($k,9)] = $v;
|
|
|
105 |
}
|
|
|
106 |
}
|
|
|
107 |
|
|
|
108 |
if (isset($options['database'])) {
|
|
|
109 |
if ($db_driver == 'DB') {
|
|
|
110 |
require_once 'DB.php';
|
|
|
111 |
$dsn = DB::parseDSN($options['database']);
|
|
|
112 |
} else {
|
|
|
113 |
require_once 'MDB2.php';
|
|
|
114 |
$dsn = MDB2::parseDSN($options['database']);
|
|
|
115 |
}
|
|
|
116 |
|
|
|
117 |
if (!isset($database[$dsn['database']])) {
|
|
|
118 |
$databases[$dsn['database']] = $options['database'];
|
|
|
119 |
}
|
|
|
120 |
}
|
|
|
121 |
|
|
|
122 |
foreach($databases as $databasename => $database) {
|
|
|
123 |
if (!$database) {
|
|
|
124 |
continue;
|
|
|
125 |
}
|
|
|
126 |
$this->debug("CREATING FOR $databasename\n");
|
|
|
127 |
$class = get_class($this);
|
|
|
128 |
$t = new $class;
|
|
|
129 |
$t->_database_dsn = $database;
|
|
|
130 |
|
|
|
131 |
|
|
|
132 |
$t->_database = $databasename;
|
|
|
133 |
if ($db_driver == 'DB') {
|
|
|
134 |
require_once 'DB.php';
|
|
|
135 |
$dsn = DB::parseDSN($database);
|
|
|
136 |
} else {
|
|
|
137 |
require_once 'MDB2.php';
|
|
|
138 |
$dsn = MDB2::parseDSN($database);
|
|
|
139 |
}
|
|
|
140 |
|
|
|
141 |
if (($dsn['phptype'] == 'sqlite') && is_file($databasename)) {
|
|
|
142 |
$t->_database = basename($t->_database);
|
|
|
143 |
}
|
|
|
144 |
$t->_createTableList();
|
|
|
145 |
|
|
|
146 |
foreach(get_class_methods($class) as $method) {
|
|
|
147 |
if (substr($method,0,8 ) != 'generate') {
|
|
|
148 |
continue;
|
|
|
149 |
}
|
|
|
150 |
$this->debug("calling $method");
|
|
|
151 |
$t->$method();
|
|
|
152 |
}
|
|
|
153 |
}
|
|
|
154 |
$this->debug("DONE\n\n");
|
|
|
155 |
}
|
|
|
156 |
|
|
|
157 |
/**
|
|
|
158 |
* Output File was config object, now just string
|
|
|
159 |
* Used to generate the Tables
|
|
|
160 |
*
|
|
|
161 |
* @var string outputbuffer for table definitions
|
|
|
162 |
* @access private
|
|
|
163 |
*/
|
|
|
164 |
var $_newConfig;
|
|
|
165 |
|
|
|
166 |
/**
|
|
|
167 |
* Build a list of tables;
|
|
|
168 |
* and store it in $this->tables and $this->_definitions[tablename];
|
|
|
169 |
*
|
|
|
170 |
* @access private
|
|
|
171 |
* @return none
|
|
|
172 |
*/
|
|
|
173 |
function _createTableList()
|
|
|
174 |
{
|
|
|
175 |
$this->_connect();
|
|
|
176 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
177 |
|
|
|
178 |
$__DB= &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
|
|
|
179 |
|
|
|
180 |
$db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
|
|
|
181 |
$is_MDB2 = ($db_driver != 'DB') ? true : false;
|
|
|
182 |
|
|
|
183 |
if (is_object($__DB) && is_a($__DB , 'PEAR_Error')) {
|
|
|
184 |
return PEAR::raiseError($__DB->toString(), null, PEAR_ERROR_DIE);
|
|
|
185 |
}
|
|
|
186 |
|
|
|
187 |
if (!$is_MDB2) {
|
|
|
188 |
// try getting a list of schema tables first. (postgres)
|
|
|
189 |
$__DB->expectError(DB_ERROR_UNSUPPORTED);
|
|
|
190 |
$this->tables = $__DB->getListOf('schema.tables');
|
|
|
191 |
$__DB->popExpect();
|
|
|
192 |
} else {
|
|
|
193 |
/**
|
|
|
194 |
* set portability and some modules to fetch the informations
|
|
|
195 |
*/
|
|
|
196 |
$db_options = PEAR::getStaticProperty('MDB2','options');
|
|
|
197 |
if (empty($db_options)) {
|
|
|
198 |
$__DB->setOption('portability', MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE);
|
|
|
199 |
}
|
|
|
200 |
|
|
|
201 |
$__DB->loadModule('Manager');
|
|
|
202 |
$__DB->loadModule('Reverse');
|
|
|
203 |
}
|
|
|
204 |
|
|
|
205 |
if ((empty($this->tables) || (is_object($this->tables) && is_a($this->tables , 'PEAR_Error')))) {
|
|
|
206 |
//if that fails fall back to clasic tables list.
|
|
|
207 |
if (!$is_MDB2) {
|
|
|
208 |
// try getting a list of schema tables first. (postgres)
|
|
|
209 |
$__DB->expectError(DB_ERROR_UNSUPPORTED);
|
|
|
210 |
$this->tables = $__DB->getListOf('tables');
|
|
|
211 |
$__DB->popExpect();
|
|
|
212 |
} else {
|
|
|
213 |
$this->tables = $__DB->manager->listTables();
|
|
|
214 |
$sequences = $__DB->manager->listSequences();
|
|
|
215 |
foreach ($sequences as $k => $v) {
|
|
|
216 |
$this->tables[] = $__DB->getSequenceName($v);
|
|
|
217 |
}
|
|
|
218 |
}
|
|
|
219 |
}
|
|
|
220 |
|
|
|
221 |
if (is_object($this->tables) && is_a($this->tables , 'PEAR_Error')) {
|
|
|
222 |
return PEAR::raiseError($this->tables->toString(), null, PEAR_ERROR_DIE);
|
|
|
223 |
}
|
|
|
224 |
|
|
|
225 |
// build views as well if asked to.
|
|
|
226 |
if (!empty($options['build_views'])) {
|
|
|
227 |
if (!$is_MDB2) {
|
|
|
228 |
$views = $__DB->getListOf('views');
|
|
|
229 |
} else {
|
|
|
230 |
$views = $__DB->manager->listViews();
|
|
|
231 |
}
|
|
|
232 |
if (is_object($views) && is_a($views,'PEAR_Error')) {
|
|
|
233 |
return PEAR::raiseError(
|
|
|
234 |
'Error getting Views (check the PEAR bug database for the fix to DB), ' .
|
|
|
235 |
$views->toString(),
|
|
|
236 |
null,
|
|
|
237 |
PEAR_ERROR_DIE
|
|
|
238 |
);
|
|
|
239 |
}
|
|
|
240 |
$this->tables = array_merge ($this->tables, $views);
|
|
|
241 |
}
|
|
|
242 |
|
|
|
243 |
// declare a temporary table to be filled with matching tables names
|
|
|
244 |
$tmp_table = array();
|
|
|
245 |
|
|
|
246 |
|
|
|
247 |
foreach($this->tables as $table) {
|
|
|
248 |
if (isset($options['generator_include_regex']) &&
|
|
|
249 |
!preg_match($options['generator_include_regex'],$table)) {
|
|
|
250 |
continue;
|
|
|
251 |
} else if (isset($options['generator_exclude_regex']) &&
|
|
|
252 |
preg_match($options['generator_exclude_regex'],$table)) {
|
|
|
253 |
continue;
|
|
|
254 |
}
|
|
|
255 |
// postgres strip the schema bit from the
|
|
|
256 |
if (!empty($options['generator_strip_schema'])) {
|
|
|
257 |
$bits = explode('.', $table,2);
|
|
|
258 |
$table = $bits[0];
|
|
|
259 |
if (count($bits) > 1) {
|
|
|
260 |
$table = $bits[1];
|
|
|
261 |
}
|
|
|
262 |
}
|
|
|
263 |
$quotedTable = !empty($options['quote_identifiers_tableinfo']) ?
|
|
|
264 |
$__DB->quoteIdentifier($table) : $table;
|
|
|
265 |
|
|
|
266 |
if (!$is_MDB2) {
|
|
|
267 |
|
|
|
268 |
$defs = $__DB->tableInfo($quotedTable);
|
|
|
269 |
} else {
|
|
|
270 |
$defs = $__DB->reverse->tableInfo($quotedTable);
|
|
|
271 |
// rename the length value, so it matches db's return.
|
|
|
272 |
|
|
|
273 |
}
|
|
|
274 |
|
|
|
275 |
if (is_object($defs) && is_a($defs,'PEAR_Error')) {
|
|
|
276 |
// running in debug mode should pick this up as a big warning..
|
|
|
277 |
$this->raiseError('Error reading tableInfo, '. $defs->toString());
|
|
|
278 |
continue;
|
|
|
279 |
}
|
|
|
280 |
// cast all definitions to objects - as we deal with that better.
|
|
|
281 |
|
|
|
282 |
|
|
|
283 |
|
|
|
284 |
foreach($defs as $def) {
|
|
|
285 |
if (!is_array($def)) {
|
|
|
286 |
continue;
|
|
|
287 |
}
|
|
|
288 |
// rename the length value, so it matches db's return.
|
|
|
289 |
if (isset($def['length']) && !isset($def['len'])) {
|
|
|
290 |
$def['len'] = $def['length'];
|
|
|
291 |
}
|
|
|
292 |
$this->_definitions[$table][] = (object) $def;
|
|
|
293 |
|
|
|
294 |
}
|
|
|
295 |
// we find a matching table, just store it into a temporary array
|
|
|
296 |
$tmp_table[] = $table;
|
|
|
297 |
|
|
|
298 |
|
|
|
299 |
}
|
|
|
300 |
// the temporary table array is now the right one (tables names matching
|
|
|
301 |
// with regex expressions have been removed)
|
|
|
302 |
$this->tables = $tmp_table;
|
|
|
303 |
//print_r($this->_definitions);
|
|
|
304 |
}
|
|
|
305 |
|
|
|
306 |
/**
|
|
|
307 |
* Auto generation of table data.
|
|
|
308 |
*
|
|
|
309 |
* it will output to db_oo_{database} the table definitions
|
|
|
310 |
*
|
|
|
311 |
* @access private
|
|
|
312 |
* @return none
|
|
|
313 |
*/
|
|
|
314 |
function generateDefinitions()
|
|
|
315 |
{
|
|
|
316 |
$this->debug("Generating Definitions file: ");
|
|
|
317 |
if (!$this->tables) {
|
|
|
318 |
$this->debug("-- NO TABLES -- \n");
|
|
|
319 |
return;
|
|
|
320 |
}
|
|
|
321 |
|
|
|
322 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
323 |
|
|
|
324 |
|
|
|
325 |
//$this->_newConfig = new Config('IniFile');
|
|
|
326 |
$this->_newConfig = '';
|
|
|
327 |
foreach($this->tables as $this->table) {
|
|
|
328 |
$this->_generateDefinitionsTable();
|
|
|
329 |
}
|
|
|
330 |
$this->_connect();
|
|
|
331 |
// dont generate a schema if location is not set
|
|
|
332 |
// it's created on the fly!
|
|
|
333 |
if (empty($options['schema_location']) && empty($options["ini_{$this->_database}"]) ) {
|
|
|
334 |
return;
|
|
|
335 |
}
|
|
|
336 |
if (!empty($options['generator_no_ini'])) { // built in ini files..
|
|
|
337 |
return;
|
|
|
338 |
}
|
|
|
339 |
$base = @$options['schema_location'];
|
|
|
340 |
if (isset($options["ini_{$this->_database}"])) {
|
|
|
341 |
$file = $options["ini_{$this->_database}"];
|
|
|
342 |
} else {
|
|
|
343 |
$file = "{$base}/{$this->_database}.ini";
|
|
|
344 |
}
|
|
|
345 |
|
|
|
346 |
if (!file_exists(dirname($file))) {
|
|
|
347 |
require_once 'System.php';
|
|
|
348 |
System::mkdir(array('-p','-m',0755,dirname($file)));
|
|
|
349 |
}
|
|
|
350 |
$this->debug("Writing ini as {$file}\n");
|
|
|
351 |
//touch($file);
|
|
|
352 |
$tmpname = tempnam(session_save_path(),'DataObject_');
|
|
|
353 |
//print_r($this->_newConfig);
|
|
|
354 |
$fh = fopen($tmpname,'w');
|
|
|
355 |
fwrite($fh,$this->_newConfig);
|
|
|
356 |
fclose($fh);
|
|
|
357 |
$perms = file_exists($file) ? fileperms($file) : 0755;
|
|
|
358 |
// windows can fail doing this. - not a perfect solution but otherwise it's getting really kludgy..
|
|
|
359 |
|
|
|
360 |
if (!@rename($tmpname, $file)) {
|
|
|
361 |
unlink($file);
|
|
|
362 |
rename($tmpname, $file);
|
|
|
363 |
}
|
|
|
364 |
chmod($file,$perms);
|
|
|
365 |
//$ret = $this->_newConfig->writeInput($file,false);
|
|
|
366 |
|
|
|
367 |
//if (PEAR::isError($ret) ) {
|
|
|
368 |
// return PEAR::raiseError($ret->message,null,PEAR_ERROR_DIE);
|
|
|
369 |
// }
|
|
|
370 |
}
|
|
|
371 |
|
|
|
372 |
/**
|
|
|
373 |
* generate Foreign Keys (for links.ini)
|
|
|
374 |
* Currenly only works with mysql / mysqli
|
|
|
375 |
* to use, you must set option: generate_links=true
|
|
|
376 |
*
|
|
|
377 |
* @author Pascal Schöni
|
|
|
378 |
*/
|
|
|
379 |
function generateForeignKeys()
|
|
|
380 |
{
|
|
|
381 |
$options = PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
382 |
if (empty($options['generate_links'])) {
|
|
|
383 |
return false;
|
|
|
384 |
}
|
|
|
385 |
$__DB = &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
|
|
|
386 |
if (!in_array($__DB->phptype, array('mysql', 'mysqli', 'pgsql'))) {
|
|
|
387 |
echo "WARNING: cant handle non-mysql and pgsql introspection for defaults.";
|
|
|
388 |
return; // cant handle non-mysql introspection for defaults.
|
|
|
389 |
}
|
|
|
390 |
|
|
|
391 |
$DB = $this->getDatabaseConnection();
|
|
|
392 |
|
|
|
393 |
$fk = array();
|
|
|
394 |
|
|
|
395 |
|
|
|
396 |
switch ($DB->phptype) {
|
|
|
397 |
|
|
|
398 |
|
|
|
399 |
case 'pgsql':
|
|
|
400 |
foreach($this->tables as $this->table) {
|
|
|
401 |
$quotedTable = !empty($options['quote_identifiers_tableinfo']) ? $DB->quoteIdentifier($table) : $this->table;
|
|
|
402 |
$res =& $DB->query("SELECT
|
|
|
403 |
pg_catalog.pg_get_constraintdef(r.oid, true) AS condef
|
|
|
404 |
FROM pg_catalog.pg_constraint r,
|
|
|
405 |
pg_catalog.pg_class c
|
|
|
406 |
WHERE c.oid=r.conrelid
|
|
|
407 |
AND r.contype = 'f'
|
|
|
408 |
AND c.relname = '" . $quotedTable . "'");
|
|
|
409 |
if (PEAR::isError($res)) {
|
|
|
410 |
die($res->getMessage());
|
|
|
411 |
}
|
|
|
412 |
|
|
|
413 |
while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
|
|
|
414 |
$treffer = array();
|
|
|
415 |
// this only picks up one of these.. see this for why: http://pear.php.net/bugs/bug.php?id=17049
|
|
|
416 |
preg_match(
|
|
|
417 |
"/FOREIGN KEY \((\w*)\) REFERENCES (\w*)\((\w*)\)/i",
|
|
|
418 |
$row['condef'],
|
|
|
419 |
$treffer);
|
|
|
420 |
if (!count($treffer)) {
|
|
|
421 |
continue;
|
|
|
422 |
}
|
|
|
423 |
$fk[$this->table][$treffer[1]] = $treffer[2] . ":" . $treffer[3];
|
|
|
424 |
}
|
|
|
425 |
}
|
|
|
426 |
break;
|
|
|
427 |
|
|
|
428 |
|
|
|
429 |
case 'mysql':
|
|
|
430 |
case 'mysqli':
|
|
|
431 |
default:
|
|
|
432 |
|
|
|
433 |
foreach($this->tables as $this->table) {
|
|
|
434 |
$quotedTable = !empty($options['quote_identifiers_tableinfo']) ? $DB->quoteIdentifier($table) : $this->table;
|
|
|
435 |
|
|
|
436 |
$res =& $DB->query('SHOW CREATE TABLE ' . $quotedTable );
|
|
|
437 |
|
|
|
438 |
if (PEAR::isError($res)) {
|
|
|
439 |
die($res->getMessage());
|
|
|
440 |
}
|
|
|
441 |
|
|
|
442 |
$text = $res->fetchRow(DB_FETCHMODE_DEFAULT, 0);
|
|
|
443 |
$treffer = array();
|
|
|
444 |
// Extract FOREIGN KEYS
|
|
|
445 |
preg_match_all(
|
|
|
446 |
"/FOREIGN KEY \(`(\w*)`\) REFERENCES `(\w*)` \(`(\w*)`\)/i",
|
|
|
447 |
$text[1],
|
|
|
448 |
$treffer,
|
|
|
449 |
PREG_SET_ORDER);
|
|
|
450 |
|
|
|
451 |
if (!count($treffer)) {
|
|
|
452 |
continue;
|
|
|
453 |
}
|
|
|
454 |
foreach($treffer as $i=> $tref) {
|
|
|
455 |
$fk[$this->table][$tref[1]] = $tref[2] . ":" . $tref[3];
|
|
|
456 |
}
|
|
|
457 |
|
|
|
458 |
}
|
|
|
459 |
|
|
|
460 |
}
|
|
|
461 |
$links_ini = "";
|
|
|
462 |
|
|
|
463 |
foreach($fk as $table => $details) {
|
|
|
464 |
$links_ini .= "[$table]\n";
|
|
|
465 |
foreach ($details as $col => $ref) {
|
|
|
466 |
$links_ini .= "$col = $ref\n";
|
|
|
467 |
}
|
|
|
468 |
$links_ini .= "\n";
|
|
|
469 |
}
|
|
|
470 |
|
|
|
471 |
// dont generate a schema if location is not set
|
|
|
472 |
// it's created on the fly!
|
|
|
473 |
$options = PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
474 |
|
|
|
475 |
if (empty($options['schema_location'])) {
|
|
|
476 |
return;
|
|
|
477 |
}
|
|
|
478 |
|
|
|
479 |
|
|
|
480 |
$file = "{$options['schema_location']}/{$this->_database}.links.ini";
|
|
|
481 |
|
|
|
482 |
if (!file_exists(dirname($file))) {
|
|
|
483 |
require_once 'System.php';
|
|
|
484 |
System::mkdir(array('-p','-m',0755,dirname($file)));
|
|
|
485 |
}
|
|
|
486 |
|
|
|
487 |
$this->debug("Writing ini as {$file}\n");
|
|
|
488 |
|
|
|
489 |
//touch($file); // not sure why this is needed?
|
|
|
490 |
$tmpname = tempnam(session_save_path(),'DataObject_');
|
|
|
491 |
|
|
|
492 |
$fh = fopen($tmpname,'w');
|
|
|
493 |
fwrite($fh,$links_ini);
|
|
|
494 |
fclose($fh);
|
|
|
495 |
$perms = file_exists($file) ? fileperms($file) : 0755;
|
|
|
496 |
// windows can fail doing this. - not a perfect solution but otherwise it's getting really kludgy..
|
|
|
497 |
if (!@rename($tmpname, $file)) {
|
|
|
498 |
unlink($file);
|
|
|
499 |
rename($tmpname, $file);
|
|
|
500 |
}
|
|
|
501 |
chmod($file, $perms);
|
|
|
502 |
}
|
|
|
503 |
|
|
|
504 |
|
|
|
505 |
/**
|
|
|
506 |
* The table geneation part
|
|
|
507 |
*
|
|
|
508 |
* @access private
|
|
|
509 |
* @return tabledef and keys array.
|
|
|
510 |
*/
|
|
|
511 |
function _generateDefinitionsTable()
|
|
|
512 |
{
|
|
|
513 |
global $_DB_DATAOBJECT;
|
|
|
514 |
$options = PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
515 |
$defs = $this->_definitions[$this->table];
|
|
|
516 |
$this->_newConfig .= "\n[{$this->table}]\n";
|
|
|
517 |
$keys_out = "\n[{$this->table}__keys]\n";
|
|
|
518 |
$keys_out_primary = '';
|
|
|
519 |
$keys_out_secondary = '';
|
|
|
520 |
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) {
|
|
|
521 |
echo "TABLE STRUCTURE FOR {$this->table}\n";
|
|
|
522 |
print_r($defs);
|
|
|
523 |
}
|
|
|
524 |
$DB = $this->getDatabaseConnection();
|
|
|
525 |
$dbtype = $DB->phptype;
|
|
|
526 |
|
|
|
527 |
$ret = array(
|
|
|
528 |
'table' => array(),
|
|
|
529 |
'keys' => array(),
|
|
|
530 |
);
|
|
|
531 |
|
|
|
532 |
$ret_keys_primary = array();
|
|
|
533 |
$ret_keys_secondary = array();
|
|
|
534 |
|
|
|
535 |
|
|
|
536 |
|
|
|
537 |
foreach($defs as $t) {
|
|
|
538 |
|
|
|
539 |
$n=0;
|
|
|
540 |
$write_ini = true;
|
|
|
541 |
|
|
|
542 |
|
|
|
543 |
switch (strtoupper($t->type)) {
|
|
|
544 |
|
|
|
545 |
case 'INT':
|
|
|
546 |
case 'INT2': // postgres
|
|
|
547 |
case 'INT4': // postgres
|
|
|
548 |
case 'INT8': // postgres
|
|
|
549 |
case 'SERIAL4': // postgres
|
|
|
550 |
case 'SERIAL8': // postgres
|
|
|
551 |
case 'INTEGER':
|
|
|
552 |
case 'TINYINT':
|
|
|
553 |
case 'SMALLINT':
|
|
|
554 |
case 'MEDIUMINT':
|
|
|
555 |
case 'BIGINT':
|
|
|
556 |
$type = DB_DATAOBJECT_INT;
|
|
|
557 |
if ($t->len == 1) {
|
|
|
558 |
$type += DB_DATAOBJECT_BOOL;
|
|
|
559 |
}
|
|
|
560 |
break;
|
|
|
561 |
|
|
|
562 |
case 'REAL':
|
|
|
563 |
case 'DOUBLE':
|
|
|
564 |
case 'DOUBLE PRECISION': // double precision (firebird)
|
|
|
565 |
case 'FLOAT':
|
|
|
566 |
case 'FLOAT4': // real (postgres)
|
|
|
567 |
case 'FLOAT8': // double precision (postgres)
|
|
|
568 |
case 'DECIMAL':
|
|
|
569 |
case 'MONEY': // mssql and maybe others
|
|
|
570 |
case 'NUMERIC':
|
|
|
571 |
case 'NUMBER': // oci8
|
|
|
572 |
$type = DB_DATAOBJECT_INT; // should really by FLOAT!!! / MONEY...
|
|
|
573 |
break;
|
|
|
574 |
|
|
|
575 |
case 'YEAR':
|
|
|
576 |
$type = DB_DATAOBJECT_INT;
|
|
|
577 |
break;
|
|
|
578 |
|
|
|
579 |
case 'BIT':
|
|
|
580 |
case 'BOOL':
|
|
|
581 |
case 'BOOLEAN':
|
|
|
582 |
|
|
|
583 |
$type = DB_DATAOBJECT_BOOL;
|
|
|
584 |
// postgres needs to quote '0'
|
|
|
585 |
if ($dbtype == 'pgsql') {
|
|
|
586 |
$type += DB_DATAOBJECT_STR;
|
|
|
587 |
}
|
|
|
588 |
break;
|
|
|
589 |
|
|
|
590 |
case 'STRING':
|
|
|
591 |
case 'CHAR':
|
|
|
592 |
case 'VARCHAR':
|
|
|
593 |
case 'VARCHAR2':
|
|
|
594 |
case 'TINYTEXT':
|
|
|
595 |
|
|
|
596 |
case 'ENUM':
|
|
|
597 |
case 'SET': // not really but oh well
|
|
|
598 |
|
|
|
599 |
case 'POINT': // mysql geometry stuff - not really string - but will do..
|
|
|
600 |
|
|
|
601 |
case 'TIMESTAMPTZ': // postgres
|
|
|
602 |
case 'BPCHAR': // postgres
|
|
|
603 |
case 'INTERVAL': // postgres (eg. '12 days')
|
|
|
604 |
|
|
|
605 |
case 'CIDR': // postgres IP net spec
|
|
|
606 |
case 'INET': // postgres IP
|
|
|
607 |
case 'MACADDR': // postgress network Mac address.
|
|
|
608 |
|
|
|
609 |
case 'INTEGER[]': // postgres type
|
|
|
610 |
case 'BOOLEAN[]': // postgres type
|
|
|
611 |
|
|
|
612 |
$type = DB_DATAOBJECT_STR;
|
|
|
613 |
break;
|
|
|
614 |
|
|
|
615 |
case 'TEXT':
|
|
|
616 |
case 'MEDIUMTEXT':
|
|
|
617 |
case 'LONGTEXT':
|
|
|
618 |
|
|
|
619 |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_TXT;
|
|
|
620 |
break;
|
|
|
621 |
|
|
|
622 |
|
|
|
623 |
case 'DATE':
|
|
|
624 |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE;
|
|
|
625 |
break;
|
|
|
626 |
|
|
|
627 |
case 'TIME':
|
|
|
628 |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_TIME;
|
|
|
629 |
break;
|
|
|
630 |
|
|
|
631 |
|
|
|
632 |
case 'DATETIME':
|
|
|
633 |
|
|
|
634 |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME;
|
|
|
635 |
break;
|
|
|
636 |
|
|
|
637 |
case 'TIMESTAMP': // do other databases use this???
|
|
|
638 |
|
|
|
639 |
$type = ($dbtype == 'mysql') ?
|
|
|
640 |
DB_DATAOBJECT_MYSQLTIMESTAMP :
|
|
|
641 |
DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME;
|
|
|
642 |
break;
|
|
|
643 |
|
|
|
644 |
|
|
|
645 |
case 'BLOB': /// these should really be ignored!!!???
|
|
|
646 |
case 'TINYBLOB':
|
|
|
647 |
case 'MEDIUMBLOB':
|
|
|
648 |
case 'LONGBLOB':
|
|
|
649 |
|
|
|
650 |
case 'CLOB': // oracle character lob support
|
|
|
651 |
|
|
|
652 |
case 'BYTEA': // postgres blob support..
|
|
|
653 |
$type = DB_DATAOBJECT_STR + DB_DATAOBJECT_BLOB;
|
|
|
654 |
break;
|
|
|
655 |
|
|
|
656 |
default:
|
|
|
657 |
echo "*****************************************************************\n".
|
|
|
658 |
"** WARNING UNKNOWN TYPE **\n".
|
|
|
659 |
"** Found column '{$t->name}', of type '{$t->type}' **\n".
|
|
|
660 |
"** Please submit a bug, describe what type you expect this **\n".
|
|
|
661 |
"** column to be **\n".
|
|
|
662 |
"** ---------POSSIBLE FIX / WORKAROUND -------------------------**\n".
|
|
|
663 |
"** Try using MDB2 as the backend - eg set the config option **\n".
|
|
|
664 |
"** db_driver = MDB2 **\n".
|
|
|
665 |
"*****************************************************************\n";
|
|
|
666 |
$write_ini = false;
|
|
|
667 |
break;
|
|
|
668 |
}
|
|
|
669 |
|
|
|
670 |
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $t->name)) {
|
|
|
671 |
echo "*****************************************************************\n".
|
|
|
672 |
"** WARNING COLUMN NAME UNUSABLE **\n".
|
|
|
673 |
"** Found column '{$t->name}', of type '{$t->type}' **\n".
|
|
|
674 |
"** Since this column name can't be converted to a php variable **\n".
|
|
|
675 |
"** name, and the whole idea of mapping would result in a mess **\n".
|
|
|
676 |
"** This column has been ignored... **\n".
|
|
|
677 |
"*****************************************************************\n";
|
|
|
678 |
continue;
|
|
|
679 |
}
|
|
|
680 |
|
|
|
681 |
if (!strlen(trim($t->name))) {
|
|
|
682 |
continue; // is this a bug?
|
|
|
683 |
}
|
|
|
684 |
|
|
|
685 |
if (preg_match('/not[ _]null/i',$t->flags)) {
|
|
|
686 |
$type += DB_DATAOBJECT_NOTNULL;
|
|
|
687 |
}
|
|
|
688 |
|
|
|
689 |
|
|
|
690 |
if (in_array($t->name,array('null','yes','no','true','false'))) {
|
|
|
691 |
echo "*****************************************************************\n".
|
|
|
692 |
"** WARNING **\n".
|
|
|
693 |
"** Found column '{$t->name}', which is invalid in an .ini file **\n".
|
|
|
694 |
"** This line will not be writen to the file - you will have **\n".
|
|
|
695 |
"** define the keys()/method manually. **\n".
|
|
|
696 |
"*****************************************************************\n";
|
|
|
697 |
$write_ini = false;
|
|
|
698 |
} else {
|
|
|
699 |
$this->_newConfig .= "{$t->name} = $type\n";
|
|
|
700 |
}
|
|
|
701 |
|
|
|
702 |
$ret['table'][$t->name] = $type;
|
|
|
703 |
// i've no idea if this will work well on other databases?
|
|
|
704 |
// only use primary key or nextval(), cause the setFrom blocks you setting all key items...
|
|
|
705 |
// if no keys exist fall back to using unique
|
|
|
706 |
//echo "\n{$t->name} => {$t->flags}\n";
|
|
|
707 |
$secondary_key_match = isset($options['generator_secondary_key_match']) ? $options['generator_secondary_key_match'] : 'primary|unique';
|
|
|
708 |
|
|
|
709 |
if (preg_match('/(auto_increment|nextval\()/i',rawurldecode($t->flags))
|
|
|
710 |
|| (isset($t->autoincrement) && ($t->autoincrement === true))) {
|
|
|
711 |
|
|
|
712 |
// native sequences = 2
|
|
|
713 |
if ($write_ini) {
|
|
|
714 |
$keys_out_primary .= "{$t->name} = N\n";
|
|
|
715 |
}
|
|
|
716 |
$ret_keys_primary[$t->name] = 'N';
|
|
|
717 |
|
|
|
718 |
} else if ($secondary_key_match && preg_match('/('.$secondary_key_match.')/i',$t->flags)) {
|
|
|
719 |
// keys.. = 1
|
|
|
720 |
$key_type = 'K';
|
|
|
721 |
if (!preg_match("/(primary)/i",$t->flags)) {
|
|
|
722 |
$key_type = 'U';
|
|
|
723 |
}
|
|
|
724 |
|
|
|
725 |
if ($write_ini) {
|
|
|
726 |
$keys_out_secondary .= "{$t->name} = {$key_type}\n";
|
|
|
727 |
}
|
|
|
728 |
$ret_keys_secondary[$t->name] = $key_type;
|
|
|
729 |
}
|
|
|
730 |
|
|
|
731 |
|
|
|
732 |
}
|
|
|
733 |
|
|
|
734 |
$this->_newConfig .= $keys_out . (empty($keys_out_primary) ? $keys_out_secondary : $keys_out_primary);
|
|
|
735 |
$ret['keys'] = empty($keys_out_primary) ? $ret_keys_secondary : $ret_keys_primary;
|
|
|
736 |
|
|
|
737 |
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) {
|
|
|
738 |
print_r(array("dump for {$this->table}", $ret));
|
|
|
739 |
}
|
|
|
740 |
|
|
|
741 |
return $ret;
|
|
|
742 |
|
|
|
743 |
|
|
|
744 |
}
|
|
|
745 |
|
|
|
746 |
/**
|
|
|
747 |
* Convert a table name into a class name -> override this if you want a different mapping
|
|
|
748 |
*
|
|
|
749 |
* @access public
|
|
|
750 |
* @return string class name;
|
|
|
751 |
*/
|
|
|
752 |
|
|
|
753 |
|
|
|
754 |
function getClassNameFromTableName($table)
|
|
|
755 |
{
|
|
|
756 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
757 |
$class_prefix = empty($options['class_prefix']) ? '' : $options['class_prefix'];
|
|
|
758 |
return $class_prefix.preg_replace('/[^A-Z0-9]/i','_',ucfirst(trim($this->table)));
|
|
|
759 |
}
|
|
|
760 |
|
|
|
761 |
|
|
|
762 |
/**
|
|
|
763 |
* Convert a table name into a file name -> override this if you want a different mapping
|
|
|
764 |
*
|
|
|
765 |
* @access public
|
|
|
766 |
* @return string file name;
|
|
|
767 |
*/
|
|
|
768 |
|
|
|
769 |
|
|
|
770 |
function getFileNameFromTableName($table)
|
|
|
771 |
{
|
|
|
772 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
773 |
$base = $options['class_location'];
|
|
|
774 |
if (strpos($base,'%s') !== false) {
|
|
|
775 |
$base = dirname($base);
|
|
|
776 |
}
|
|
|
777 |
if (!file_exists($base)) {
|
|
|
778 |
require_once 'System.php';
|
|
|
779 |
System::mkdir(array('-p',$base));
|
|
|
780 |
}
|
|
|
781 |
if (strpos($options['class_location'],'%s') !== false) {
|
|
|
782 |
$outfilename = sprintf($options['class_location'],
|
|
|
783 |
preg_replace('/[^A-Z0-9]/i','_',ucfirst($this->table)));
|
|
|
784 |
} else {
|
|
|
785 |
$outfilename = "{$base}/".preg_replace('/[^A-Z0-9]/i','_',ucfirst($this->table)).".php";
|
|
|
786 |
}
|
|
|
787 |
return $outfilename;
|
|
|
788 |
|
|
|
789 |
}
|
|
|
790 |
|
|
|
791 |
|
|
|
792 |
/**
|
|
|
793 |
* Convert a column name into a method name (usually prefixed by get/set/validateXXXXX)
|
|
|
794 |
*
|
|
|
795 |
* @access public
|
|
|
796 |
* @return string method name;
|
|
|
797 |
*/
|
|
|
798 |
|
|
|
799 |
|
|
|
800 |
function getMethodNameFromColumnName($col)
|
|
|
801 |
{
|
|
|
802 |
return ucfirst($col);
|
|
|
803 |
}
|
|
|
804 |
|
|
|
805 |
|
|
|
806 |
|
|
|
807 |
|
|
|
808 |
/*
|
|
|
809 |
* building the class files
|
|
|
810 |
* for each of the tables output a file!
|
|
|
811 |
*/
|
|
|
812 |
function generateClasses()
|
|
|
813 |
{
|
|
|
814 |
//echo "Generating Class files: \n";
|
|
|
815 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
816 |
|
|
|
817 |
$this->_extends = empty($options['extends']) ? $this->_extends : $options['extends'];
|
|
|
818 |
$this->_extendsFile = empty($options['extends_location']) ? $this->_extendsFile : $options['extends_location'];
|
|
|
819 |
|
|
|
820 |
|
|
|
821 |
foreach($this->tables as $this->table) {
|
|
|
822 |
$this->table = trim($this->table);
|
|
|
823 |
$this->classname = $this->getClassNameFromTableName($this->table);
|
|
|
824 |
$i = '';
|
|
|
825 |
$outfilename = $this->getFileNameFromTableName($this->table);
|
|
|
826 |
|
|
|
827 |
$oldcontents = '';
|
|
|
828 |
if (file_exists($outfilename)) {
|
|
|
829 |
// file_get_contents???
|
|
|
830 |
$oldcontents = implode('',file($outfilename));
|
|
|
831 |
}
|
|
|
832 |
|
|
|
833 |
$out = $this->_generateClassTable($oldcontents);
|
|
|
834 |
$this->debug( "writing $this->classname\n");
|
|
|
835 |
$tmpname = tempnam(session_save_path(),'DataObject_');
|
|
|
836 |
|
|
|
837 |
$fh = fopen($tmpname, "w");
|
|
|
838 |
fputs($fh,$out);
|
|
|
839 |
fclose($fh);
|
|
|
840 |
$perms = file_exists($outfilename) ? fileperms($outfilename) : 0755;
|
|
|
841 |
|
|
|
842 |
// windows can fail doing this. - not a perfect solution but otherwise it's getting really kludgy..
|
|
|
843 |
if (!@rename($tmpname, $outfilename)) {
|
|
|
844 |
unlink($outfilename);
|
|
|
845 |
rename($tmpname, $outfilename);
|
|
|
846 |
}
|
|
|
847 |
|
|
|
848 |
chmod($outfilename, $perms);
|
|
|
849 |
}
|
|
|
850 |
//echo $out;
|
|
|
851 |
}
|
|
|
852 |
|
|
|
853 |
/**
|
|
|
854 |
* class being extended (can be overridden by [DB_DataObject] extends=xxxx
|
|
|
855 |
*
|
|
|
856 |
* @var string
|
|
|
857 |
* @access private
|
|
|
858 |
*/
|
|
|
859 |
var $_extends = 'DB_DataObject';
|
|
|
860 |
|
|
|
861 |
/**
|
|
|
862 |
* line to use for require('DB/DataObject.php');
|
|
|
863 |
*
|
|
|
864 |
* @var string
|
|
|
865 |
* @access private
|
|
|
866 |
*/
|
|
|
867 |
var $_extendsFile = "DB/DataObject.php";
|
|
|
868 |
|
|
|
869 |
/**
|
|
|
870 |
* class being generated
|
|
|
871 |
*
|
|
|
872 |
* @var string
|
|
|
873 |
* @access private
|
|
|
874 |
*/
|
|
|
875 |
var $_className;
|
|
|
876 |
|
|
|
877 |
/**
|
|
|
878 |
* The table class geneation part - single file.
|
|
|
879 |
*
|
|
|
880 |
* @access private
|
|
|
881 |
* @return none
|
|
|
882 |
*/
|
|
|
883 |
function _generateClassTable($input = '')
|
|
|
884 |
{
|
|
|
885 |
// title = expand me!
|
|
|
886 |
$foot = "";
|
|
|
887 |
$head = "<?php\n/**\n * Table Definition for {$this->table}\n";
|
|
|
888 |
$head .= $this->derivedHookPageLevelDocBlock();
|
|
|
889 |
$head .= " */\n";
|
|
|
890 |
$head .= $this->derivedHookExtendsDocBlock();
|
|
|
891 |
|
|
|
892 |
|
|
|
893 |
// requires
|
|
|
894 |
$head .= "require_once '{$this->_extendsFile}';\n\n";
|
|
|
895 |
// add dummy class header in...
|
|
|
896 |
// class
|
|
|
897 |
$head .= $this->derivedHookClassDocBlock();
|
|
|
898 |
$head .= "class {$this->classname} extends {$this->_extends} \n{";
|
|
|
899 |
|
|
|
900 |
$body = "\n ###START_AUTOCODE\n";
|
|
|
901 |
$body .= " /* the code below is auto generated do not remove the above tag */\n\n";
|
|
|
902 |
// table
|
|
|
903 |
|
|
|
904 |
$p = str_repeat(' ',max(2, (18 - strlen($this->table)))) ;
|
|
|
905 |
|
|
|
906 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
907 |
|
|
|
908 |
|
|
|
909 |
$var = (substr(phpversion(),0,1) > 4) ? 'public' : 'var';
|
|
|
910 |
$var = !empty($options['generator_var_keyword']) ? $options['generator_var_keyword'] : $var;
|
|
|
911 |
|
|
|
912 |
|
|
|
913 |
$body .= " {$var} \$__table = '{$this->table}'; {$p}// table name\n";
|
|
|
914 |
|
|
|
915 |
|
|
|
916 |
// if we are using the option database_{databasename} = dsn
|
|
|
917 |
// then we should add var $_database = here
|
|
|
918 |
// as database names may not always match..
|
|
|
919 |
|
|
|
920 |
if (empty($GLOBALS['_DB_DATAOBJECT']['CONFIG'])) {
|
|
|
921 |
DB_DataObject::_loadConfig();
|
|
|
922 |
}
|
|
|
923 |
|
|
|
924 |
// Only include the $_database property if the omit_database_var is unset or false
|
|
|
925 |
|
|
|
926 |
if (isset($options["database_{$this->_database}"]) && empty($GLOBALS['_DB_DATAOBJECT']['CONFIG']['generator_omit_database_var'])) {
|
|
|
927 |
$p = str_repeat(' ', max(2, (16 - strlen($this->table))));
|
|
|
928 |
$body .= " {$var} \$_database = '{$this->_database}'; {$p}// database name (used with database_{*} config)\n";
|
|
|
929 |
}
|
|
|
930 |
|
|
|
931 |
|
|
|
932 |
if (!empty($options['generator_novars'])) {
|
|
|
933 |
$var = '//'.$var;
|
|
|
934 |
}
|
|
|
935 |
|
|
|
936 |
$defs = $this->_definitions[$this->table];
|
|
|
937 |
|
|
|
938 |
// show nice information!
|
|
|
939 |
$connections = array();
|
|
|
940 |
$sets = array();
|
|
|
941 |
|
|
|
942 |
foreach($defs as $t) {
|
|
|
943 |
if (!strlen(trim($t->name))) {
|
|
|
944 |
continue;
|
|
|
945 |
}
|
|
|
946 |
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $t->name)) {
|
|
|
947 |
echo "*****************************************************************\n".
|
|
|
948 |
"** WARNING COLUMN NAME UNUSABLE **\n".
|
|
|
949 |
"** Found column '{$t->name}', of type '{$t->type}' **\n".
|
|
|
950 |
"** Since this column name can't be converted to a php variable **\n".
|
|
|
951 |
"** name, and the whole idea of mapping would result in a mess **\n".
|
|
|
952 |
"** This column has been ignored... **\n".
|
|
|
953 |
"*****************************************************************\n";
|
|
|
954 |
continue;
|
|
|
955 |
}
|
|
|
956 |
|
|
|
957 |
$p = str_repeat(' ',max(2, (30 - strlen($t->name))));
|
|
|
958 |
|
|
|
959 |
$length = empty($t->len) ? '' : '('.$t->len.')';
|
|
|
960 |
$body .=" {$var} \${$t->name}; {$p}// {$t->type}$length {$t->flags}\n";
|
|
|
961 |
|
|
|
962 |
// can not do set as PEAR::DB table info doesnt support it.
|
|
|
963 |
//if (substr($t->Type,0,3) == "set")
|
|
|
964 |
// $sets[$t->Field] = "array".substr($t->Type,3);
|
|
|
965 |
$body .= $this->derivedHookVar($t,strlen($p));
|
|
|
966 |
}
|
|
|
967 |
|
|
|
968 |
$body .= $this->derivedHookPostVar($defs);
|
|
|
969 |
|
|
|
970 |
// THIS IS TOTALLY BORKED old FC creation
|
|
|
971 |
// IT WILL BE REMOVED!!!!! in DataObjects 1.6
|
|
|
972 |
// grep -r __clone * to find all it's uses
|
|
|
973 |
// and replace them with $x = clone($y);
|
|
|
974 |
// due to the change in the PHP5 clone design.
|
|
|
975 |
|
|
|
976 |
if ( substr(phpversion(),0,1) < 5) {
|
|
|
977 |
$body .= "\n";
|
|
|
978 |
$body .= " /* ZE2 compatibility trick*/\n";
|
|
|
979 |
$body .= " function __clone() { return \$this;}\n";
|
|
|
980 |
}
|
|
|
981 |
|
|
|
982 |
// simple creation tools ! (static stuff!)
|
|
|
983 |
$body .= "\n";
|
|
|
984 |
$body .= " /* Static get */\n";
|
|
|
985 |
$body .= " function staticGet(\$k,\$v=NULL) { return DB_DataObject::staticGet('{$this->classname}',\$k,\$v); }\n";
|
|
|
986 |
|
|
|
987 |
// generate getter and setter methods
|
|
|
988 |
$body .= $this->_generateGetters($input);
|
|
|
989 |
$body .= $this->_generateSetters($input);
|
|
|
990 |
|
|
|
991 |
/*
|
|
|
992 |
theoretically there is scope here to introduce 'list' methods
|
|
|
993 |
based up 'xxxx_up' column!!! for heiracitcal trees..
|
|
|
994 |
*/
|
|
|
995 |
|
|
|
996 |
// set methods
|
|
|
997 |
//foreach ($sets as $k=>$v) {
|
|
|
998 |
// $kk = strtoupper($k);
|
|
|
999 |
// $body .=" function getSets{$k}() { return {$v}; }\n";
|
|
|
1000 |
//}
|
|
|
1001 |
|
|
|
1002 |
if (!empty($options['generator_no_ini'])) {
|
|
|
1003 |
$def = $this->_generateDefinitionsTable(); // simplify this!?
|
|
|
1004 |
$body .= $this->_generateTableFunction($def['table']);
|
|
|
1005 |
$body .= $this->_generateKeysFunction($def['keys']);
|
|
|
1006 |
$body .= $this->_generateSequenceKeyFunction($def);
|
|
|
1007 |
$body .= $this->_generateDefaultsFunction($this->table, $def['table']);
|
|
|
1008 |
} else if (!empty($options['generator_add_defaults'])) {
|
|
|
1009 |
// I dont really like doing it this way (adding another option)
|
|
|
1010 |
// but it helps on older projects.
|
|
|
1011 |
$def = $this->_generateDefinitionsTable(); // simplify this!?
|
|
|
1012 |
$body .= $this->_generateDefaultsFunction($this->table,$def['table']);
|
|
|
1013 |
|
|
|
1014 |
}
|
|
|
1015 |
$body .= $this->derivedHookFunctions($input);
|
|
|
1016 |
|
|
|
1017 |
$body .= "\n /* the code above is auto generated do not remove the tag below */";
|
|
|
1018 |
$body .= "\n ###END_AUTOCODE\n";
|
|
|
1019 |
|
|
|
1020 |
|
|
|
1021 |
// stubs..
|
|
|
1022 |
|
|
|
1023 |
if (!empty($options['generator_add_validate_stubs'])) {
|
|
|
1024 |
foreach($defs as $t) {
|
|
|
1025 |
if (!strlen(trim($t->name))) {
|
|
|
1026 |
continue;
|
|
|
1027 |
}
|
|
|
1028 |
$validate_fname = 'validate' . $this->getMethodNameFromColumnName($t->name);
|
|
|
1029 |
// dont re-add it..
|
|
|
1030 |
if (preg_match('/\s+function\s+' . $validate_fname . '\s*\(/i', $input)) {
|
|
|
1031 |
continue;
|
|
|
1032 |
}
|
|
|
1033 |
$body .= "\n function {$validate_fname}()\n {\n return false;\n }\n";
|
|
|
1034 |
}
|
|
|
1035 |
}
|
|
|
1036 |
|
|
|
1037 |
|
|
|
1038 |
|
|
|
1039 |
|
|
|
1040 |
$foot .= "}\n";
|
|
|
1041 |
$full = $head . $body . $foot;
|
|
|
1042 |
|
|
|
1043 |
if (!$input) {
|
|
|
1044 |
return $full;
|
|
|
1045 |
}
|
|
|
1046 |
if (!preg_match('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n)/s',$input)) {
|
|
|
1047 |
return $full;
|
|
|
1048 |
}
|
|
|
1049 |
if (!preg_match('/(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s',$input)) {
|
|
|
1050 |
return $full;
|
|
|
1051 |
}
|
|
|
1052 |
|
|
|
1053 |
|
|
|
1054 |
/* this will only replace extends DB_DataObject by default,
|
|
|
1055 |
unless use set generator_class_rewrite to ANY or a name*/
|
|
|
1056 |
|
|
|
1057 |
$class_rewrite = 'DB_DataObject';
|
|
|
1058 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
1059 |
if (empty($options['generator_class_rewrite']) || !($class_rewrite = $options['generator_class_rewrite'])) {
|
|
|
1060 |
$class_rewrite = 'DB_DataObject';
|
|
|
1061 |
}
|
|
|
1062 |
if ($class_rewrite == 'ANY') {
|
|
|
1063 |
$class_rewrite = '[a-z_]+';
|
|
|
1064 |
}
|
|
|
1065 |
|
|
|
1066 |
$input = preg_replace(
|
|
|
1067 |
'/(\n|\r\n)class\s*[a-z0-9_]+\s*extends\s*' .$class_rewrite . '\s*(\n|\r\n)\{(\n|\r\n)/si',
|
|
|
1068 |
"\nclass {$this->classname} extends {$this->_extends} \n{\n",
|
|
|
1069 |
$input);
|
|
|
1070 |
|
|
|
1071 |
$ret = preg_replace(
|
|
|
1072 |
'/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s',
|
|
|
1073 |
$body,$input);
|
|
|
1074 |
|
|
|
1075 |
if (!strlen($ret)) {
|
|
|
1076 |
return PEAR::raiseError(
|
|
|
1077 |
"PREG_REPLACE failed to replace body, - you probably need to set these in your php.ini\n".
|
|
|
1078 |
"pcre.backtrack_limit=1000000\n".
|
|
|
1079 |
"pcre.recursion_limit=1000000\n"
|
|
|
1080 |
,null, PEAR_ERROR_DIE);
|
|
|
1081 |
}
|
|
|
1082 |
|
|
|
1083 |
return $ret;
|
|
|
1084 |
}
|
|
|
1085 |
|
|
|
1086 |
/**
|
|
|
1087 |
* hook to add extra methods to all classes
|
|
|
1088 |
*
|
|
|
1089 |
* called once for each class, use with $this->table and
|
|
|
1090 |
* $this->_definitions[$this->table], to get data out of the current table,
|
|
|
1091 |
* use it to add extra methods to the default classes.
|
|
|
1092 |
*
|
|
|
1093 |
* @access public
|
|
|
1094 |
* @return string added to class eg. functions.
|
|
|
1095 |
*/
|
|
|
1096 |
function derivedHookFunctions($input = "")
|
|
|
1097 |
{
|
|
|
1098 |
// This is so derived generator classes can generate functions
|
|
|
1099 |
// It MUST NOT be changed here!!!
|
|
|
1100 |
return "";
|
|
|
1101 |
}
|
|
|
1102 |
|
|
|
1103 |
/**
|
|
|
1104 |
* hook for var lines
|
|
|
1105 |
* called each time a var line is generated, override to add extra var
|
|
|
1106 |
* lines
|
|
|
1107 |
*
|
|
|
1108 |
* @param object t containing type,len,flags etc. from tableInfo call
|
|
|
1109 |
* @param int padding number of spaces
|
|
|
1110 |
* @access public
|
|
|
1111 |
* @return string added to class eg. functions.
|
|
|
1112 |
*/
|
|
|
1113 |
function derivedHookVar(&$t,$padding)
|
|
|
1114 |
{
|
|
|
1115 |
// This is so derived generator classes can generate variabels
|
|
|
1116 |
// It MUST NOT be changed here!!!
|
|
|
1117 |
return "";
|
|
|
1118 |
}
|
|
|
1119 |
/**
|
|
|
1120 |
* hook for after var lines (
|
|
|
1121 |
* called at the end of the output of var line have generated, override to add extra var
|
|
|
1122 |
* lines
|
|
|
1123 |
*
|
|
|
1124 |
* @param array cols containing array of objects with type,len,flags etc. from tableInfo call
|
|
|
1125 |
* @access public
|
|
|
1126 |
* @return string added to class eg. functions.
|
|
|
1127 |
*/
|
|
|
1128 |
function derivedHookPostVar($t)
|
|
|
1129 |
{
|
|
|
1130 |
// This is so derived generator classes can generate variabels
|
|
|
1131 |
// It MUST NOT be changed here!!!
|
|
|
1132 |
return "";
|
|
|
1133 |
}
|
|
|
1134 |
/**
|
|
|
1135 |
* hook to add extra page-level (in terms of phpDocumentor) DocBlock
|
|
|
1136 |
*
|
|
|
1137 |
* called once for each class, use it add extra page-level docs
|
|
|
1138 |
* @access public
|
|
|
1139 |
* @return string added to class eg. functions.
|
|
|
1140 |
*/
|
|
|
1141 |
function derivedHookPageLevelDocBlock() {
|
|
|
1142 |
return '';
|
|
|
1143 |
}
|
|
|
1144 |
|
|
|
1145 |
/**
|
|
|
1146 |
* hook to add extra doc block (in terms of phpDocumentor) to extend string
|
|
|
1147 |
*
|
|
|
1148 |
* called once for each class, use it add extra comments to extends
|
|
|
1149 |
* string (require_once...)
|
|
|
1150 |
* @access public
|
|
|
1151 |
* @return string added to class eg. functions.
|
|
|
1152 |
*/
|
|
|
1153 |
function derivedHookExtendsDocBlock() {
|
|
|
1154 |
return '';
|
|
|
1155 |
}
|
|
|
1156 |
|
|
|
1157 |
/**
|
|
|
1158 |
* hook to add extra class level DocBlock (in terms of phpDocumentor)
|
|
|
1159 |
*
|
|
|
1160 |
* called once for each class, use it add extra comments to class
|
|
|
1161 |
* string (require_once...)
|
|
|
1162 |
* @access public
|
|
|
1163 |
* @return string added to class eg. functions.
|
|
|
1164 |
*/
|
|
|
1165 |
function derivedHookClassDocBlock() {
|
|
|
1166 |
return '';
|
|
|
1167 |
}
|
|
|
1168 |
|
|
|
1169 |
/**
|
|
|
1170 |
|
|
|
1171 |
/**
|
|
|
1172 |
* getProxyFull - create a class definition on the fly and instantate it..
|
|
|
1173 |
*
|
|
|
1174 |
* similar to generated files - but also evals the class definitoin code.
|
|
|
1175 |
*
|
|
|
1176 |
*
|
|
|
1177 |
* @param string database name
|
|
|
1178 |
* @param string table name of table to create proxy for.
|
|
|
1179 |
*
|
|
|
1180 |
*
|
|
|
1181 |
* @return object Instance of class. or PEAR Error
|
|
|
1182 |
* @access public
|
|
|
1183 |
*/
|
|
|
1184 |
function getProxyFull($database,$table)
|
|
|
1185 |
{
|
|
|
1186 |
|
|
|
1187 |
if ($err = $this->fillTableSchema($database,$table)) {
|
|
|
1188 |
return $err;
|
|
|
1189 |
}
|
|
|
1190 |
|
|
|
1191 |
|
|
|
1192 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
1193 |
$class_prefix = empty($options['class_prefix']) ? '' : $options['class_prefix'];
|
|
|
1194 |
|
|
|
1195 |
$this->_extends = empty($options['extends']) ? $this->_extends : $options['extends'];
|
|
|
1196 |
$this->_extendsFile = empty($options['extends_location']) ? $this->_extendsFile : $options['extends_location'];
|
|
|
1197 |
|
|
|
1198 |
$classname = $this->classname = $this->getClassNameFromTableName($this->table);
|
|
|
1199 |
|
|
|
1200 |
$out = $this->_generateClassTable();
|
|
|
1201 |
//echo $out;
|
|
|
1202 |
eval('?>'.$out);
|
|
|
1203 |
return new $classname;
|
|
|
1204 |
|
|
|
1205 |
}
|
|
|
1206 |
|
|
|
1207 |
/**
|
|
|
1208 |
* fillTableSchema - set the database schema on the fly
|
|
|
1209 |
*
|
|
|
1210 |
*
|
|
|
1211 |
*
|
|
|
1212 |
* @param string database name
|
|
|
1213 |
* @param string table name of table to create schema info for
|
|
|
1214 |
*
|
|
|
1215 |
* @return none | PEAR::error()
|
|
|
1216 |
* @access public
|
|
|
1217 |
*/
|
|
|
1218 |
function fillTableSchema($database,$table)
|
|
|
1219 |
{
|
|
|
1220 |
global $_DB_DATAOBJECT;
|
|
|
1221 |
// a little bit of sanity testing.
|
|
|
1222 |
if ((false !== strpos($database,"'")) || (false !== strpos($database,";"))) {
|
|
|
1223 |
return PEAR::raiseError("Error: Database name contains a quote or semi-colon", null, PEAR_ERROR_DIE);
|
|
|
1224 |
}
|
|
|
1225 |
|
|
|
1226 |
$this->_database = $database;
|
|
|
1227 |
|
|
|
1228 |
$this->_connect();
|
|
|
1229 |
$table = trim($table);
|
|
|
1230 |
|
|
|
1231 |
// a little bit of sanity testing.
|
|
|
1232 |
if ((false !== strpos($table,"'")) || (false !== strpos($table,";"))) {
|
|
|
1233 |
return PEAR::raiseError("Error: Table contains a quote or semi-colon", null, PEAR_ERROR_DIE);
|
|
|
1234 |
}
|
|
|
1235 |
$__DB= &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
|
|
|
1236 |
|
|
|
1237 |
|
|
|
1238 |
$options = PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
1239 |
$db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
|
|
|
1240 |
$is_MDB2 = ($db_driver != 'DB') ? true : false;
|
|
|
1241 |
|
|
|
1242 |
if (!$is_MDB2) {
|
|
|
1243 |
// try getting a list of schema tables first. (postgres)
|
|
|
1244 |
$__DB->expectError(DB_ERROR_UNSUPPORTED);
|
|
|
1245 |
$this->tables = $__DB->getListOf('schema.tables');
|
|
|
1246 |
$__DB->popExpect();
|
|
|
1247 |
} else {
|
|
|
1248 |
/**
|
|
|
1249 |
* set portability and some modules to fetch the informations
|
|
|
1250 |
*/
|
|
|
1251 |
$__DB->setOption('portability', MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_FIX_CASE);
|
|
|
1252 |
$__DB->loadModule('Manager');
|
|
|
1253 |
$__DB->loadModule('Reverse');
|
|
|
1254 |
}
|
|
|
1255 |
$quotedTable = !empty($options['quote_identifiers_tableinfo']) ?
|
|
|
1256 |
$__DB->quoteIdentifier($table) : $table;
|
|
|
1257 |
|
|
|
1258 |
if (!$is_MDB2) {
|
|
|
1259 |
$defs = $__DB->tableInfo($quotedTable);
|
|
|
1260 |
} else {
|
|
|
1261 |
$defs = $__DB->reverse->tableInfo($quotedTable);
|
|
|
1262 |
foreach ($defs as $k => $v) {
|
|
|
1263 |
if (!isset($defs[$k]['length'])) {
|
|
|
1264 |
continue;
|
|
|
1265 |
}
|
|
|
1266 |
$defs[$k]['len'] = $defs[$k]['length'];
|
|
|
1267 |
}
|
|
|
1268 |
}
|
|
|
1269 |
|
|
|
1270 |
|
|
|
1271 |
|
|
|
1272 |
|
|
|
1273 |
if (PEAR::isError($defs)) {
|
|
|
1274 |
return $defs;
|
|
|
1275 |
}
|
|
|
1276 |
if (@$_DB_DATAOBJECT['CONFIG']['debug'] > 2) {
|
|
|
1277 |
$this->debug("getting def for $database/$table",'fillTable');
|
|
|
1278 |
$this->debug(print_r($defs,true),'defs');
|
|
|
1279 |
}
|
|
|
1280 |
// cast all definitions to objects - as we deal with that better.
|
|
|
1281 |
|
|
|
1282 |
|
|
|
1283 |
foreach($defs as $def) {
|
|
|
1284 |
if (is_array($def)) {
|
|
|
1285 |
$this->_definitions[$table][] = (object) $def;
|
|
|
1286 |
}
|
|
|
1287 |
}
|
|
|
1288 |
|
|
|
1289 |
$this->table = trim($table);
|
|
|
1290 |
$ret = $this->_generateDefinitionsTable();
|
|
|
1291 |
|
|
|
1292 |
$_DB_DATAOBJECT['INI'][$database][$table] = $ret['table'];
|
|
|
1293 |
$_DB_DATAOBJECT['INI'][$database][$table.'__keys'] = $ret['keys'];
|
|
|
1294 |
return false;
|
|
|
1295 |
|
|
|
1296 |
}
|
|
|
1297 |
|
|
|
1298 |
/**
|
|
|
1299 |
* Generate getter methods for class definition
|
|
|
1300 |
*
|
|
|
1301 |
* @param string $input Existing class contents
|
|
|
1302 |
* @return string
|
|
|
1303 |
* @access public
|
|
|
1304 |
*/
|
|
|
1305 |
function _generateGetters($input)
|
|
|
1306 |
{
|
|
|
1307 |
|
|
|
1308 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
1309 |
$getters = '';
|
|
|
1310 |
|
|
|
1311 |
// only generate if option is set to true
|
|
|
1312 |
if (empty($options['generate_getters'])) {
|
|
|
1313 |
return '';
|
|
|
1314 |
}
|
|
|
1315 |
|
|
|
1316 |
// remove auto-generated code from input to be able to check if the method exists outside of the auto-code
|
|
|
1317 |
$input = preg_replace('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', '', $input);
|
|
|
1318 |
|
|
|
1319 |
$getters .= "\n\n";
|
|
|
1320 |
$defs = $this->_definitions[$this->table];
|
|
|
1321 |
|
|
|
1322 |
// loop through properties and create getter methods
|
|
|
1323 |
foreach ($defs = $defs as $t) {
|
|
|
1324 |
|
|
|
1325 |
// build mehtod name
|
|
|
1326 |
$methodName = 'get' . $this->getMethodNameFromColumnName($t->name);
|
|
|
1327 |
|
|
|
1328 |
if (!strlen(trim($t->name)) || preg_match("/function[\s]+[&]?$methodName\(/i", $input)) {
|
|
|
1329 |
continue;
|
|
|
1330 |
}
|
|
|
1331 |
|
|
|
1332 |
$getters .= " /**\n";
|
|
|
1333 |
$getters .= " * Getter for \${$t->name}\n";
|
|
|
1334 |
$getters .= " *\n";
|
|
|
1335 |
$getters .= (stristr($t->flags, 'multiple_key')) ? " * @return object\n"
|
|
|
1336 |
: " * @return {$t->type}\n";
|
|
|
1337 |
$getters .= " * @access public\n";
|
|
|
1338 |
$getters .= " */\n";
|
|
|
1339 |
$getters .= (substr(phpversion(),0,1) > 4) ? ' public '
|
|
|
1340 |
: ' ';
|
|
|
1341 |
$getters .= "function $methodName() {\n";
|
|
|
1342 |
$getters .= " return \$this->{$t->name};\n";
|
|
|
1343 |
$getters .= " }\n\n";
|
|
|
1344 |
}
|
|
|
1345 |
|
|
|
1346 |
|
|
|
1347 |
return $getters;
|
|
|
1348 |
}
|
|
|
1349 |
|
|
|
1350 |
|
|
|
1351 |
/**
|
|
|
1352 |
* Generate setter methods for class definition
|
|
|
1353 |
*
|
|
|
1354 |
* @param string Existing class contents
|
|
|
1355 |
* @return string
|
|
|
1356 |
* @access public
|
|
|
1357 |
*/
|
|
|
1358 |
function _generateSetters($input)
|
|
|
1359 |
{
|
|
|
1360 |
|
|
|
1361 |
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
1362 |
$setters = '';
|
|
|
1363 |
|
|
|
1364 |
// only generate if option is set to true
|
|
|
1365 |
if (empty($options['generate_setters'])) {
|
|
|
1366 |
return '';
|
|
|
1367 |
}
|
|
|
1368 |
|
|
|
1369 |
// remove auto-generated code from input to be able to check if the method exists outside of the auto-code
|
|
|
1370 |
$input = preg_replace('/(\n|\r\n)\s*###START_AUTOCODE(\n|\r\n).*(\n|\r\n)\s*###END_AUTOCODE(\n|\r\n)/s', '', $input);
|
|
|
1371 |
|
|
|
1372 |
$setters .= "\n";
|
|
|
1373 |
$defs = $this->_definitions[$this->table];
|
|
|
1374 |
|
|
|
1375 |
// loop through properties and create setter methods
|
|
|
1376 |
foreach ($defs = $defs as $t) {
|
|
|
1377 |
|
|
|
1378 |
// build mehtod name
|
|
|
1379 |
$methodName = 'set' . $this->getMethodNameFromColumnName($t->name);
|
|
|
1380 |
|
|
|
1381 |
if (!strlen(trim($t->name)) || preg_match("/function[\s]+[&]?$methodName\(/i", $input)) {
|
|
|
1382 |
continue;
|
|
|
1383 |
}
|
|
|
1384 |
|
|
|
1385 |
$setters .= " /**\n";
|
|
|
1386 |
$setters .= " * Setter for \${$t->name}\n";
|
|
|
1387 |
$setters .= " *\n";
|
|
|
1388 |
$setters .= " * @param mixed input value\n";
|
|
|
1389 |
$setters .= " * @access public\n";
|
|
|
1390 |
$setters .= " */\n";
|
|
|
1391 |
$setters .= (substr(phpversion(),0,1) > 4) ? ' public '
|
|
|
1392 |
: ' ';
|
|
|
1393 |
$setters .= "function $methodName(\$value) {\n";
|
|
|
1394 |
$setters .= " \$this->{$t->name} = \$value;\n";
|
|
|
1395 |
$setters .= " }\n\n";
|
|
|
1396 |
}
|
|
|
1397 |
|
|
|
1398 |
|
|
|
1399 |
return $setters;
|
|
|
1400 |
}
|
|
|
1401 |
/**
|
|
|
1402 |
* Generate table Function - used when generator_no_ini is set.
|
|
|
1403 |
*
|
|
|
1404 |
* @param array table array.
|
|
|
1405 |
* @return string
|
|
|
1406 |
* @access public
|
|
|
1407 |
*/
|
|
|
1408 |
function _generateTableFunction($def)
|
|
|
1409 |
{
|
|
|
1410 |
$defines = explode(',','INT,STR,DATE,TIME,BOOL,TXT,BLOB,NOTNULL,MYSQLTIMESTAMP');
|
|
|
1411 |
|
|
|
1412 |
$ret = "\n" .
|
|
|
1413 |
" function table()\n" .
|
|
|
1414 |
" {\n" .
|
|
|
1415 |
" return array(\n";
|
|
|
1416 |
|
|
|
1417 |
foreach($def as $k=>$v) {
|
|
|
1418 |
$str = '0';
|
|
|
1419 |
foreach($defines as $dn) {
|
|
|
1420 |
if ($v & constant('DB_DATAOBJECT_' . $dn)) {
|
|
|
1421 |
$str .= ' + DB_DATAOBJECT_' . $dn;
|
|
|
1422 |
}
|
|
|
1423 |
}
|
|
|
1424 |
if (strlen($str) > 1) {
|
|
|
1425 |
$str = substr($str,3); // strip the 0 +
|
|
|
1426 |
}
|
|
|
1427 |
// hopefully addslashes is good enough here!!!
|
|
|
1428 |
$ret .= ' \''.addslashes($k).'\' => ' . $str . ",\n";
|
|
|
1429 |
}
|
|
|
1430 |
return $ret . " );\n" .
|
|
|
1431 |
" }\n";
|
|
|
1432 |
|
|
|
1433 |
|
|
|
1434 |
|
|
|
1435 |
}
|
|
|
1436 |
/**
|
|
|
1437 |
* Generate keys Function - used generator_no_ini is set.
|
|
|
1438 |
*
|
|
|
1439 |
* @param array keys array.
|
|
|
1440 |
* @return string
|
|
|
1441 |
* @access public
|
|
|
1442 |
*/
|
|
|
1443 |
function _generateKeysFunction($def)
|
|
|
1444 |
{
|
|
|
1445 |
|
|
|
1446 |
$ret = "\n" .
|
|
|
1447 |
" function keys()\n" .
|
|
|
1448 |
" {\n" .
|
|
|
1449 |
" return array(";
|
|
|
1450 |
|
|
|
1451 |
foreach($def as $k=>$type) {
|
|
|
1452 |
// hopefully addslashes is good enough here!!!
|
|
|
1453 |
$ret .= '\''.addslashes($k).'\', ';
|
|
|
1454 |
}
|
|
|
1455 |
$ret = preg_replace('#, $#', '', $ret);
|
|
|
1456 |
return $ret . ");\n" .
|
|
|
1457 |
" }\n";
|
|
|
1458 |
|
|
|
1459 |
|
|
|
1460 |
|
|
|
1461 |
}
|
|
|
1462 |
/**
|
|
|
1463 |
* Generate sequenceKey Function - used generator_no_ini is set.
|
|
|
1464 |
*
|
|
|
1465 |
* @param array table and key definition.
|
|
|
1466 |
* @return string
|
|
|
1467 |
* @access public
|
|
|
1468 |
*/
|
|
|
1469 |
function _generateSequenceKeyFunction($def)
|
|
|
1470 |
{
|
|
|
1471 |
|
|
|
1472 |
//print_r($def);
|
|
|
1473 |
// DB_DataObject::debugLevel(5);
|
|
|
1474 |
global $_DB_DATAOBJECT;
|
|
|
1475 |
// print_r($def);
|
|
|
1476 |
|
|
|
1477 |
|
|
|
1478 |
$dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'];
|
|
|
1479 |
$realkeys = $def['keys'];
|
|
|
1480 |
$keys = array_keys($realkeys);
|
|
|
1481 |
$usekey = isset($keys[0]) ? $keys[0] : false;
|
|
|
1482 |
$table = $def['table'];
|
|
|
1483 |
|
|
|
1484 |
|
|
|
1485 |
$seqname = false;
|
|
|
1486 |
|
|
|
1487 |
|
|
|
1488 |
|
|
|
1489 |
|
|
|
1490 |
$ar = array(false,false,false);
|
|
|
1491 |
if ($usekey !== false) {
|
|
|
1492 |
if (!empty($_DB_DATAOBJECT['CONFIG']['sequence_'.$this->__table])) {
|
|
|
1493 |
$usekey = $_DB_DATAOBJECT['CONFIG']['sequence_'.$this->__table];
|
|
|
1494 |
if (strpos($usekey,':') !== false) {
|
|
|
1495 |
list($usekey,$seqname) = explode(':',$usekey);
|
|
|
1496 |
}
|
|
|
1497 |
}
|
|
|
1498 |
|
|
|
1499 |
if (in_array($dbtype , array( 'mysql', 'mysqli', 'mssql', 'ifx')) &&
|
|
|
1500 |
($table[$usekey] & DB_DATAOBJECT_INT) &&
|
|
|
1501 |
isset($realkeys[$usekey]) && ($realkeys[$usekey] == 'N')
|
|
|
1502 |
) {
|
|
|
1503 |
// use native sequence keys.
|
|
|
1504 |
$ar = array($usekey,true,$seqname);
|
|
|
1505 |
} else {
|
|
|
1506 |
// use generated sequence keys..
|
|
|
1507 |
if ($table[$usekey] & DB_DATAOBJECT_INT) {
|
|
|
1508 |
$ar = array($usekey,false,$seqname);
|
|
|
1509 |
}
|
|
|
1510 |
}
|
|
|
1511 |
}
|
|
|
1512 |
|
|
|
1513 |
|
|
|
1514 |
|
|
|
1515 |
|
|
|
1516 |
$ret = "\n" .
|
|
|
1517 |
" function sequenceKey() // keyname, use native, native name\n" .
|
|
|
1518 |
" {\n" .
|
|
|
1519 |
" return array(";
|
|
|
1520 |
foreach($ar as $v) {
|
|
|
1521 |
switch (gettype($v)) {
|
|
|
1522 |
case 'boolean':
|
|
|
1523 |
$ret .= ($v ? 'true' : 'false') . ', ';
|
|
|
1524 |
break;
|
|
|
1525 |
|
|
|
1526 |
case 'string':
|
|
|
1527 |
$ret .= "'" . $v . "', ";
|
|
|
1528 |
break;
|
|
|
1529 |
|
|
|
1530 |
default: // eak
|
|
|
1531 |
$ret .= "null, ";
|
|
|
1532 |
|
|
|
1533 |
}
|
|
|
1534 |
}
|
|
|
1535 |
$ret = preg_replace('#, $#', '', $ret);
|
|
|
1536 |
return $ret . ");\n" .
|
|
|
1537 |
" }\n";
|
|
|
1538 |
|
|
|
1539 |
}
|
|
|
1540 |
/**
|
|
|
1541 |
* Generate defaults Function - used generator_add_defaults or generator_no_ini is set.
|
|
|
1542 |
* Only supports mysql and mysqli ... welcome ideas for more..
|
|
|
1543 |
*
|
|
|
1544 |
*
|
|
|
1545 |
* @param array table and key definition.
|
|
|
1546 |
* @return string
|
|
|
1547 |
* @access public
|
|
|
1548 |
*/
|
|
|
1549 |
function _generateDefaultsFunction($table,$defs)
|
|
|
1550 |
{
|
|
|
1551 |
$__DB= &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
|
|
|
1552 |
if (!in_array($__DB->phptype, array('mysql','mysqli'))) {
|
|
|
1553 |
return; // cant handle non-mysql introspection for defaults.
|
|
|
1554 |
}
|
|
|
1555 |
$options = PEAR::getStaticProperty('DB_DataObject','options');
|
|
|
1556 |
$db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
|
|
|
1557 |
$method = $db_driver == 'DB' ? 'getAll' : 'queryAll';
|
|
|
1558 |
$res = $__DB->$method('DESCRIBE ' . $table,DB_FETCHMODE_ASSOC);
|
|
|
1559 |
$defaults = array();
|
|
|
1560 |
foreach($res as $ar) {
|
|
|
1561 |
// this is initially very dumb... -> and it may mess up..
|
|
|
1562 |
$type = $defs[$ar['Field']];
|
|
|
1563 |
|
|
|
1564 |
switch (true) {
|
|
|
1565 |
|
|
|
1566 |
case (is_null( $ar['Default'])):
|
|
|
1567 |
$defaults[$ar['Field']] = 'null';
|
|
|
1568 |
break;
|
|
|
1569 |
|
|
|
1570 |
case ($type & DB_DATAOBJECT_DATE):
|
|
|
1571 |
case ($type & DB_DATAOBJECT_TIME):
|
|
|
1572 |
case ($type & DB_DATAOBJECT_MYSQLTIMESTAMP): // not supported yet..
|
|
|
1573 |
break;
|
|
|
1574 |
|
|
|
1575 |
case ($type & DB_DATAOBJECT_BOOL):
|
|
|
1576 |
$defaults[$ar['Field']] = (int)(boolean) $ar['Default'];
|
|
|
1577 |
break;
|
|
|
1578 |
|
|
|
1579 |
|
|
|
1580 |
case ($type & DB_DATAOBJECT_STR):
|
|
|
1581 |
$defaults[$ar['Field']] = "'" . addslashes($ar['Default']) . "'";
|
|
|
1582 |
break;
|
|
|
1583 |
|
|
|
1584 |
|
|
|
1585 |
default: // hopefully eveything else... - numbers etc.
|
|
|
1586 |
if (!strlen($ar['Default'])) {
|
|
|
1587 |
continue;
|
|
|
1588 |
}
|
|
|
1589 |
if (is_numeric($ar['Default'])) {
|
|
|
1590 |
$defaults[$ar['Field']] = $ar['Default'];
|
|
|
1591 |
}
|
|
|
1592 |
break;
|
|
|
1593 |
|
|
|
1594 |
}
|
|
|
1595 |
//var_dump(array($ar['Field'], $ar['Default'], $defaults[$ar['Field']]));
|
|
|
1596 |
}
|
|
|
1597 |
if (empty($defaults)) {
|
|
|
1598 |
return;
|
|
|
1599 |
}
|
|
|
1600 |
|
|
|
1601 |
$ret = "\n" .
|
|
|
1602 |
" function defaults() // column default values \n" .
|
|
|
1603 |
" {\n" .
|
|
|
1604 |
" return array(\n";
|
|
|
1605 |
foreach($defaults as $k=>$v) {
|
|
|
1606 |
$ret .= ' \''.addslashes($k).'\' => ' . $v . ",\n";
|
|
|
1607 |
}
|
|
|
1608 |
return $ret . " );\n" .
|
|
|
1609 |
" }\n";
|
|
|
1610 |
|
|
|
1611 |
|
|
|
1612 |
|
|
|
1613 |
|
|
|
1614 |
}
|
|
|
1615 |
|
|
|
1616 |
|
|
|
1617 |
|
|
|
1618 |
|
|
|
1619 |
|
|
|
1620 |
}
|