Doctrine.php 28.9 KB
Newer Older
lsmith's avatar
lsmith committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
<?php
/*
 *  $Id$
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many individuals
 * and is licensed under the LGPL. For more information, see
 * <http://www.phpdoctrine.com>.
 */

/**
 * Doctrine
 * the base class of Doctrine framework
 *
 * @package     Doctrine
 * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
 * @author      Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
 * @link        www.phpdoctrine.com
 * @since       1.0
 * @version     $Revision$
 */
lsmith's avatar
lsmith committed
34 35 36
final class Doctrine
{
    /**
lsmith's avatar
lsmith committed
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
     * ERROR CONSTANTS
     */
    const ERR                       = -1;
    const ERR_SYNTAX                = -2;
    const ERR_CONSTRAINT            = -3;
    const ERR_NOT_FOUND             = -4;
    const ERR_ALREADY_EXISTS        = -5;
    const ERR_UNSUPPORTED           = -6;
    const ERR_MISMATCH              = -7;
    const ERR_INVALID               = -8;
    const ERR_NOT_CAPABLE           = -9;
    const ERR_TRUNCATED             = -10;
    const ERR_INVALID_NUMBER        = -11;
    const ERR_INVALID_DATE          = -12;
    const ERR_DIVZERO               = -13;
    const ERR_NODBSELECTED          = -14;
    const ERR_CANNOT_CREATE         = -15;
    const ERR_CANNOT_DELETE         = -16;
    const ERR_CANNOT_DROP           = -17;
    const ERR_NOSUCHTABLE           = -18;
    const ERR_NOSUCHFIELD           = -19;
    const ERR_NEED_MORE_DATA        = -20;
    const ERR_NOT_LOCKED            = -21;
    const ERR_VALUE_COUNT_ON_ROW    = -22;
    const ERR_INVALID_DSN           = -23;
    const ERR_CONNECT_FAILED        = -24;
    const ERR_EXTENSION_NOT_FOUND   = -25;
    const ERR_NOSUCHDB              = -26;
    const ERR_ACCESS_VIOLATION      = -27;
    const ERR_CANNOT_REPLACE        = -28;
    const ERR_CONSTRAINT_NOT_NULL   = -29;
    const ERR_DEADLOCK              = -30;
    const ERR_CANNOT_ALTER          = -31;
    const ERR_MANAGER               = -32;
    const ERR_MANAGER_PARSE         = -33;
    const ERR_LOADMODULE            = -34;
    const ERR_INSUFFICIENT_DATA     = -35;
    const ERR_CLASS_NAME            = -36;
75

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
    /**
     * PDO derived constants
     */
    const CASE_LOWER = 2;
    const CASE_NATURAL = 0;
    const CASE_UPPER = 1;
    const CURSOR_FWDONLY = 0;
    const CURSOR_SCROLL = 1;
    const ERRMODE_EXCEPTION = 2;
    const ERRMODE_SILENT = 0;
    const ERRMODE_WARNING = 1;
    const FETCH_ASSOC = 2;
    const FETCH_BOTH = 4;
    const FETCH_BOUND = 6;
    const FETCH_CLASS = 8;
    const FETCH_CLASSTYPE = 262144;
    const FETCH_COLUMN = 7;
    const FETCH_FUNC = 10;
    const FETCH_GROUP = 65536;
    const FETCH_INTO = 9;
    const FETCH_LAZY = 1;
    const FETCH_NAMED = 11;
    const FETCH_NUM = 3;
    const FETCH_OBJ = 5;
    const FETCH_ORI_ABS = 4;
    const FETCH_ORI_FIRST = 2;
    const FETCH_ORI_LAST = 3;
    const FETCH_ORI_NEXT = 0;
    const FETCH_ORI_PRIOR = 1;
    const FETCH_ORI_REL = 5;
    const FETCH_SERIALIZE = 524288;
    const FETCH_UNIQUE = 196608;
    const NULL_EMPTY_STRING = 1;
    const NULL_NATURAL = 0;
110
    const NULL_TO_STRING         = NULL;
111 112 113 114 115 116 117
    const PARAM_BOOL = 5;
    const PARAM_INPUT_OUTPUT = -2147483648;
    const PARAM_INT = 1;
    const PARAM_LOB = 3;
    const PARAM_NULL = 0;
    const PARAM_STMT = 4;
    const PARAM_STR = 2;
118

lsmith's avatar
lsmith committed
119 120 121
    /**
     * ATTRIBUTE CONSTANTS
     */
122

123 124 125 126 127
    /**
     * PDO derived attributes
     */
    const ATTR_AUTOCOMMIT           = 0;
    const ATTR_PREFETCH             = 1;
128
    const ATTR_TIMEOUT              = 2;
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
    const ATTR_ERRMODE              = 3;
    const ATTR_SERVER_VERSION       = 4;
    const ATTR_CLIENT_VERSION       = 5;
    const ATTR_SERVER_INFO          = 6;
    const ATTR_CONNECTION_STATUS    = 7;
    const ATTR_CASE                 = 8;
    const ATTR_CURSOR_NAME          = 9;
    const ATTR_CURSOR               = 10;
    const ATTR_ORACLE_NULLS         = 11;
    const ATTR_PERSISTENT           = 12;
    const ATTR_STATEMENT_CLASS      = 13;
    const ATTR_FETCH_TABLE_NAMES    = 14;
    const ATTR_FETCH_CATALOG_NAMES  = 15;
    const ATTR_DRIVER_NAME          = 16;
    const ATTR_STRINGIFY_FETCHES    = 17;
    const ATTR_MAX_COLUMN_LEN       = 18;
zYne's avatar
zYne committed
145

146 147 148 149 150 151 152 153
    /**
     * Doctrine constants
     */
    const ATTR_LISTENER             = 100;
    const ATTR_QUOTE_IDENTIFIER     = 101;
    const ATTR_FIELD_CASE           = 102;
    const ATTR_IDXNAME_FORMAT       = 103;
    const ATTR_SEQNAME_FORMAT       = 104;
zYne's avatar
zYne committed
154
    const ATTR_SEQCOL_NAME          = 105;
155 156 157
    const ATTR_CMPNAME_FORMAT       = 118;
    const ATTR_DBNAME_FORMAT        = 117;
    const ATTR_TBLCLASS_FORMAT      = 119;
zYne's avatar
zYne committed
158
    const ATTR_EXPORT               = 140;
159
    const ATTR_DECIMAL_PLACES       = 141;
160

161
    const ATTR_PORTABILITY          = 106;
162
    const ATTR_VALIDATE             = 107;
163 164 165 166 167 168 169
    const ATTR_COLL_KEY             = 108;
    const ATTR_QUERY_LIMIT          = 109;
    const ATTR_DEFAULT_TABLE_TYPE   = 112;
    const ATTR_DEF_TEXT_LENGTH      = 113;
    const ATTR_DEF_VARCHAR_LENGTH   = 114;
    const ATTR_DEF_TABLESPACE       = 115;
    const ATTR_EMULATE_DATABASE     = 116;
170
    const ATTR_USE_NATIVE_ENUM      = 117;
zYne's avatar
zYne committed
171
    const ATTR_DEFAULT_SEQUENCE     = 133;
lsmith's avatar
lsmith committed
172

173 174 175 176
    const ATTR_FETCHMODE            = 118;
    const ATTR_NAME_PREFIX          = 121;
    const ATTR_CREATE_TABLES        = 122;
    const ATTR_COLL_LIMIT           = 123;
177

zYne's avatar
zYne committed
178
    const ATTR_CACHE                = 150;
zYne's avatar
zYne committed
179
    const ATTR_CACHE_LIFESPAN       = 151;
zYne's avatar
zYne committed
180
    const ATTR_LOAD_REFERENCES      = 153;
181
    const ATTR_RECORD_LISTENER      = 154;
zYne's avatar
zYne committed
182 183
    const ATTR_THROW_EXCEPTIONS     = 155;

lsmith's avatar
lsmith committed
184 185 186 187 188 189 190 191
    /**
     * LIMIT CONSTANTS
     */

