Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/*
3
 *  $Id: Export.php 7653 2010-06-08 15:54:31Z jwage $
4
 *
5
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
 *
17
 * This software consists of voluntary contributions made by many individuals
18
 * and is licensed under the LGPL. For more information, see
19
 * <http://www.doctrine-project.org>.
20
 */
21
 
22
/**
23
 * Doctrine_Export
24
 *
25
 * @package     Doctrine
26
 * @subpackage  Export
27
 * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
28
 * @author      Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
29
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
30
 * @link        www.doctrine-project.org
31
 * @since       1.0
32
 * @version     $Revision: 7653 $
33
 */
34
class Doctrine_Export extends Doctrine_Connection_Module
35
{
36
    protected $valid_default_values = array(
37
        'text'      => '',
38
        'boolean'   => true,
39
        'integer'   => 0,
40
        'decimal'   => 0.0,
41
        'float'     => 0.0,
42
        'timestamp' => '1970-01-01 00:00:00',
43
        'time'      => '00:00:00',
44
        'date'      => '1970-01-01',
45
        'clob'      => '',
46
        'blob'      => '',
47
        'string'    => ''
48
    );
49
 
50
    /**
51
     * drop an existing database
52
     * (this method is implemented by the drivers)
53
     *
54
     * @param string $name name of the database that should be dropped
55
     * @return void
56
     */
57
    public function dropDatabase($database)
58
    {
59
        foreach ((array) $this->dropDatabaseSql($database) as $query) {
60
            $this->conn->execute($query);
61
        }
62
    }
63
 
64
    /**
65
     * drop an existing database
66
     * (this method is implemented by the drivers)
67
     *
68
     * @param string $name name of the database that should be dropped
69
     * @return void
70
     */
71
    public function dropDatabaseSql($database)
72
    {
73
        throw new Doctrine_Export_Exception('Drop database not supported by this driver.');
74
    }
75
 
76
    /**
77
     * dropTableSql
78
     * drop an existing table
79
     *
80
     * @param string $table           name of table that should be dropped from the database
81
     * @return string
82
     */
83
    public function dropTableSql($table)
84
    {
85
        return 'DROP TABLE ' . $this->conn->quoteIdentifier($table);
86
    }
87
 
88
    /**
89
     * dropTable
90
     * drop an existing table
91
     *
92
     * @param string $table           name of table that should be dropped from the database
93
     * @return void
94
     */
95
    public function dropTable($table)
96
    {
97
        $this->conn->execute($this->dropTableSql($table));
98
    }
99
 
100
    /**
101
     * drop existing index
102
     *
103
     * @param string    $table        name of table that should be used in method
104
     * @param string    $name         name of the index to be dropped
105
     * @return void
106
     */
107
    public function dropIndex($table, $name)
108
    {
109
        return $this->conn->exec($this->dropIndexSql($table, $name));
110
    }
111
 
112
    /**
113
     * dropIndexSql
114
     *
115
     * @param string    $table        name of table that should be used in method
116
     * @param string    $name         name of the index to be dropped
117
     * @return string                 SQL that is used for dropping an index
118
     */
119
    public function dropIndexSql($table, $name)
120
    {
121
        $name = $this->conn->quoteIdentifier($this->conn->formatter->getIndexName($name));
122
 
123
        return 'DROP INDEX ' . $name;
124
    }
125
 
126
    /**
127
     * drop existing constraint
128
     *
129
     * @param string    $table        name of table that should be used in method
130
     * @param string    $name         name of the constraint to be dropped
131
     * @param string    $primary      hint if the constraint is primary
132
     * @return void
133
     */
134
    public function dropConstraint($table, $name, $primary = false)
135
    {
136
        $table = $this->conn->quoteIdentifier($table);
137
        $name  = $this->conn->quoteIdentifier($name);
138
 
139
        return $this->conn->exec('ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $name);
140
    }
141
 
142
    /**
143
     * drop existing foreign key
144
     *
145
     * @param string    $table        name of table that should be used in method
146
     * @param string    $name         name of the foreign key to be dropped
147
     * @return void
148
     */
149
    public function dropForeignKey($table, $name)
150
    {
151
        return $this->dropConstraint($table, $this->conn->formatter->getForeignKeyName($name));
152
    }
153
 
154
    /**
155
     * dropSequenceSql
156
     * drop existing sequence
157
     * (this method is implemented by the drivers)
158
     *
159
     * @throws Doctrine_Connection_Exception     if something fails at database level
160
     * @param string $sequenceName      name of the sequence to be dropped
161
     * @return void
162
     */
163
    public function dropSequence($sequenceName)
164
    {
165
        $this->conn->exec($this->dropSequenceSql($sequenceName));
166
    }
167
 
168
    /**
169
     * dropSequenceSql
170
     * drop existing sequence
171
     *
172
     * @throws Doctrine_Connection_Exception     if something fails at database level
173
     * @param string $sequenceName name of the sequence to be dropped
174
     * @return void
175
     */
176
    public function dropSequenceSql($sequenceName)
177
    {
178
        throw new Doctrine_Export_Exception('Drop sequence not supported by this driver.');
179
    }
180
 
181
    /**
182
     * create a new database
183
     * (this method is implemented by the drivers)
184
     *
185
     * @param string $name name of the database that should be created
186
     * @return void
187
     */
188
    public function createDatabase($database)
189
    {
190
        $this->conn->execute($this->createDatabaseSql($database));
191
    }
192
 
193
    /**
194
     * create a new database
195
     * (this method is implemented by the drivers)
196
     *
197
     * @param string $name name of the database that should be created
198
     * @return string
199
     */
200
    public function createDatabaseSql($database)
201
    {
202
        throw new Doctrine_Export_Exception('Create database not supported by this driver.');
203
    }
204
 
205
    /**
206
     * create a new table
207
     *
208
     * @param string $name   Name of the database that should be created
209
     * @param array $fields  Associative array that contains the definition of each field of the new table
210
     *                       The indexes of the array entries are the names of the fields of the table an
211
     *                       the array entry values are associative arrays like those that are meant to be
212
     *                       passed with the field definitions to get[Type]Declaration() functions.
213
     *                          array(
214
     *                              'id' => array(
215
     *                                  'type' => 'integer',
216
     *                                  'unsigned' => 1
217
     *                                  'notnull' => 1
218
     *                                  'default' => 0
219
     *                              ),
220
     *                              'name' => array(
221
     *                                  'type' => 'text',
222
     *                                  'length' => 12
223
     *                              ),
224
     *                              'password' => array(
225
     *                                  'type' => 'text',
226
     *                                  'length' => 12
227
     *                              )
228
     *                          );
229
     * @param array $options  An associative array of table options:
230
     *
231
     * @return string
232
     */
233
    public function createTableSql($name, array $fields, array $options = array())
234
    {
235
        if ( ! $name) {
236
            throw new Doctrine_Export_Exception('no valid table name specified');
237
        }
238
 
239
        if (empty($fields)) {
240
            throw new Doctrine_Export_Exception('no fields specified for table ' . $name);
241
        }
242
 
243
        $queryFields = $this->getFieldDeclarationList($fields);
244
 
245
 
246
        if (isset($options['primary']) && ! empty($options['primary'])) {
247
            $primaryKeys = array_map(array($this->conn, 'quoteIdentifier'), array_values($options['primary']));
248
            $queryFields .= ', PRIMARY KEY(' . implode(', ', $primaryKeys) . ')';
249
        }
250
 
251
        if (isset($options['indexes']) && ! empty($options['indexes'])) {
252
            foreach($options['indexes'] as $index => $definition) {
253
                $indexDeclaration = $this->getIndexDeclaration($index, $definition);
254
                // append only created index declarations
255
                if ( ! is_null($indexDeclaration)) {
256
                    $queryFields .= ', '.$indexDeclaration;
257
                }
258
            }
259
        }
260
 
261
        $query = 'CREATE TABLE ' . $this->conn->quoteIdentifier($name, true) . ' (' . $queryFields;
262
 
263
        $check = $this->getCheckDeclaration($fields);
264
 
265
        if ( ! empty($check)) {
266
            $query .= ', ' . $check;
267
        }
268
 
269
        $query .= ')';
270
 
271
        $sql[] = $query;
272
 
273
        if (isset($options['foreignKeys'])) {
274
 
275
            foreach ((array) $options['foreignKeys'] as $k => $definition) {
276
                if (is_array($definition)) {
277
                    $sql[] = $this->createForeignKeySql($name, $definition);
278
                }
279
            }
280
        }
281
        return $sql;
282
    }
283
 
284
    /**
285
     * create a new table
286
     *
287
     * @param string $name   Name of the database that should be created
288
     * @param array $fields  Associative array that contains the definition of each field of the new table
289
     * @param array $options  An associative array of table options:
290
     * @see Doctrine_Export::createTableSql()
291
     *
292
     * @return void
293
     */
294
    public function createTable($name, array $fields, array $options = array())
295
    {
296
        // Build array of the primary keys if any of the individual field definitions
297
        // specify primary => true
298
        $count = 0;
299
        foreach ($fields as $fieldName => $field) {
300
            if (isset($field['primary']) && $field['primary']) {
301
                if ($count == 0) {
302
                    $options['primary'] = array();
303
                }
304
                $count++;
305
                $options['primary'][] = $fieldName;
306
            }
307
        }
308
 
309
        $sql = (array) $this->createTableSql($name, $fields, $options);
310
 
311
        foreach ($sql as $query) {
312
            $this->conn->execute($query);
313
        }
314
    }
315
 
316
    /**
317
     * create sequence
318
     *
319
     * @throws Doctrine_Connection_Exception     if something fails at database level
320
     * @param string    $seqName        name of the sequence to be created
321
     * @param string    $start          start value of the sequence; default is 1
322
     * @param array     $options  An associative array of table options:
323
     *                          array(
324
     *                              'comment' => 'Foo',
325
     *                              'charset' => 'utf8',
326
     *                              'collate' => 'utf8_unicode_ci',
327
     *                          );
328
     * @return void
329
     */
330
    public function createSequence($seqName, $start = 1, array $options = array())
331
    {
332
        return $this->conn->execute($this->createSequenceSql($seqName, $start = 1, $options));
333
    }
334
 
335
    /**
336
     * return RDBMS specific create sequence statement
337
     * (this method is implemented by the drivers)
338
     *
339
     * @throws Doctrine_Connection_Exception     if something fails at database level
340
     * @param string    $seqName        name of the sequence to be created
341
     * @param string    $start          start value of the sequence; default is 1
342
     * @param array     $options  An associative array of table options:
343
     *                          array(
344
     *                              'comment' => 'Foo',
345
     *                              'charset' => 'utf8',
346
     *                              'collate' => 'utf8_unicode_ci',
347
     *                          );
348
     * @return string
349
     */
350
    public function createSequenceSql($seqName, $start = 1, array $options = array())
351
    {
352
        throw new Doctrine_Export_Exception('Create sequence not supported by this driver.');
353
    }
354
 
355
    /**
356
     * create a constraint on a table
357
     *
358
     * @param string    $table         name of the table on which the constraint is to be created
359
     * @param string    $name          name of the constraint to be created
360
     * @param array     $definition    associative array that defines properties of the constraint to be created.
361
     *                                 Currently, only one property named FIELDS is supported. This property
362
     *                                 is also an associative with the names of the constraint fields as array
363
     *                                 constraints. Each entry of this array is set to another type of associative
364
     *                                 array that specifies properties of the constraint that are specific to
365
     *                                 each field.
366
     *
367
     *                                 Example
368
     *                                    array(
369
     *                                        'fields' => array(
370
     *                                            'user_name' => array(),
371
     *                                            'last_login' => array()
372
     *                                        )
373
     *                                    )
374
     * @return void
375
     */
376
    public function createConstraint($table, $name, $definition)
377
    {
378
        $sql = $this->createConstraintSql($table, $name, $definition);
379
 
380
        return $this->conn->exec($sql);
381
    }
382
 
383
    /**
384
     * create a constraint on a table
385
     *
386
     * @param string    $table         name of the table on which the constraint is to be created
387
     * @param string    $name          name of the constraint to be created
388
     * @param array     $definition    associative array that defines properties of the constraint to be created.
389
     *                                 Currently, only one property named FIELDS is supported. This property
390
     *                                 is also an associative with the names of the constraint fields as array
391
     *                                 constraints. Each entry of this array is set to another type of associative
392
     *                                 array that specifies properties of the constraint that are specific to
393
     *                                 each field.
394
     *
395
     *                                 Example
396
     *                                    array(
397
     *                                        'fields' => array(
398
     *                                            'user_name' => array(),
399
     *                                            'last_login' => array()
400
     *                                        )
401
     *                                    )
402
     * @return void
403
     */
404
    public function createConstraintSql($table, $name, $definition)
405
    {
406
        $table = $this->conn->quoteIdentifier($table);
407
        $name  = $this->conn->quoteIdentifier($this->conn->formatter->getIndexName($name));
408
        $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $name;
409
 
410
        if (isset($definition['primary']) && $definition['primary']) {
411
            $query .= ' PRIMARY KEY';
412
        } elseif (isset($definition['unique']) && $definition['unique']) {
413
            $query .= ' UNIQUE';
414
        }
415
 
416
        $fields = array();
417
        foreach (array_keys($definition['fields']) as $field) {
418
            $fields[] = $this->conn->quoteIdentifier($field, true);
419
        }
420
        $query .= ' ('. implode(', ', $fields) . ')';
421
 
422
        return $query;
423
    }
424
 
425
    /**
426
     * Get the stucture of a field into an array
427
     *
428
     * @param string    $table         name of the table on which the index is to be created
429
     * @param string    $name          name of the index to be created
430
     * @param array     $definition    associative array that defines properties of the index to be created.
431
     *                                 Currently, only one property named FIELDS is supported. This property
432
     *                                 is also an associative with the names of the index fields as array
433
     *                                 indexes. Each entry of this array is set to another type of associative
434
     *                                 array that specifies properties of the index that are specific to
435
     *                                 each field.
436
     *
437
     *                                 Currently, only the sorting property is supported. It should be used
438
     *                                 to define the sorting direction of the index. It may be set to either
439
     *                                 ascending or descending.
440
     *
441
     *                                 Not all DBMS support index sorting direction configuration. The DBMS
442
     *                                 drivers of those that do not support it ignore this property. Use the
443
     *                                 function supports() to determine whether the DBMS driver can manage indexes.
444
     *
445
     *                                 Example
446
     *                                    array(
447
     *                                        'fields' => array(
448
     *                                            'user_name' => array(
449
     *                                                'sorting' => 'ascending'
450
     *                                            ),
451
     *                                            'last_login' => array()
452
     *                                        )
453
     *                                    )
454
     * @return void
455
     */
456
    public function createIndex($table, $name, array $definition)
457
    {
458
        return $this->conn->execute($this->createIndexSql($table, $name, $definition));
459
    }
460
 
461
    /**
462
     * Get the stucture of a field into an array
463
     *
464
     * @param string    $table         name of the table on which the index is to be created
465
     * @param string    $name          name of the index to be created
466
     * @param array     $definition    associative array that defines properties of the index to be created.
467
     * @see Doctrine_Export::createIndex()
468
     * @return string
469
     */
470
    public function createIndexSql($table, $name, array $definition)
471
    {
472
        $table  = $this->conn->quoteIdentifier($table);
473
        $name   = $this->conn->quoteIdentifier($name);
474
        $type   = '';
475
 
476
        if (isset($definition['type'])) {
477
            switch (strtolower($definition['type'])) {
478
                case 'unique':
479
                    $type = strtoupper($definition['type']) . ' ';
480
                break;
481
                default:
482
                    throw new Doctrine_Export_Exception(
483
                        'Unknown type ' . $definition['type'] . ' for index ' . $name . ' in table ' . $table
484
                    );
485
            }
486
        }
487
 
488
        $query = 'CREATE ' . $type . 'INDEX ' . $name . ' ON ' . $table;
489
 
490
        $fields = array();
491
        foreach ($definition['fields'] as $field) {
492
            $fields[] = $this->conn->quoteIdentifier($field);
493
        }
494
        $query .= ' (' . implode(', ', $fields) . ')';
495
 
496
        return $query;
497
    }
498
    /**
499
     * createForeignKeySql
500
     *
501
     * @param string    $table         name of the table on which the foreign key is to be created
502
     * @param array     $definition    associative array that defines properties of the foreign key to be created.
503
     * @return string
504
     */
505
    public function createForeignKeySql($table, array $definition)
506
    {
507
        $table = $this->conn->quoteIdentifier($table);
508
        $query = 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclaration($definition);
509
 
510
        return $query;
511
    }
512
 
513
    /**
514
     * createForeignKey
515
     *
516
     * @param string    $table         name of the table on which the foreign key is to be created
517
     * @param array     $definition    associative array that defines properties of the foreign key to be created.
518
     * @return string
519
     */
520
    public function createForeignKey($table, array $definition)
521
    {
522
        $sql = $this->createForeignKeySql($table, $definition);
523
 
524
        return $this->conn->execute($sql);
525
    }
526
 
527
    /**
528
     * alter an existing table
529
     * (this method is implemented by the drivers)
530
     *
531
     * @param string $name         name of the table that is intended to be changed.
532
     * @param array $changes     associative array that contains the details of each type
533
     *                             of change that is intended to be performed. The types of
534
     *                             changes that are currently supported are defined as follows:
535
     *
536
     *                             name
537
     *
538
     *                                New name for the table.
539
     *
540
     *                            add
541
     *
542
     *                                Associative array with the names of fields to be added as
543
     *                                 indexes of the array. The value of each entry of the array
544
     *                                 should be set to another associative array with the properties
545
     *                                 of the fields to be added. The properties of the fields should
546
     *                                 be the same as defined by the MDB2 parser.
547
     *
548
     *
549
     *                            remove
550
     *
551
     *                                Associative array with the names of fields to be removed as indexes
552
     *                                 of the array. Currently the values assigned to each entry are ignored.
553
     *                                 An empty array should be used for future compatibility.
554
     *
555
     *                            rename
556
     *
557
     *                                Associative array with the names of fields to be renamed as indexes
558
     *                                 of the array. The value of each entry of the array should be set to
559
     *                                 another associative array with the entry named name with the new
560
     *                                 field name and the entry named Declaration that is expected to contain
561
     *                                 the portion of the field declaration already in DBMS specific SQL code
562
     *                                 as it is used in the CREATE TABLE statement.
563
     *
564
     *                            change
565
     *
566
     *                                Associative array with the names of the fields to be changed as indexes
567
     *                                 of the array. Keep in mind that if it is intended to change either the
568
     *                                 name of a field and any other properties, the change array entries
569
     *                                 should have the new names of the fields as array indexes.
570
     *
571
     *                                The value of each entry of the array should be set to another associative
572
     *                                 array with the properties of the fields to that are meant to be changed as
573
     *                                 array entries. These entries should be assigned to the new values of the
574
     *                                 respective properties. The properties of the fields should be the same
575
     *                                 as defined by the MDB2 parser.
576
     *
577
     *                            Example
578
     *                                array(
579
     *                                    'name' => 'userlist',
580
     *                                    'add' => array(
581
     *                                        'quota' => array(
582
     *                                            'type' => 'integer',
583
     *                                            'unsigned' => 1
584
     *                                        )
585
     *                                    ),
586
     *                                    'remove' => array(
587
     *                                        'file_limit' => array(),
588
     *                                        'time_limit' => array()
589
     *                                    ),
590
     *                                    'change' => array(
591
     *                                        'name' => array(
592
     *                                            'length' => '20',
593
     *                                            'definition' => array(
594
     *                                                'type' => 'text',
595
     *                                                'length' => 20,
596
     *                                            ),
597
     *                                        )
598
     *                                    ),
599
     *                                    'rename' => array(
600
     *                                        'sex' => array(
601
     *                                            'name' => 'gender',
602
     *                                            'definition' => array(
603
     *                                                'type' => 'text',
604
     *                                                'length' => 1,
605
     *                                                'default' => 'M',
606
     *                                            ),
607
     *                                        )
608
     *                                    )
609
     *                                )
610
     *
611
     * @param boolean $check     indicates whether the function should just check if the DBMS driver
612
     *                             can perform the requested table alterations if the value is true or
613
     *                             actually perform them otherwise.
614
     * @return void
615
     */
616
    public function alterTable($name, array $changes, $check = false)
617
    {
618
        $sql = $this->alterTableSql($name, $changes, $check);
619
 
620
        if (is_string($sql) && $sql) {
621
            $this->conn->execute($sql);
622
        }
623
    }
624
 
625
    /**
626
     * generates the sql for altering an existing table
627
     * (this method is implemented by the drivers)
628
     *
629
     * @param string $name          name of the table that is intended to be changed.
630
     * @param array $changes        associative array that contains the details of each type      *
631
     * @param boolean $check        indicates whether the function should just check if the DBMS driver
632
     *                              can perform the requested table alterations if the value is true or
633
     *                              actually perform them otherwise.
634
     * @see Doctrine_Export::alterTable()
635
     * @return string
636
     */
637
    public function alterTableSql($name, array $changes, $check = false)
638
    {
639
        throw new Doctrine_Export_Exception('Alter table not supported by this driver.');
640
    }
641
 
642
    /**
643
     * Get declaration of a number of field in bulk
644
     *
645
     * @param array $fields  a multidimensional associative array.
646
     *      The first dimension determines the field name, while the second
647
     *      dimension is keyed with the name of the properties
648
     *      of the field being declared as array indexes. Currently, the types
649
     *      of supported field properties are as follows:
650
     *
651
     *      length
652
     *          Integer value that determines the maximum length of the text
653
     *          field. If this argument is missing the field should be
654
     *          declared to have the longest length allowed by the DBMS.
655
     *
656
     *      default
657
     *          Text value to be used as default for this field.
658
     *
659
     *      notnull
660
     *          Boolean flag that indicates whether this field is constrained
661
     *          to not be set to null.
662
     *      charset
663
     *          Text value with the default CHARACTER SET for this field.
664
     *      collation
665
     *          Text value with the default COLLATION for this field.
666
     *      unique
667
     *          unique constraint
668
     *
669
     * @return string
670
     */
671
    public function getFieldDeclarationList(array $fields)
672
    {
673
        foreach ($fields as $fieldName => $field) {
674
            $query = $this->getDeclaration($fieldName, $field);
675
 
676
            $queryFields[] = $query;
677
        }
678
        return implode(', ', $queryFields);
679
    }
680
 
681
    /**
682
     * Obtain DBMS specific SQL code portion needed to declare a generic type
683
     * field to be used in statements like CREATE TABLE.
684
     *
685
     * @param string $name   name the field to be declared.
686
     * @param array  $field  associative array with the name of the properties
687
     *      of the field being declared as array indexes. Currently, the types
688
     *      of supported field properties are as follows:
689
     *
690
     *      length
691
     *          Integer value that determines the maximum length of the text
692
     *          field. If this argument is missing the field should be
693
     *          declared to have the longest length allowed by the DBMS.
694
     *
695
     *      default
696
     *          Text value to be used as default for this field.
697
     *
698
     *      notnull
699
     *          Boolean flag that indicates whether this field is constrained
700
     *          to not be set to null.
701
     *
702
     *      charset
703
     *          Text value with the default CHARACTER SET for this field.
704
     *
705
     *      collation
706
     *          Text value with the default COLLATION for this field.
707
     *
708
     *      unique
709
     *          unique constraint
710
     *
711
     *      check
712
     *          column check constraint
713
     *
714
     * @return string  DBMS specific SQL code portion that should be used to
715
     *      declare the specified field.
716
     */
717
    public function getDeclaration($name, array $field)
718
    {
719
 
720
        $default   = $this->getDefaultFieldDeclaration($field);
721
 
722
        $charset   = (isset($field['charset']) && $field['charset']) ?
723
                    ' ' . $this->getCharsetFieldDeclaration($field['charset']) : '';
724
 
725
        $collation = (isset($field['collation']) && $field['collation']) ?
726
                    ' ' . $this->getCollationFieldDeclaration($field['collation']) : '';
727
 
728
        $notnull   = $this->getNotNullFieldDeclaration($field);
729
 
730
        $unique    = (isset($field['unique']) && $field['unique']) ?
731
                    ' ' . $this->getUniqueFieldDeclaration() : '';
732
 
733
        $check     = (isset($field['check']) && $field['check']) ?
734
                    ' ' . $field['check'] : '';
735
 
736
        $method = 'get' . $field['type'] . 'Declaration';
737
 
738
        try {
739
            if (method_exists($this->conn->dataDict, $method)) {
740
                return $this->conn->dataDict->$method($name, $field);
741
            } else {
742
                $dec = $this->conn->dataDict->getNativeDeclaration($field);
743
            }
744
 
745
            return $this->conn->quoteIdentifier($name, true)
746
                 . ' ' . $dec . $charset . $default . $notnull . $unique . $check . $collation;
747
        } catch (Exception $e) {
748
            throw new Doctrine_Exception('Around field ' . $name . ': ' . $e->getMessage());
749
        }
750
 
751
    }
752
 
753
    /**
754
     * getDefaultDeclaration
755
     * Obtain DBMS specific SQL code portion needed to set a default value
756
     * declaration to be used in statements like CREATE TABLE.
757
     *
758
     * @param array $field      field definition array
759
     * @return string           DBMS specific SQL code portion needed to set a default value
760
     */
761
    public function getDefaultFieldDeclaration($field)
762
    {
763
        $default = '';
764
 
765
        if (array_key_exists('default', $field)) {
766
            if ($field['default'] === '') {
767
                $field['default'] = empty($field['notnull'])
768
                    ? null : $this->valid_default_values[$field['type']];
769
 
770
                if ($field['default'] === '' &&
771
                   ($this->conn->getAttribute(Doctrine_Core::ATTR_PORTABILITY) & Doctrine_Core::PORTABILITY_EMPTY_TO_NULL)) {
772
                    $field['default'] = null;
773
                }
774
            }
775
 
776
            if ($field['type'] === 'boolean') {
777
                $field['default'] = $this->conn->convertBooleans($field['default']);
778
            }
779
            $default = ' DEFAULT ' . (is_null($field['default'])
780
                ? 'NULL'
781
                : $this->conn->quote($field['default'], $field['type']));
782
        }
783
 
784
        return $default;
785
    }
786
 
787
 
788
    /**
789
     * getNotNullFieldDeclaration
790
     * Obtain DBMS specific SQL code portion needed to set a NOT NULL
791
     * declaration to be used in statements like CREATE TABLE.
792
     *
793
     * @param array $field      field definition array
794
     * @return string           DBMS specific SQL code portion needed to set a default value
795
     */
796
    public function getNotNullFieldDeclaration(array $definition)
797
    {
798
        return (isset($definition['notnull']) && $definition['notnull']) ? ' NOT NULL' : '';
799
    }
800
 
801
 
802
    /**
803
     * Obtain DBMS specific SQL code portion needed to set a CHECK constraint
804
     * declaration to be used in statements like CREATE TABLE.
805
     *
806
     * @param array $definition     check definition
807
     * @return string               DBMS specific SQL code portion needed to set a CHECK constraint
808
     */
809
    public function getCheckDeclaration(array $definition)
810
    {
811
        $constraints = array();
812
        foreach ($definition as $field => $def) {
813
            if (is_string($def)) {
814
                $constraints[] = 'CHECK (' . $def . ')';
815
            } else {
816
                if (isset($def['min'])) {
817
                    $constraints[] = 'CHECK (' . $field . ' >= ' . $def['min'] . ')';
818
                }
819
 
820
                if (isset($def['max'])) {
821
                    $constraints[] = 'CHECK (' . $field . ' <= ' . $def['max'] . ')';
822
                }
823
            }
824
        }
825
 
826
        return implode(', ', $constraints);
827
    }
828
 
829
    /**
830
     * Obtain DBMS specific SQL code portion needed to set an index
831
     * declaration to be used in statements like CREATE TABLE.
832
     *
833
     * @param string $name          name of the index
834
     * @param array $definition     index definition
835
     * @return string               DBMS specific SQL code portion needed to set an index
836
     */
837
    public function getIndexDeclaration($name, array $definition)
838
    {
839
        $name   = $this->conn->quoteIdentifier($name);
840
        $type   = '';
841
 
842
        if (isset($definition['type'])) {
843
            if (strtolower($definition['type']) == 'unique') {
844
                $type = strtoupper($definition['type']) . ' ';
845
            } else {
846
                throw new Doctrine_Export_Exception(
847
                    'Unknown type ' . $definition['type'] . ' for index ' . $name
848
                );
849
            }
850
        }
851
 
852
        if ( ! isset($definition['fields']) || ! is_array($definition['fields'])) {
853
            throw new Doctrine_Export_Exception('No columns given for index ' . $name);
854
        }
855
 
856
        $query = $type . 'INDEX ' . $name;
857
 
858
        $query .= ' (' . $this->getIndexFieldDeclarationList($definition['fields']) . ')';
859
 
860
        return $query;
861
    }
862
 
863
    /**
864
     * getIndexFieldDeclarationList
865
     * Obtain DBMS specific SQL code portion needed to set an index
866
     * declaration to be used in statements like CREATE TABLE.
867
     *
868
     * @return string
869
     */
870
    public function getIndexFieldDeclarationList(array $fields)
871
    {
872
        $ret = array();
873
        foreach ($fields as $field => $definition) {
874
            if (is_array($definition)) {
875
                $ret[] = $this->conn->quoteIdentifier($field);
876
            } else {
877
                $ret[] = $this->conn->quoteIdentifier($definition);
878
            }
879
        }
880
        return implode(', ', $ret);
881
    }
882
 
883
    /**
884
     * A method to return the required SQL string that fits between CREATE ... TABLE
885
     * to create the table as a temporary table.
886
     *
887
     * Should be overridden in driver classes to return the correct string for the
888
     * specific database type.
889
     *
890
     * The default is to return the string "TEMPORARY" - this will result in a
891
     * SQL error for any database that does not support temporary tables, or that
892
     * requires a different SQL command from "CREATE TEMPORARY TABLE".
893
     *
894
     * @return string The string required to be placed between "CREATE" and "TABLE"
895
     *                to generate a temporary table, if possible.
896
     */
897
    public function getTemporaryTableQuery()
898
    {
899
        return 'TEMPORARY';
900
    }
901
 
902
    /**
903
     * getForeignKeyDeclaration
904
     * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
905
     * of a field declaration to be used in statements like CREATE TABLE.
906
     *
907
     * @param array $definition         an associative array with the following structure:
908
     *          name                    optional constraint name
909
     *
910
     *          local                   the local field(s)
911
     *
912
     *          foreign                 the foreign reference field(s)
913
     *
914
     *          foreignTable            the name of the foreign table
915
     *
916
     *          onDelete                referential delete action
917
     *
918
     *          onUpdate                referential update action
919
     *
920
     *          deferred                deferred constraint checking
921
     *
922
     * The onDelete and onUpdate keys accept the following values:
923
     *
924
     * CASCADE: Delete or update the row from the parent table and automatically delete or
925
     *          update the matching rows in the child table. Both ON DELETE CASCADE and ON UPDATE CASCADE are supported.
926
     *          Between two tables, you should not define several ON UPDATE CASCADE clauses that act on the same column
927
     *          in the parent table or in the child table.
928
     *
929
     * SET NULL: Delete or update the row from the parent table and set the foreign key column or columns in the
930
     *          child table to NULL. This is valid only if the foreign key columns do not have the NOT NULL qualifier
931
     *          specified. Both ON DELETE SET NULL and ON UPDATE SET NULL clauses are supported.
932
     *
933
     * NO ACTION: In standard SQL, NO ACTION means no action in the sense that an attempt to delete or update a primary
934
     *           key value is not allowed to proceed if there is a related foreign key value in the referenced table.
935
     *
936
     * RESTRICT: Rejects the delete or update operation for the parent table. NO ACTION and RESTRICT are the same as
937
     *           omitting the ON DELETE or ON UPDATE clause.
938
     *
939
     * SET DEFAULT
940
     *
941
     * @return string  DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
942
     *                 of a field declaration.
943
     */
944
    public function getForeignKeyDeclaration(array $definition)
945
    {
946
        $sql  = $this->getForeignKeyBaseDeclaration($definition);
947
        $sql .= $this->getAdvancedForeignKeyOptions($definition);
948
 
949
        return $sql;
950
    }
951
 
952
    /**
953
     * getAdvancedForeignKeyOptions
954
     * Return the FOREIGN KEY query section dealing with non-standard options
955
     * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
956
     *
957
     * @param array $definition     foreign key definition
958
     * @return string
959
     */
960
    public function getAdvancedForeignKeyOptions(array $definition)
961
    {
962
        $query = '';
963
        if ( ! empty($definition['onUpdate'])) {
964
            $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialAction($definition['onUpdate']);
965
        }
966
        if ( ! empty($definition['onDelete'])) {
967
            $query .= ' ON DELETE ' . $this->getForeignKeyReferentialAction($definition['onDelete']);
968
        }
969
        return $query;
970
    }
971
 
972
    /**
973
     * getForeignKeyReferentialAction
974
     *
975
     * returns given referential action in uppercase if valid, otherwise throws
976
     * an exception
977
     *
978
     * @throws Doctrine_Exception_Exception     if unknown referential action given
979
     * @param string $action    foreign key referential action
980
     * @param string            foreign key referential action in uppercase
981
     */
982
    public function getForeignKeyReferentialAction($action)
983
    {
984
        $upper = strtoupper($action);
985
        switch ($upper) {
986
            case 'CASCADE':
987
            case 'SET NULL':
988
            case 'NO ACTION':
989
            case 'RESTRICT':
990
            case 'SET DEFAULT':
991
                return $upper;
992
            break;
993
            default:
994
                throw new Doctrine_Export_Exception('Unknown foreign key referential action \'' . $upper . '\' given.');
995
        }
996
    }
997
 
998
    /**
999
     * getForeignKeyBaseDeclaration
1000
     * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint
1001
     * of a field declaration to be used in statements like CREATE TABLE.
1002
     *
1003
     * @param array $definition
1004
     * @return string
1005
     */
1006
    public function getForeignKeyBaseDeclaration(array $definition)
1007
    {
1008
        $sql = '';
1009
        if (isset($definition['name'])) {
1010
            $sql .= 'CONSTRAINT ' . $this->conn->quoteIdentifier($this->conn->formatter->getForeignKeyName($definition['name'])) . ' ';
1011
        }
1012
        $sql .= 'FOREIGN KEY (';
1013
 
1014
        if ( ! isset($definition['local'])) {
1015
            throw new Doctrine_Export_Exception('Local reference field missing from definition.');
1016
        }
1017
        if ( ! isset($definition['foreign'])) {
1018
            throw new Doctrine_Export_Exception('Foreign reference field missing from definition.');
1019
        }
1020
        if ( ! isset($definition['foreignTable'])) {
1021
            throw new Doctrine_Export_Exception('Foreign reference table missing from definition.');
1022
        }
1023
 
1024
        if ( ! is_array($definition['local'])) {
1025
            $definition['local'] = array($definition['local']);
1026
        }
1027
        if ( ! is_array($definition['foreign'])) {
1028
            $definition['foreign'] = array($definition['foreign']);
1029
        }
1030
 
1031
        $sql .= implode(', ', array_map(array($this->conn, 'quoteIdentifier'), $definition['local']))
1032
              . ') REFERENCES '
1033
              . $this->conn->quoteIdentifier($definition['foreignTable']) . '('
1034
              . implode(', ', array_map(array($this->conn, 'quoteIdentifier'), $definition['foreign'])) . ')';
1035
 
1036
        return $sql;
1037
    }
1038
 
1039
    /**
1040
     * Obtain DBMS specific SQL code portion needed to set the UNIQUE constraint
1041
     * of a field declaration to be used in statements like CREATE TABLE.
1042
     *
1043
     * @return string  DBMS specific SQL code portion needed to set the UNIQUE constraint
1044
     *                 of a field declaration.
1045
     */
1046
    public function getUniqueFieldDeclaration()
1047
    {
1048
        return 'UNIQUE';
1049
    }
1050
 
1051
    /**
1052
     * Obtain DBMS specific SQL code portion needed to set the CHARACTER SET
1053
     * of a field declaration to be used in statements like CREATE TABLE.
1054
     *
1055
     * @param string $charset   name of the charset
1056
     * @return string  DBMS specific SQL code portion needed to set the CHARACTER SET
1057
     *                 of a field declaration.
1058
     */
1059
    public function getCharsetFieldDeclaration($charset)
1060
    {
1061
        return '';
1062
    }
1063
 
1064
    /**
1065
     * Obtain DBMS specific SQL code portion needed to set the COLLATION
1066
     * of a field declaration to be used in statements like CREATE TABLE.
1067
     *
1068
     * @param string $collation   name of the collation
1069
     * @return string  DBMS specific SQL code portion needed to set the COLLATION
1070
     *                 of a field declaration.
1071
     */
1072
    public function getCollationFieldDeclaration($collation)
1073
    {
1074
        return '';
1075
    }
1076
 
1077
    /**
1078
     * exportSchema
1079
     * method for exporting Doctrine_Record classes to a schema
1080
     *
1081
     * if the directory parameter is given this method first iterates
1082
     * recursively trhough the given directory in order to find any model classes
1083
     *
1084
     * Then it iterates through all declared classes and creates tables for the ones
1085
     * that extend Doctrine_Record and are not abstract classes
1086
     *
1087
     * @throws Doctrine_Connection_Exception    if some error other than Doctrine_Core::ERR_ALREADY_EXISTS
1088
     *                                          occurred during the create table operation
1089
     * @param string $directory     optional directory parameter
1090
     * @return void
1091
     */
1092
    public function exportSchema($directory = null)
1093
    {
1094
        if ($directory !== null) {
1095
            $models = Doctrine_Core::filterInvalidModels(Doctrine_Core::loadModels($directory));
1096
        } else {
1097
            $models = Doctrine_Core::getLoadedModels();
1098
        }
1099
 
1100
        $this->exportClasses($models);
1101
    }
1102
 
1103
    public function exportSortedClassesSql($classes, $groupByConnection = true)
1104
    {
1105
         $connections = array();
1106
         foreach ($classes as $class) {
1107
             $connection = Doctrine_Manager::getInstance()->getConnectionForComponent($class);
1108
             $connectionName = $connection->getName();
1109
 
1110
             if ( ! isset($connections[$connectionName])) {
1111
                 $connections[$connectionName] = array(
1112
                     'create_tables'    => array(),
1113
                     'create_sequences' => array(),
1114
                     'create_indexes'   => array(),
1115
                     'alters'           => array(),
1116
                     'create_triggers'  => array(),
1117
                 );
1118
             }
1119
 
1120
             $sql = $connection->export->exportClassesSql(array($class));
1121
 
1122
             // Build array of all the creates
1123
             // We need these to happen first
1124
             foreach ($sql as $key => $query) {
1125
                 // If create table statement
1126
                 if (substr($query, 0, strlen('CREATE TABLE')) == 'CREATE TABLE') {
1127
                     $connections[$connectionName]['create_tables'][] = $query;
1128
 
1129
                     unset($sql[$key]);
1130
                     continue;
1131
                 }
1132
 
1133
                 // If create sequence statement
1134
                 if (substr($query, 0, strlen('CREATE SEQUENCE')) == 'CREATE SEQUENCE') {
1135
                     $connections[$connectionName]['create_sequences'][] = $query;
1136
 
1137
                     unset($sql[$key]);
1138
                     continue;
1139
                 }
1140
 
1141
                 // If create index statement
1142
                 if (preg_grep("/CREATE ([^ ]* )?INDEX/", array($query))) {
1143
                     $connections[$connectionName]['create_indexes'][] =  $query;
1144
 
1145
                     unset($sql[$key]);
1146
                     continue;
1147
                 }
1148
 
1149
                 // If alter table statement or oracle anonymous block enclosing alter
1150
                 if (substr($query, 0, strlen('ALTER TABLE')) == 'ALTER TABLE'
1151
                       || substr($query, 0, strlen('DECLARE')) == 'DECLARE') {
1152
                     $connections[$connectionName]['alters'][] = $query;
1153
 
1154
                     unset($sql[$key]);
1155
                     continue;
1156
                 }
1157
 
1158
                 // If create trgger statement
1159
                 if (substr($query, 0, strlen('CREATE TRIGGER')) == 'CREATE TRIGGER') {
1160
                     $connections[$connectionName]['create_triggers'][] = $query;
1161
 
1162
                 	 unset($sql[$key]);
1163
                     continue;
1164
                 }
1165
 
1166
                 // If comment statement
1167
                 if (substr($query, 0, strlen('COMMENT ON')) == 'COMMENT ON') {
1168
                     $connections[$connectionName]['comments'][] = $query;
1169
 
1170
                     unset($sql[$key]);
1171
                     continue;
1172
                 }
1173
             }
1174
         }
1175
 
1176
         // Loop over all the sql again to merge everything together so it is in the correct order
1177
         $build = array();
1178
         foreach ($connections as $connectionName => $sql) {
1179
             $build[$connectionName] = array_unique(array_merge($sql['create_tables'], $sql['create_sequences'], $sql['create_indexes'], $sql['alters'], $sql['create_triggers']));
1180
         }
1181
 
1182
         if ( ! $groupByConnection) {
1183
             $new = array();
1184
             foreach($build as $connectionname => $sql) {
1185
                 $new = array_unique(array_merge($new, $sql));
1186
             }
1187
             $build = $new;
1188
         }
1189
         return $build;
1190
    }
1191
 
1192
    /**
1193
     * exportClasses
1194
     * method for exporting Doctrine_Record classes to a schema
1195
     *
1196
     * FIXME: This function has ugly hacks in it to make sure sql is inserted in the correct order.
1197
     *
1198
     * @throws Doctrine_Connection_Exception    if some error other than Doctrine_Core::ERR_ALREADY_EXISTS
1199
     *                                          occurred during the create table operation
1200
     * @param array $classes
1201
     * @return void
1202
     */
1203
     public function exportClasses(array $classes)
1204
     {
1205
         $queries = $this->exportSortedClassesSql($classes);
1206
 
1207
         foreach ($queries as $connectionName => $sql) {
1208
             $connection = Doctrine_Manager::getInstance()->getConnection($connectionName);
1209
 
1210
             $connection->beginTransaction();
1211
 
1212
             foreach ($sql as $query) {
1213
                 try {
1214
                     $connection->exec($query);
1215
                 } catch (Doctrine_Connection_Exception $e) {
1216
                     // we only want to silence table already exists errors
1217
                     if ($e->getPortableCode() !== Doctrine_Core::ERR_ALREADY_EXISTS) {
1218
                         $connection->rollback();
1219
                         throw new Doctrine_Export_Exception($e->getMessage() . '. Failing Query: ' . $query);
1220
                     }
1221
                 }
1222
             }
1223
 
1224
             $connection->commit();
1225
         }
1226
     }
1227
 
1228
    /**
1229
     * exportClassesSql
1230
     * method for exporting Doctrine_Record classes to a schema
1231
     *
1232
     * @throws Doctrine_Connection_Exception    if some error other than Doctrine_Core::ERR_ALREADY_EXISTS
1233
     *                                          occurred during the create table operation
1234
     * @param array $classes
1235
     * @return void
1236
     */
1237
    public function exportClassesSql(array $classes)
1238
    {
1239
        $models = Doctrine_Core::filterInvalidModels($classes);
1240
 
1241
        $sql = array();
1242
 
1243
        foreach ($models as $name) {
1244
            $record = new $name();
1245
            $table = $record->getTable();
1246
            $parents = $table->getOption('joinedParents');
1247
 
1248
            foreach ($parents as $parent) {
1249
                $data  = $table->getConnection()->getTable($parent)->getExportableFormat();
1250
 
1251
                $query = $this->conn->export->createTableSql($data['tableName'], $data['columns'], $data['options']);
1252
 
1253
                $sql = array_merge($sql, (array) $query);
1254
            }
1255
 
1256
            // Don't export the tables with attribute EXPORT_NONE'
1257
            if ($table->getAttribute(Doctrine_Core::ATTR_EXPORT) === Doctrine_Core::EXPORT_NONE) {
1258
                continue;
1259
            }
1260
 
1261
            $data = $table->getExportableFormat();
1262
 
1263
            $query = $this->conn->export->createTableSql($data['tableName'], $data['columns'], $data['options']);
1264
 
1265
            if (is_array($query)) {
1266
                $sql = array_merge($sql, $query);
1267
            } else {
1268
                $sql[] = $query;
1269
            }
1270
 
1271
            if ($table->getAttribute(Doctrine_Core::ATTR_EXPORT) & Doctrine_Core::EXPORT_PLUGINS) {
1272
                $sql = array_merge($sql, $this->exportGeneratorsSql($table));
1273
            }
1274
 
1275
            // DC-474: Remove dummy $record from repository to not pollute it during export
1276
            $table->getRepository()->evict($record->getOid());
1277
            unset($record);
1278
        }
1279
 
1280
        $sql = array_unique($sql);
1281
 
1282
        rsort($sql);
1283
 
1284
        return $sql;
1285
    }
1286
 
1287
    /**
1288
     * fetches all generators recursively for given table
1289
     *
1290
     * @param Doctrine_Table $table     table object to retrieve the generators from
1291
     * @return array                    an array of Doctrine_Record_Generator objects
1292
     */
1293
    public function getAllGenerators(Doctrine_Table $table)
1294
    {
1295
        $generators = array();
1296
 
1297
        foreach ($table->getGenerators() as $name => $generator) {
1298
            if ($generator === null) {
1299
                continue;
1300
            }
1301
 
1302
            $generators[] = $generator;
1303
 
1304
            $generatorTable = $generator->getTable();
1305
 
1306
            if ($generatorTable instanceof Doctrine_Table) {
1307
                $generators = array_merge($generators, $this->getAllGenerators($generatorTable));
1308
            }
1309
        }
1310
 
1311
        return $generators;
1312
    }
1313
 
1314
    /**
1315
     * exportGeneratorsSql
1316
     * exports plugin tables for given table
1317
     *
1318
     * @param Doctrine_Table $table     the table in which the generators belong to
1319
     * @return array                    an array of sql strings
1320
     */
1321
    public function exportGeneratorsSql(Doctrine_Table $table)
1322
    {
1323
    	$sql = array();
1324
 
1325
        foreach ($this->getAllGenerators($table) as $name => $generator) {
1326
            $table = $generator->getTable();
1327
 
1328
            // Make sure plugin has a valid table
1329
            if ($table instanceof Doctrine_Table) {
1330
                $data = $table->getExportableFormat();
1331
 
1332
                $query = $this->conn->export->createTableSql($data['tableName'], $data['columns'], $data['options']);
1333
 
1334
                $sql = array_merge($sql, (array) $query);
1335
            }
1336
        }
1337
 
1338
        return $sql;
1339
    }
1340
 
1341
    /**
1342
     * exportSql
1343
     * returns the sql for exporting Doctrine_Record classes to a schema
1344
     *
1345
     * if the directory parameter is given this method first iterates
1346
     * recursively trhough the given directory in order to find any model classes
1347
     *
1348
     * Then it iterates through all declared classes and creates tables for the ones
1349
     * that extend Doctrine_Record and are not abstract classes
1350
     *
1351
     * @throws Doctrine_Connection_Exception    if some error other than Doctrine_Core::ERR_ALREADY_EXISTS
1352
     *                                          occurred during the create table operation
1353
     * @param string $directory     optional directory parameter
1354
     * @return void
1355
     */
1356
    public function exportSql($directory = null)
1357
    {
1358
        if ($directory !== null) {
1359
            $models = Doctrine_Core::filterInvalidModels(Doctrine_Core::loadModels($directory));
1360
        } else {
1361
            $models = Doctrine_Core::getLoadedModels();
1362
        }
1363
 
1364
        return $this->exportSortedClassesSql($models, false);
1365
    }
1366
 
1367
    /**
1368
     * exportTable
1369
     * exports given table into database based on column and option definitions
1370
     *
1371
     * @throws Doctrine_Connection_Exception    if some error other than Doctrine_Core::ERR_ALREADY_EXISTS
1372
     *                                          occurred during the create table operation
1373
     * @return boolean                          whether or not the export operation was successful
1374
     *                                          false if table already existed in the database
1375
     */
1376
    public function exportTable(Doctrine_Table $table)
1377
    {
1378
        try {
1379
            $data = $table->getExportableFormat();
1380
 
1381
            $this->conn->export->createTable($data['tableName'], $data['columns'], $data['options']);
1382
        } catch(Doctrine_Connection_Exception $e) {
1383
            // we only want to silence table already exists errors
1384
            if ($e->getPortableCode() !== Doctrine_Core::ERR_ALREADY_EXISTS) {
1385
                throw $e;
1386
            }
1387
        }
1388
    }
1389
}