Subversion Repositories Applications.gtt

Rev

Rev 94 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
94 jpm 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.96 2005/06/16 02:03:45 alan_k 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
}