    /**
     * constant for row limiting
     */
    const LIMIT_ROWS       = 1;
192

lsmith's avatar
lsmith committed
193 194 195 196 197 198 199 200 201 202 203 204 205 206
    /**
     * constant for record limiting
     */
    const LIMIT_RECORDS    = 2;

    /**
     * FETCHMODE CONSTANTS
     */

    /**
     * IMMEDIATE FETCHING
     * mode for immediate fetching
     */
    const FETCH_IMMEDIATE       = 0;
207

lsmith's avatar
lsmith committed
208 209 210 211 212
    /**
     * BATCH FETCHING
     * mode for batch fetching
     */
    const FETCH_BATCH           = 1;
213

lsmith's avatar
lsmith committed
214 215 216 217 218
    /**
     * LAZY FETCHING
     * mode for offset fetching
     */
    const FETCH_OFFSET          = 3;
219

lsmith's avatar
lsmith committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
    /**
     * LAZY OFFSET FETCHING
     * mode for lazy offset fetching
     */
    const FETCH_LAZY_OFFSET     = 4;

    /**
     * FETCH CONSTANTS
     */


    /**
     * FETCH VALUEHOLDER
     */
    const FETCH_VHOLDER         = 1;
235

lsmith's avatar
lsmith committed
236 237 238
    /**
     * FETCH RECORD
     *
lsmith's avatar
lsmith committed
239
     * Specifies that the fetch method shall return Doctrine_Record
lsmith's avatar
lsmith committed
240 241 242 243 244
     * objects as the elements of the result set.
     *
     * This is the default fetchmode.
     */
    const FETCH_RECORD          = 2;
245

lsmith's avatar
lsmith committed
246
    /**
lsmith's avatar
lsmith committed
247
     * FETCH ARRAY
lsmith's avatar
lsmith committed
248 249
     */
    const FETCH_ARRAY           = 3;
250

lsmith's avatar
lsmith committed
251 252 253 254 255 256
    /**
     * PORTABILITY CONSTANTS
     */

    /**
     * Portability: turn off all portability features.
257
     * @see self::ATTR_PORTABILITY
lsmith's avatar
lsmith committed
258
     */
zYne's avatar
zYne committed
259
    const PORTABILITY_NONE          = 0;
260

lsmith's avatar
lsmith committed
261 262 263
    /**
     * Portability: convert names of tables and fields to case defined in the
     * "field_case" option when using the query*(), fetch*() methods.
264
     * @see self::ATTR_PORTABILITY
lsmith's avatar
lsmith committed
265 266 267 268 269
     */
    const PORTABILITY_FIX_CASE      = 1;

    /**
     * Portability: right trim the data output by query*() and fetch*().
270
     * @see self::ATTR_PORTABILITY
lsmith's avatar
lsmith committed
271 272
     */
    const PORTABILITY_RTRIM         = 2;
273

lsmith's avatar
lsmith committed
274 275
    /**
     * Portability: force reporting the number of rows deleted.
276
     * @see self::ATTR_PORTABILITY
lsmith's avatar
lsmith committed
277 278
     */
    const PORTABILITY_DELETE_COUNT  = 4;
279

lsmith's avatar
lsmith committed
280 281 282
    /**
     * Portability: convert empty values to null strings in data output by
     * query*() and fetch*().
283
     * @see self::ATTR_PORTABILITY
lsmith's avatar
lsmith committed
284 285
     */
    const PORTABILITY_EMPTY_TO_NULL = 8;
286

lsmith's avatar
lsmith committed
287 288
    /**
     * Portability: removes database/table qualifiers from associative indexes
289
     * @see self::ATTR_PORTABILITY
lsmith's avatar
lsmith committed
290 291
     */
    const PORTABILITY_FIX_ASSOC_FIELD_NAMES = 16;
292

zYne's avatar
zYne committed
293 294
    /**
     * Portability: makes Doctrine_Expression throw exception for unportable RDBMS expressions
295
     * @see self::ATTR_PORTABILITY
zYne's avatar
zYne committed
296 297
     */
    const PORTABILITY_EXPR          = 32;
298

lsmith's avatar
lsmith committed
299 300
    /**
     * Portability: turn on all portability features.
301
     * @see self::ATTR_PORTABILITY
lsmith's avatar
lsmith committed
302
     */
zYne's avatar
zYne committed
303
    const PORTABILITY_ALL           = 63;
lsmith's avatar
lsmith committed
304 305 306 307 308 309 310 311 312

    /**
     * LOCKMODE CONSTANTS
     */

    /**
     * mode for optimistic locking
     */
    const LOCK_OPTIMISTIC       = 0;
313

lsmith's avatar
lsmith committed
314 315 316 317
    /**
     * mode for pessimistic locking
     */
    const LOCK_PESSIMISTIC      = 1;
318

zYne's avatar
zYne committed
319 320 321
    /**
     * EXPORT CONSTANTS
     */
322

zYne's avatar
zYne committed
323
    /**
324
     * EXPORT_NONE
zYne's avatar
zYne committed
325 326
     */
    const EXPORT_NONE               = 0;
327

zYne's avatar
zYne committed
328
    /**
329
     * EXPORT_TABLES
zYne's avatar
zYne committed
330
     */
zYne's avatar
zYne committed
331
    const EXPORT_TABLES             = 1;
332

zYne's avatar
zYne committed
333
    /**
334
     * EXPORT_CONSTRAINTS
zYne's avatar
zYne committed
335
     */
zYne's avatar
zYne committed
336
    const EXPORT_CONSTRAINTS        = 2;
337

zYne's avatar
zYne committed
338
    /**
339
     * EXPORT_PLUGINS
zYne's avatar
zYne committed
340 341
     */
    const EXPORT_PLUGINS            = 4;
342

zYne's avatar
zYne committed
343
    /**
344
     * EXPORT_ALL
zYne's avatar
zYne committed
345
     */
zYne's avatar
zYne committed
346
    const EXPORT_ALL                = 7;
347

zYne's avatar
zYne committed
348 349 350 351 352
    /**
     * HYDRATION CONSTANTS
     */
    const HYDRATE_RECORD            = 2;
    
353 354 355
    /**
     * HYDRATE_ARRAY
     */
zYne's avatar
zYne committed
356
    const HYDRATE_ARRAY             = 3;
zYne's avatar
zYne committed
357

zYne's avatar
zYne committed
358 359 360 361 362
    /**
     * VALIDATION CONSTANTS
     */
    const VALIDATE_NONE             = 0;

363 364 365
    /**
     * VALIDATE_LENGTHS
     */
zYne's avatar
zYne committed
366
    const VALIDATE_LENGTHS          = 1;
367 368 369 370

    /**
     * VALIDATE_TYPES
     */
zYne's avatar
zYne committed
371
    const VALIDATE_TYPES            = 2;
372 373 374 375

    /**
     * VALIDATE_CONSTRAINTS
     */
zYne's avatar
zYne committed
376
    const VALIDATE_CONSTRAINTS      = 4;
377 378 379 380

    /**
     * VALIDATE_ALL
     */
zYne's avatar
zYne committed
381
    const VALIDATE_ALL              = 7;
zYne's avatar
zYne committed
382 383

    /**
384 385
     * IDENTIFIER_AUTOINC
     *
zYne's avatar
zYne committed
386 387 388
     * constant for auto_increment identifier
     */
    const IDENTIFIER_AUTOINC        = 1;
389

zYne's avatar
zYne committed
390
    /**
391 392
     * IDENTIFIER_SEQUENCE
     *
zYne's avatar
zYne committed
393 394 395
     * constant for sequence identifier
     */
    const IDENTIFIER_SEQUENCE       = 2;
396

zYne's avatar
zYne committed
397
    /**
398 399
     * IDENTIFIER_NATURAL
     *
zYne's avatar
zYne committed
400 401 402
     * constant for normal identifier
     */
    const IDENTIFIER_NATURAL        = 3;
403

zYne's avatar
zYne committed
404
    /**
405 406
     * IDENTIFIER_COMPOSITE
     *
zYne's avatar
zYne committed
407 408 409
     * constant for composite identifier
     */
    const IDENTIFIER_COMPOSITE      = 4;
410

lsmith's avatar
lsmith committed
411
    /**
412 413
     * Path
     *
lsmith's avatar
lsmith committed
414 415
     * @var string $path            doctrine root directory
     */
416
    private static $_path;
417

zYne's avatar
zYne committed
418
    /**
419 420 421 422
     * Debug
     *
     * Bool true/false
     *
zYne's avatar
zYne committed
423 424 425
     * @var boolean $_debug
     */
    private static $_debug = false;
426

427 428 429 430 431 432 433 434 435 436
    /**
     * __construct
     *
     * @return void
     * @throws Doctrine_Exception
     */
    public function __construct()
    {
        throw new Doctrine_Exception('Doctrine is static class. No instances can be created.');
    }
437

438 439 440 441 442 443
    /**
     * debug
     *
     * @param string $bool 
     * @return void
     */
zYne's avatar
zYne committed
444 445 446 447 448
    public static function debug($bool = null)
    {
        if ($bool !== null) {
            self::$_debug = (bool) $bool;
        }
449
        
zYne's avatar
zYne committed
450 451
        return self::$_debug;
    }
452

lsmith's avatar
lsmith committed
453 454 455 456 457 458
    /**
     * getPath
     * returns the doctrine root
     *
     * @return string
     */
lsmith's avatar
lsmith committed
459 460
    public static function getPath()
    {
461 462
        if ( ! self::$_path) {
            self::$_path = dirname(__FILE__);
lsmith's avatar
lsmith committed
463
        }
464
        
465
        return self::$_path;
lsmith's avatar
lsmith committed
466
    }
467

lsmith's avatar
lsmith committed
468 469 470 471 472 473
    /**
     * loadAll
     * loads all runtime classes
     *
     * @return void
     */
lsmith's avatar
lsmith committed
474 475
    public static function loadAll()
    {
476 477
        return self::loadAllRuntimeClasses();
    }
478

479 480 481 482 483 484 485 486 487 488 489 490
    /**
     * importSchema
     * method for importing existing schema to Doctrine_Record classes
     *
     * @param string $directory Directory to write your models to
     * @param array $databases Array of databases to generate models for
     * @return boolean
     */
    public static function importSchema($directory, array $databases = array())
    {
        return self::generateModelsFromDb($directory, $databases);
    }
491

492 493 494 495 496 497 498 499 500 501 502
    /**
     * exportSchema
     * method for exporting Doctrine_Record classes to a schema
     *
     * @param string $directory Directory containing your models
     * @return void
     */
    public static function exportSchema($directory = null)
    {
        return self::createTablesFromModels($directory);
    }
503

504 505 506 507 508 509 510 511 512 513
    /**
     * exportSql
     * method for exporting Doctrine_Record classes to a schema
     *
     * @param string $directory
     */
    public static function exportSql($directory = null)
    {
        return self::generateSqlFromModels($directory);
    }
514

515 516 517 518 519 520 521 522 523 524 525 526 527 528
    /**
     * loadAllRuntimeClasses
     *
     * loads all runtime classes
     *
     * @return void
     */
    public static function loadAllRuntimeClasses()
    {
        $classes = Doctrine_Compiler::getRuntimeClasses();

        foreach ($classes as $class) {
            self::autoload($class);
        }
lsmith's avatar
lsmith committed
529
    }
530

Jonathan.Wage's avatar
Jonathan.Wage committed
531 532 533 534 535 536
    /**
     * loadModels
     *
     * Recursively load all models from a directory or array of directories
     * 
     * @param string $directory Path to directory of models or array of directory paths
537
     * @return array $loadedModels
Jonathan.Wage's avatar
Jonathan.Wage committed
538 539 540
     */
    public static function loadModels($directory)
    {
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
        $declared = get_declared_classes();
        
        if ($directory !== null) {
            foreach ((array) $directory as $dir) {
                $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir),
                                                        RecursiveIteratorIterator::LEAVES_ONLY);

                foreach ($it as $file) {
                    $e = explode('.', $file->getFileName());
                    if (end($e) === 'php' && strpos($file->getFileName(), '.inc') === false) {
                        require_once $file->getPathName();
                    }
                }
            }
            
            $declared = array_diff(get_declared_classes(), $declared);
        }
        
        return self::getLoadedModels($declared);
Jonathan.Wage's avatar
Jonathan.Wage committed
560
    }
561

Jonathan.Wage's avatar
Jonathan.Wage committed
562 563 564
    /**
     * getLoadedModels
     *
565 566
     * Get all the loaded models, you can provide an array of classes or it will use get_declared_classes()
     * 
567 568 569
     * Will filter through an array of classes and return the Doctrine_Records out of them.
     * If you do not specify $classes it will return all of the currently loaded Doctrine_Records
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
570
     * @param $classes Array of classes to filter through, otherwise uses get_declared_classes()
571
     * @return array $loadedModels
Jonathan.Wage's avatar
Jonathan.Wage committed
572 573 574
     */
    public static function getLoadedModels($classes = null)
    {
575 576 577 578 579 580 581 582
        if ($classes === null) {
            $classes = get_declared_classes();
        }
        
        $parent = new ReflectionClass('Doctrine_Record');
        
        $loadedModels = array();
        
583
        foreach ((array) $classes as $name) {
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
            $class = new ReflectionClass($name);
            
            // Skip the following classes
            // - abstract classes
            // - not a subclass of Doctrine_Record 
            // - don't have a setTableDefinition method
            if ($class->isAbstract() || 
                !$class->isSubClassOf($parent) || 
                !$class->hasMethod('setTableDefinition')) {
                continue;
            }
            
            $loadedModels[] = $name;
        }
        
        return $loadedModels;
Jonathan.Wage's avatar
Jonathan.Wage committed
600
    }
601

602 603 604 605 606 607
    /**
     * getConnectionByTableName
     *
     * Get the connection object for a table by the actual table name
     * 
     * @param string $tableName 
608
     * @return object Doctrine_Connection
609 610
     */
    public static function getConnectionByTableName($tableName)
Jonathan.Wage's avatar
Jonathan.Wage committed
611
    {
612 613 614 615 616 617 618 619 620 621 622 623
        $loadedModels = self::getLoadedModels();
        
        foreach ($loadedModels as $name) {
            $model = new $name();
            $table = $model->getTable();
            
            if ($table->getTableName() == $tableName) {
               return $table->getConnection(); 
            }
        }
        
        return Doctrine_Manager::connection();
Jonathan.Wage's avatar
Jonathan.Wage committed
624
    }
625

lsmith's avatar
lsmith committed
626
    /**
627 628
     * generateModelsFromDb
     *
lsmith's avatar
lsmith committed
629 630
     * method for importing existing schema to Doctrine_Record classes
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
631 632
     * @param string $directory Directory to write your models to
     * @param array $databases Array of databases to generate models for
zYne's avatar
zYne committed
633
     * @return boolean
634
     * @throws Exception
lsmith's avatar
lsmith committed
635
     */
636
    public static function generateModelsFromDb($directory, array $databases = array())
lsmith's avatar
lsmith committed
637
    {
638
        return Doctrine_Manager::connection()->import->importSchema($directory, $databases);
639
    }
640

lsmith's avatar
lsmith committed
641
    /**
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
     * generateYamlFromDb
     *
     * Generates models from database to temporary location then uses those models to generate a yaml schema file.
     * This should probably be fixed. We should write something to generate a yaml schema file directly from the database.
     *
     * @param string $yamlPath Path to write oyur yaml schema file to
     * @return void
     */
    public static function generateYamlFromDb($yamlPath)
    {
        $directory = '/tmp/tmp_doctrine_models';

        Doctrine::generateModelsFromDb($directory);

        $export = new Doctrine_Export_Schema();
        
        $result = $export->exportSchema($yamlPath, 'yml', $directory);
        
        exec('rm -rf ' . $directory);
        
        return $result;
    }
664

665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
    /**
     * generateModelsFromYaml
     *
     * Generate a yaml schema file from an existing directory of models
     *
     * @param string $yamlPath Path to your yaml schema files
     * @param string $directory Directory to generate your models in
     * @return void
     */
    public static function generateModelsFromYaml($yamlPath, $directory)
    {
        $import = new Doctrine_Import_Schema();
        $import->generateBaseClasses(true);
        
        return $import->importSchema($yamlPath, 'yml', $directory);
    }
681

682 683 684 685
    /**
     * createTablesFromModels
     *
     * Creates database tables for the models in the specified directory
lsmith's avatar
lsmith committed
686
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
687 688
     * @param string $directory Directory containing your models
     * @return void
lsmith's avatar
lsmith committed
689
     */
690
    public static function createTablesFromModels($directory = null)
lsmith's avatar
lsmith committed
691
    {
692
        return Doctrine_Manager::connection()->export->exportSchema($directory);
693
    }
694

zYne's avatar
zYne committed
695
    /**
696
     * generateSqlFromModels
zYne's avatar
zYne committed
697
     *
698
     * @param string $directory 
699
     * @return string $build  String of sql queries. One query per line
zYne's avatar
zYne committed
700
     */
701
    public static function generateSqlFromModels($directory = null)
zYne's avatar
zYne committed
702
    {
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
        $sql = Doctrine_Manager::connection()->export->exportSql($directory);
        
        $build = '';
        foreach ($sql as $query) {
            $build .= $query.";\n";
        }
        
        return $build;
    }

    /**
     * generateYamlFromModels
     *
     * Generate yaml schema file for the models in the specified directory
     *
     * @param string $yamlPath Path to your yaml schema files
     * @param string $directory Directory to generate your models in
     * @return void
     */
    public static function generateYamlFromModels($yamlPath, $directory)
    {
        $export = new Doctrine_Export_Schema();
        
        return $export->exportSchema($yamlPath, 'yml', $directory);
    }
728

729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
    /**
     * createDatabases
     *
     * Creates databases for connections
     *
     * @param string $specifiedConnections Array of connections you wish to create the database for
     * @return void
     */
    public static function createDatabases($specifiedConnections)
    {
        if (!is_array($specifiedConnections)) {
            $specifiedConnections = (array) $specifiedConnections;
        }
        
        $connections = Doctrine_Manager::getInstance()->getConnections();
        
        foreach ($connections as $name => $connection) {
            if (!empty($specifiedConnections) && !in_array($name, $specifiedConnections)) {
                continue;
            }
            
            $connection->export->createDatabase($name);
        }
    }
753

754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
    /**
     * dropDatabases
     *
     * Drops databases for connections
     *
     * @param string $specifiedConnections Array of connections you wish to drop the database for
     * @return void
     */
    public static function dropDatabases($specifiedConnections = array())
    {
        if (!is_array($specifiedConnections)) {
            $specifiedConnections = (array) $specifiedConnections;
        }
        
        $connections = Doctrine_Manager::getInstance()->getConnections();
        
        foreach ($connections as $name => $connection) {
            if (!empty($specifiedConnections) && !in_array($name, $specifiedConnections)) {
                continue;
            }
            
            $connection->export->dropDatabase($name);
        }
    }
778

779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
    /**
     * dumpData
     *
     * Dump data to a yaml fixtures file
     *
     * @param string $yamlPath Path to write the yaml data fixtures to
     * @param string $individualFiles Whether or not to dump data to individual fixtures files
     * @return void
     */
    public static function dumpData($yamlPath, $individualFiles = false)
    {
        $data = new Doctrine_Data();
        
        return $data->exportData($yamlPath, 'yml', array(), $individualFiles);
    }
794

795 796 797 798 799 800 801 802 803 804 805 806 807 808
    /**
     * loadData
     *
     * Load data from a yaml fixtures file.
     * The output of dumpData can be fed to loadData
     *
     * @param string $yamlPath Path to your yaml data fixtures
     * @param string $append Whether or not to append the data
     * @return void
     */
    public static function loadData($yamlPath, $append = false)
    {
        $data = new Doctrine_Data();
        
809 810 811 812
        if (!$append) {
            $data->purge();
        }
        
813 814
        return $data->importData($yamlPath, 'yml');
    }
815

816 817 818 819 820 821 822 823 824 825 826
    /**
     * loadDummyData
     *
     * Populdate your models with dummy data
     *
     * @param string $append Whether or not to append the data
     * @param string $num Number of records to populate
     * @return void
     */
    public static function loadDummyData($append, $num = 5)
    {
827
        $data = new Doctrine_Data();
828

829 830
        if (!$append) {
          $data->purge();
831 832 833 834 835 836 837 838 839 840
        }
        
        return $data->importDummyData($num);
    }
    
    /**
     * migrate
     * 
     * Migrate database to specified $to version. Migrates from current to latest if you do not specify.
     *
841
     * @param string $migrationsPath Path to migrations directory which contains your migration classes
842
     * @param string $to Version you wish to migrate to.
843 844
     * @return bool true
     * @throws new Doctrine_Migration_Exception
845
     */
846
    public static function migrate($migrationsPath, $to = null)
847
    {
848
        $migration = new Doctrine_Migration($migrationsPath);
849 850 851
        
        return $migration->migrate($to);
    }
852

853 854 855 856 857 858
    /**
     * generateMigrationClass
     *
     * Generate new migration class skeleton
     *
     * @param string $className Name of the Migration class to generate
859
     * @param string $migrationsPath Path to directory which contains your migration classes
860
     */
861
    public static function generateMigrationClass($className, $migrationsPath)
862
    {
863
        $builder = new Doctrine_Migration_Builder($migrationsPath);
864
        
865 866
        return $builder->generateMigrationClass($className);
    }
867

868 869 870 871 872
    /**
     * generateMigrationsFromDb
     *
     * @param string $migrationsPath 
     * @return void
873
     * @throws new Doctrine_Migration_Exception
874
     */
Jonathan.Wage's avatar
Jonathan.Wage committed
875
    public static function generateMigrationsFromDb($migrationsPath)
876 877
    {
        $builder = new Doctrine_Migration_Builder($migrationsPath);
878
        
879 880
        return $builder->generateMigrationsFromDb();
    }
881

882 883 884 885 886 887 888
    /**
     * generateMigrationsFromModels
     *
     * @param string $migrationsPath 
     * @param string $modelsPath 
     * @return void
     */
Jonathan.Wage's avatar
Jonathan.Wage committed
889
    public static function generateMigrationsFromModels($migrationsPath, $modelsPath = null)
890 891
    {
        $builder = new Doctrine_Migration_Builder($migrationsPath);
892
        
893 894 895 896 897 898 899 900 901
        return $builder->generateMigrationsFromModels($modelsPath);
    }
    
    /**
     * getTable
     *
     * @param string $tableName 
     * @return void
     */
Jonathan.Wage's avatar
Jonathan.Wage committed
902
    public static function getTable($tableName)
903 904 905 906 907 908 909 910 911 912 913
    {
        return Doctrine_Manager::table($tableName);
    }
    
    /**
     * connection
     *
     * @param string $adapter 
     * @param string $name 
     * @return void
     */
Jonathan.Wage's avatar
Jonathan.Wage committed
914
    public static function connection($adapter, $name = null)
915 916
    {
        return Doctrine_Manager::connection($adapter, $name);
917
    }
918
    
919 920 921 922 923 924 925 926 927 928 929
    /**
     * fileFinder
     *
     * @param string $type 
     * @return void
     */
    public static function fileFinder($type)
    {
        return Doctrine_FileFinder::type($type);
    }
    
lsmith's avatar
lsmith committed
930 931 932 933 934 935
    /**
     * compile
     * method for making a single file of most used doctrine runtime components
     * including the compiled file instead of multiple files (in worst
     * cases dozens of files) can improve performance by an order of magnitude
     *
936 937
     * @param string $target
     *
lsmith's avatar
lsmith committed
938 939 940
     * @throws Doctrine_Exception
     * @return void
     */
941
    public static function compile($target = null, $includedDrivers = array())
lsmith's avatar
lsmith committed
942
    {
943
        return Doctrine_Compiler::compile($target, $includedDrivers);
lsmith's avatar
lsmith committed
944
    }
945
    
lsmith's avatar
lsmith committed
946 947 948 949 950 951 952
    /**
     * simple autoload function
     * returns true if the class was loaded, otherwise false
     *
     * @param string $classname
     * @return boolean
     */
lsmith's avatar
lsmith committed
953
    public static function autoload($classname)
954
    {
zYne's avatar
zYne committed
955
        if (class_exists($classname, false)) {
lsmith's avatar
lsmith committed
956 957
            return false;
        }
958
        
959 960
        if ( ! self::$_path) {
            self::$_path = dirname(__FILE__);
lsmith's avatar
lsmith committed
961
        }
962 963
        
        $class = self::$_path . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $classname) . '.php';
lsmith's avatar
lsmith committed
964 965 966 967 968 969 970 971 972

        if ( ! file_exists($class)) {
            return false;
        }

        require_once($class);

        return true;
    }
973
    
zYne's avatar
zYne committed
974 975 976 977 978 979
    /**
     * dump
     *
     * dumps a given variable
     *
     * @param mixed $var        a variable of any type
980
     * @param boolean $output   whether to output the content
zYne's avatar
zYne committed
981 982
     * @return void|string
     */
983
    public static function dump($var, $output = true)
zYne's avatar
zYne committed
984
    {
985
        $ret = array();
zYne's avatar
zYne committed
986 987 988 989
        switch (gettype($var)) {
            case 'array':
                $ret[] = 'Array(';
                foreach ($var as $k => $v) {
990
                    $ret[] = $k . ' : ' . self::dump($v, false);
zYne's avatar
zYne committed
991
                }
zYne's avatar
zYne committed
992
                $ret[] = ")";
zYne's avatar
zYne committed
993
                break;
994
            case 'object':
zYne's avatar
zYne committed
995 996 997 998 999
                $ret[] = 'Object(' . get_class($var) . ')';
                break;
            default:
                $ret[] = var_export($var, true);
        }
1000 1001 1002
        if ($output) {
            print implode("\n", $ret);
        }
zYne's avatar
zYne committed
1003 1004
        return implode("\n", $ret);
    }
1005
    
lsmith's avatar
lsmith committed
1006 1007 1008 1009 1010 1011
    /**
     * returns table name from class name
     *
     * @param string $classname
     * @return string
     */
lsmith's avatar
lsmith committed
1012 1013
    public static function tableize($classname)
    {
lsmith's avatar
lsmith committed
1014 1015
         return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $classname));
    }
1016
    
lsmith's avatar
lsmith committed
1017 1018 1019 1020 1021 1022
    /**
     * returns class name from table name
     *
     * @param string $tablename
     * @return string
     */
lsmith's avatar
lsmith committed
1023 1024
    public static function classify($tablename)
    {
1025 1026
        return preg_replace_callback('~(_?)(_)([\w])~', array("Doctrine", "classifyCallback"), ucfirst($tablename));
    }
1027
    
1028 1029 1030 1031 1032 1033 1034 1035 1036
    /**
     * Callback function to classify a classname propperly. 
     *
     * @param array $matches An array of matches from a pcre_replace call
     * @return string A string with matches 1 and mathces 3 in upper case. 
     */
    public static function classifyCallback($matches)
    {
        return $matches[1] . strtoupper($matches[3]);
lsmith's avatar
lsmith committed
1037
    }
1038
    
lsmith's avatar
lsmith committed
1039 1040 1041 1042 1043 1044
    /**
     * checks for valid class name (uses camel case and underscores)
     *
     * @param string $classname
     * @return boolean
     */
lsmith's avatar
lsmith committed
1045 1046
    public static function isValidClassname($classname)
    {
zYne's avatar
zYne committed
1047
        if (preg_match('~(^[a-z])|(_[a-z])|([\W])|(_{2})~', $classname)) {
lsmith's avatar
lsmith committed
1048
            return false;
1049
        }
lsmith's avatar
lsmith committed
1050 1051 1052

        return true;
    }
1053
}