Doctrine.php 33.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
<?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
19
 * <http://www.phpdoctrine.org>.
20 21 22 23 24 25 26 27 28 29
 */

/**
 * 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
30
 * @link        www.phpdoctrine.org
31 32
 * @since       1.0
 * @version     $Revision$
33 34
 * @todo Remove all the constants, attributes to the new attribute system,
 *       All methods to separate classes.
35 36 37
 */
final class Doctrine
{
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
    /**
     * DEPRECATED ATTRIBUTE CONSTANT NAMES AND VALUES
     *
     * REMOVE BEFORE 1.0
     * These were deprecated either because they are not used anymore or because they didn't follow the naming pattern required
     * by Doctrine attributes
     *
     * Attribute names must be ATTR_{ATTR_NAME} and the values must be {ATTR_NAME}_NAME_OF_VALUE
     */
    const LIMIT_ROWS            = 1;
    const LIMIT_RECORDS         = 2;
    const FETCH_IMMEDIATE       = 0;
    const FETCH_BATCH           = 1;
    const FETCH_OFFSET          = 3;
    const FETCH_LAZY_OFFSET     = 4;
    const FETCH_VHOLDER         = 1;
    const FETCH_RECORD          = 2;
    const FETCH_ARRAY           = 3;

57 58 59
    /**
     * VERSION
     */
romanb's avatar
romanb committed
60
    const VERSION                   = '2.0.0';
61

62 63 64 65 66 67 68 69 70 71 72 73 74 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
    /**
     * 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;

    /**
     * PDO derived constants
     */
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
    const CASE_NATURAL              = 0;
    const CASE_UPPER                = 1;
    const CASE_LOWER                = 2;
    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;
    const NULL_TO_STRING            = NULL;
    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;
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174

    /**
     * ATTRIBUTE CONSTANTS
     */

    /**
     * PDO derived attributes
     */
    const ATTR_AUTOCOMMIT           = 0;
    const ATTR_PREFETCH             = 1;
    const ATTR_TIMEOUT              = 2;
    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;

    /**
     * Doctrine constants
     */
175
    const ATTR_LISTENER                 = 100;
romanb's avatar
romanb committed
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
    const ATTR_QUOTE_IDENTIFIER         = 101; // manager/session attribute
    const ATTR_FIELD_CASE               = 102; // manager/session attribute
    const ATTR_IDXNAME_FORMAT           = 103; // manager/session attribute
    const ATTR_SEQNAME_FORMAT           = 104; // manager/session attribute
    const ATTR_SEQCOL_NAME              = 105; // class attribute
    const ATTR_CMPNAME_FORMAT           = 118; // ??
    const ATTR_DBNAME_FORMAT            = 117; // manager/session attribute
    const ATTR_TBLCLASS_FORMAT          = 119; // manager/session attribute
    const ATTR_TBLNAME_FORMAT           = 120; // manager/session attribute
    const ATTR_EXPORT                   = 140; // manager/session attribute
    const ATTR_DECIMAL_PLACES           = 141; // manager/session attribute
    const ATTR_PORTABILITY              = 106; // manager/session attribute
    const ATTR_COLL_KEY                 = 108; // class attribute
    const ATTR_QUERY_LIMIT              = 109; // manager/session attribute
    const ATTR_DEFAULT_TABLE_TYPE       = 112; // manager/session attribute
    const ATTR_DEF_TEXT_LENGTH          = 113; // manager/session attribute
    const ATTR_DEF_VARCHAR_LENGTH       = 114; // manager/session attribute
    const ATTR_DEF_TABLESPACE           = 115; // manager/session attribute
    const ATTR_EMULATE_DATABASE         = 116; // manager/session attribute
    const ATTR_USE_NATIVE_ENUM          = 117; // manager/session attribute
    const ATTR_DEFAULT_SEQUENCE         = 133; // ??
197
    const ATTR_FETCHMODE                = 118; // deprecated? might use them again for associations
romanb's avatar
romanb committed
198 199 200 201 202 203
    const ATTR_NAME_PREFIX              = 121; // ??
    const ATTR_CREATE_TABLES            = 122; // manager/session attribute
    const ATTR_COLL_LIMIT               = 123; // manager/session attribute
    const ATTR_RESULT_CACHE             = 150; // manager/session attribute
    const ATTR_RESULT_CACHE_LIFESPAN    = 151; // manager/session attribute
    const ATTR_LOAD_REFERENCES          = 153; // class attribute
204
    const ATTR_RECORD_LISTENER          = 154;
romanb's avatar
romanb committed
205 206 207 208 209 210 211 212 213
    const ATTR_THROW_EXCEPTIONS         = 155; // manager/session attribute
    const ATTR_DEFAULT_PARAM_NAMESPACE  = 156; // ??
    const ATTR_QUERY_CACHE              = 157; // manager/session attribute
    const ATTR_QUERY_CACHE_LIFESPAN     = 158; // manager/session attribute
    const ATTR_MODEL_LOADING            = 161; // manager/session attribute
    const ATTR_HYDRATE                  = 163; // ??
    const ATTR_IDENTIFIER               = 164; // ??
    const ATTR_METADATA_CACHE           = 165; // manager/session attribute
    const ATTR_METADATA_CACHE_LIFESPAN  = 166; // manager/session attribute
214

215
    /**
216
     * QUERY_LIMIT CONSTANTS
217 218 219
     */

    /**
220 221
     * QUERY_LIMIT_ROWS
     *
222
     * constant for row limiting
223 224
     *
     * @see self::ATTR_QUERY_LIMIT
225
     */
226
    const QUERY_LIMIT_ROWS      = 1;
227 228 229

    /**
     * constant for record limiting
230
     * @see self::ATTR_QUERY_LIMIT
231
     */
232
    const QUERY_LIMIT_RECORDS         = 2;
233 234 235 236 237 238 239 240

    /**
     * FETCHMODE CONSTANTS
     */

    /**
     * IMMEDIATE FETCHING
     * mode for immediate fetching
241
     * @see self::ATTR_FETCHMODE
romanb's avatar
romanb committed
242
     * @deprecated???
243
     */
244
    const FETCHMODE_IMMEDIATE       = 0;
245 246

    /**
247 248
     * FETCHMODE_BATCH
     *
249
     * mode for batch fetching
250 251
     *
     * @see self::ATTR_FETCHMODE
romanb's avatar
romanb committed
252
     * @deprecated???
253
     */
254
    const FETCHMODE_BATCH           = 1;
255 256

    /**
257 258
     * FETCHMODE_OFFSET
     *
259
     * mode for offset fetching
260 261
     *
     * @see self::ATTR_FETCHMODE
romanb's avatar
romanb committed
262
     * @deprecated???
263
     */
264
    const FETCHMODE_OFFSET          = 3;
265 266

    /**
267 268
     * FETCHMODE_LAZY_OFFSET
     *
269
     * mode for lazy offset fetching
270 271
     *
     * @see self::ATTR_FETCHMODE
romanb's avatar
romanb committed
272
     * @deprecated???
273
     */
274
    const FETCHMODE_LAZY_OFFSET     = 4;
275 276

    /**
277
     * FETCHMODE CONSTANTS
278 279 280
     */

    /**
281 282 283
     * FETCHMODE_VHOLDER
     *
     * @see self::ATTR_FETCHMODE
romanb's avatar
romanb committed
284
     * @deprecated???
285
     */
286
    const FETCHMODE_VHOLDER         = 1;
287 288

    /**
289
     * FETCHMODE_RECORD
290
     *
291
     * Specifies that the fetch method shall return Doctrine_Entity
292 293 294
     * objects as the elements of the result set.
     *
     * This is the default fetchmode.
295 296
     *
     * @see self::ATTR_FETCHMODE
romanb's avatar
romanb committed
297
     * @deprecated???
298
     */
299
    const FETCHMODE_RECORD          = 2;
300 301

    /**
302 303 304
     * FETCHMODE_ARRAY
     *
     * @see self::ATTR_FETCHMODE
romanb's avatar
romanb committed
305
     * @deprecated???
306
     */
307
    const FETCHMODE_ARRAY           = 3;
308 309 310 311 312 313

    /**
     * PORTABILITY CONSTANTS
     */

    /**
314 315
     * PORTABILITY_NONE
     *
316
     * Portability: turn off all portability features.
317
     *
318 319 320 321 322
     * @see self::ATTR_PORTABILITY
     */
    const PORTABILITY_NONE          = 0;

    /**
323 324
     * PORTABILITY_FIX_CASE
     *
325 326
     * Portability: convert names of tables and fields to case defined in the
     * "field_case" option when using the query*(), fetch*() methods.
327
     *
328 329 330 331 332
     * @see self::ATTR_PORTABILITY
     */
    const PORTABILITY_FIX_CASE      = 1;

    /**
333 334
     * PORTABILITY_RTRIM
     *
335
     * Portability: right trim the data output by query*() and fetch*().
336
     *
337 338 339 340 341
     * @see self::ATTR_PORTABILITY
     */
    const PORTABILITY_RTRIM         = 2;

    /**
342 343
     * PORTABILITY_DELETE_COUNT
     *
344
     * Portability: force reporting the number of rows deleted.
345
     *
346 347 348 349 350
     * @see self::ATTR_PORTABILITY
     */
    const PORTABILITY_DELETE_COUNT  = 4;

    /**
351 352
     * PORTABILITY_EMPTY_TO_NULL
     *
353 354
     * Portability: convert empty values to null strings in data output by
     * query*() and fetch*().
355
     *
356 357 358 359 360
     * @see self::ATTR_PORTABILITY
     */
    const PORTABILITY_EMPTY_TO_NULL = 8;

    /**
361 362
     * PORTABILITY_FIX_ASSOC_FIELD_NAMES
     *
363
     * Portability: removes database/table qualifiers from associative indexes
364
     *
365 366 367 368 369
     * @see self::ATTR_PORTABILITY
     */
    const PORTABILITY_FIX_ASSOC_FIELD_NAMES = 16;

    /**
370 371
     * PORTABILITY_EXPR
     *
372
     * Portability: makes Doctrine_Expression throw exception for unportable RDBMS expressions
373
     *
374 375 376 377 378
     * @see self::ATTR_PORTABILITY
     */
    const PORTABILITY_EXPR          = 32;

    /**
379 380
     * PORTABILITY_ALL
     *
381
     * Portability: turn on all portability features.
382
     *
383 384 385 386 387
     * @see self::ATTR_PORTABILITY
     */
    const PORTABILITY_ALL           = 63;

    /**
388
     * LOCK CONSTANTS
389 390 391
     */

    /**
392 393
     * LOCK_OPTIMISTIC
     *
394
     * mode for optimistic locking
395
     * @see self::ATTR_LOCK
romanb's avatar
romanb committed
396
     * @deprecated???
397 398 399 400
     */
    const LOCK_OPTIMISTIC       = 0;

    /**
401 402
     * LOCK_PESSIMISTIC
     *
403
     * mode for pessimistic locking
404 405
     *
     * @see self::ATTR_LOCK
romanb's avatar
romanb committed
406
     * @deprecated???
407 408 409 410 411 412 413 414 415
     */
    const LOCK_PESSIMISTIC      = 1;

    /**
     * EXPORT CONSTANTS
     */

    /**
     * EXPORT_NONE
416 417
     *
     * @see self::ATTR_EXPORT
418 419 420 421 422
     */
    const EXPORT_NONE               = 0;

    /**
     * EXPORT_TABLES
423 424
     *
     * @see self::ATTR_EXPORT
425 426 427 428 429
     */
    const EXPORT_TABLES             = 1;

    /**
     * EXPORT_CONSTRAINTS
430 431
     *
     * @see self::ATTR_EXPORT
432 433 434 435 436
     */
    const EXPORT_CONSTRAINTS        = 2;

    /**
     * EXPORT_PLUGINS
437 438
     *
     * @see self::ATTR_EXPORT
439 440 441 442 443
     */
    const EXPORT_PLUGINS            = 4;

    /**
     * EXPORT_ALL
444 445
     *
     * @see self::ATTR_EXPORT
446 447 448 449
     */
    const EXPORT_ALL                = 7;

    /**
450 451 452 453 454 455 456
     * HYDRATE CONSTANTS
     */

    /**
     * HYDRATE_RECORD
     *
     * @see self::ATTR_HYDRATE
457 458 459 460 461
     */
    const HYDRATE_RECORD            = 2;

    /**
     * HYDRATE_ARRAY
462 463
     *
     * @see self::ATTR_HYDRATE
464 465
     */
    const HYDRATE_ARRAY             = 3;
466

467 468
    /**
     * HYDRATE_NONE
469 470
     *
     * @see self::ATTR_HYDRATE
471 472
     */
    const HYDRATE_NONE              = 4;
473 474
    
    /* new hydration modes. move to Query class when it's time. */
475 476 477 478 479
    const HYDRATE_IDENTITY_OBJECT = 2; // default, auto-adds PKs, produces object graphs
    const HYDRATE_IDENTITY_ARRAY = 3; // auto-adds PKs, produces array graphs
    const HYDRATE_SCALAR = 5; // produces flat result list with scalar values
    const HYDRATE_SINGLE_SCALAR = 6; // produces a single scalar value
    //const HYDRATE_NONE = 4; // produces a result set as it's returned by the db
480
    
481 482

    /**
483 484 485
     * VALIDATE CONSTANTS
     *
     * @see self::ATTR_VALIDATE
486 487 488 489 490
     */
    const VALIDATE_NONE             = 0;

    /**
     * VALIDATE_LENGTHS
491 492
     *
     * @see self::ATTR_VALIDATE
493 494 495 496 497
     */
    const VALIDATE_LENGTHS          = 1;

    /**
     * VALIDATE_TYPES
498 499
     *
     * @see self::ATTR_VALIDATE
500 501 502 503 504
     */
    const VALIDATE_TYPES            = 2;

    /**
     * VALIDATE_CONSTRAINTS
505 506
     *
     * @see self::ATTR_VALIDATE
romanb's avatar
romanb committed
507
     * Not used? Purpose?
508 509 510 511 512
     */
    const VALIDATE_CONSTRAINTS      = 4;

    /**
     * VALIDATE_ALL
513 514
     *
     * @see self::ATTR_VALIDATE
515 516 517 518 519 520 521
     */
    const VALIDATE_ALL              = 7;

    /**
     * IDENTIFIER_AUTOINC
     *
     * constant for auto_increment identifier
522 523
     *
     * @see self::ATTR_IDENTIFIER
524 525 526 527 528 529 530
     */
    const IDENTIFIER_AUTOINC        = 1;

    /**
     * IDENTIFIER_SEQUENCE
     *
     * constant for sequence identifier
531 532
     *
     * @see self::ATTR_IDENTIFIER
533 534 535 536 537 538 539
     */
    const IDENTIFIER_SEQUENCE       = 2;

    /**
     * IDENTIFIER_NATURAL
     *
     * constant for normal identifier
540 541
     *
     * @see self::ATTR_IDENTIFIER
542 543 544 545 546 547 548
     */
    const IDENTIFIER_NATURAL        = 3;

    /**
     * IDENTIFIER_COMPOSITE
     *
     * constant for composite identifier
549
     * @see self::ATTR_IDENTIFIER
550 551 552
     */
    const IDENTIFIER_COMPOSITE      = 4;

553
    /**
Jonathan.Wage's avatar
Jonathan.Wage committed
554
     * MODEL_LOADING_AGGRESSIVE
555 556 557
     *
     * Constant for agressive model loading
     * Will require_once() all found model files
558 559
     *
     * @see self::ATTR_MODEL_LOADING
560
     */
Jonathan.Wage's avatar
Jonathan.Wage committed
561
    const MODEL_LOADING_AGGRESSIVE   = 1;
562 563 564 565 566 567 568

    /**
     * MODEL_LOADING_CONSERVATIVE
     *
     * Constant for conservative model loading
     * Will not require_once() found model files inititally instead it will build an array
     * and reference it in autoload() when a class is needed it will require_once() it
569 570
     *
     * @see self::ATTR_MODEL_LOADING
571
     */
romanb's avatar
romanb committed
572
    const MODEL_LOADING_CONSERVATIVE = 2;
573
    
574
    /**
575 576
     * INHERITANCE TYPE CONSTANTS.
     */
romanb's avatar
romanb committed
577 578
    const INHERITANCE_TYPE_NONE = 0;
    
579 580
    /**
     * Constant for Single Table Inheritance.
581
     *
582 583
     * @see http://martinfowler.com/eaaCatalog/singleTableInheritance.html
    */
romanb's avatar
romanb committed
584
    const INHERITANCE_TYPE_SINGLE_TABLE = 1;
585 586 587 588 589
         
    /**
     * Constant for Class Table Inheritance.
     *
     * @see http://martinfowler.com/eaaCatalog/classTableInheritance.html
590
     */
romanb's avatar
romanb committed
591
    const INHERITANCE_TYPE_JOINED = 2;
592
     
593
    /**
594
     * Constant for Concrete Table Inheritance.
595
     *
596 597
     * @see http://martinfowler.com/eaaCatalog/concreteTableInheritance.html
     */
romanb's avatar
romanb committed
598
    const INHERITANCE_TYPE_TABLE_PER_CLASS = 3;
romanb's avatar
romanb committed
599

600 601 602

    /**
     * Path
603
     *
604
     * @var string $path            doctrine root directory
605
     */
606
    private static $_path;
607

608
    /**
609
     * _loadedModelFiles
610
     *
611 612 613 614
     * Array of all the loaded models and the path to each one for autoloading
     *
     * @var array
     */
615
    private static $_loadedModelFiles = array();
616

617 618
    private static $_pathModels = array();

619 620 621 622 623 624 625 626 627 628
    /**
     * __construct
     *
     * @return void
     * @throws Doctrine_Exception
     */
    public function __construct()
    {
        throw new Doctrine_Exception('Doctrine is static class. No instances can be created.');
    }
629 630 631 632 633

    public static function getLoadedModelFiles()
    {
        return self::$_loadedModelFiles;
    }
634
    
635 636 637 638 639
    public static function getPathModels()
    {
        return self::$_pathModels;
    }

640 641 642 643 644 645 646 647 648 649 650
    /**
     * getPath
     * returns the doctrine root
     *
     * @return string
     */
    public static function getPath()
    {
        if ( ! self::$_path) {
            self::$_path = dirname(__FILE__);
        }
651

652 653 654 655 656 657 658
        return self::$_path;
    }

    /**
     * loadModels
     *
     * Recursively load all models from a directory or array of directories
659 660
     *
     * @param string $directory    Path to directory of models or array of directory paths
661 662
     * @return array $loadedModels
     */
663
    public static function loadModels($directory)
664
    {
665 666
        $loadedModels = array();
        
667 668
        if ($directory !== null) {
            $manager = Doctrine_Manager::getInstance();
669
            
670 671 672 673 674 675
            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) {
676
                        
677
                        if ($manager->getAttribute(Doctrine::ATTR_MODEL_LOADING) === Doctrine::MODEL_LOADING_CONSERVATIVE) {
678
                            self::$_loadedModelFiles[$e[0]] = $file->getPathName();
679 680
                            self::$_pathModels[$file->getPathName()][$e[0]] = $e[0];

681 682 683 684 685 686 687 688 689 690 691 692
                            $loadedModels[] = $e[0];
                        } else {
                            $declaredBefore = get_declared_classes();
                            require_once($file->getPathName());
                            
                            $declaredAfter = get_declared_classes();
                            // Using array_slice because array_diff is broken is some PHP versions
                            $foundClasses = array_slice($declaredAfter, count($declaredBefore) - 1);
                            if ($foundClasses) {
                                foreach ($foundClasses as $className) {
                                    if (self::isValidModelClass($className) && !in_array($className, $loadedModels)) {
                                        $loadedModels[] = $className;
693 694

                                        self::$_pathModels[$file->getPathName()][$className] = $className;
695 696 697
                                    }
                                }
                            }
698
                        }
699 700 701 702 703
                    }
                }
            }
        }

704 705 706 707 708 709 710 711
        // We do not want to filter invalid models when using conservative model loading
        // The filtering requires that the class be loaded and inflected in order to determine if it is 
        // a valid class.
        if ($manager->getAttribute(Doctrine::ATTR_MODEL_LOADING) == Doctrine::MODEL_LOADING_CONSERVATIVE) {
            return $loadedModels;
        } else {
            return self::filterInvalidModels($loadedModels);
        }
712 713 714 715 716 717
    }

    /**
     * getLoadedModels
     *
     * Get all the loaded models, you can provide an array of classes or it will use get_declared_classes()
718
     *
719 720
     * Will filter through an array of classes and return the Doctrine_Entitys out of them.
     * If you do not specify $classes it will return all of the currently loaded Doctrine_Entitys
721
     *
722
     * @return array   $loadedModels
723
     */
724
    public static function getLoadedModels()
725
    {
726 727
        $classes = get_declared_classes();
        $classes = array_merge($classes, array_keys(self::$_loadedModelFiles));
728

729 730 731 732 733 734 735
        return self::filterInvalidModels($classes);
    }

    /**
     * filterInvalidModels
     *
     * Filter through an array of classes and return all the classes that are valid models
736
     * This will inflect the class, causing it to be loaded in to memory.
737 738 739 740 741 742 743
     *
     * @param classes  Array of classes to filter through, otherwise uses get_declared_classes()
     * @return array   $loadedModels
     */
    public static function filterInvalidModels($classes)
    {
        $validModels = array();
744

745
        foreach ((array) $classes as $name) {
746 747
            if (self::isValidModelClass($name) && !in_array($name, $validModels)) {
                $validModels[] = $name;
748 749 750
            }
        }

751 752
        return $validModels;
    }
753 754 755 756

    /**
     * isValidModelClass
     *
757
     * Checks if what is passed is a valid Doctrine_Entity
758
     * Will load class in to memory in order to inflect it and find out information about the class
759
     *
760 761
     * @param   mixed   $class Can be a string named after the class, an instance of the class, or an instance of the class reflected
     * @return  boolean
762 763 764
     */
    public static function isValidModelClass($class)
    {
765
        if ($class instanceof Doctrine_Entity) {
766 767 768 769 770 771 772
            $class = get_class($class);
        }

        if (is_string($class) && class_exists($class)) {
            $class = new ReflectionClass($class);
        }

773
        if ($class instanceof ReflectionClass) {
774 775
            // Skip the following classes
            // - abstract classes
776
            // - not a subclass of Doctrine_Entity
777
            // - don't have a setTableDefinition method
778
            if (!$class->isAbstract() &&
779
                $class->isSubClassOf('Doctrine_Entity')) {
780

781
                return true;
782 783
            }
        }
784

785
        return false;
786 787 788 789 790 791
    }

    /**
     * getConnectionByTableName
     *
     * Get the connection object for a table by the actual table name
792 793
     *
     * @param string $tableName
794 795 796 797 798
     * @return object Doctrine_Connection
     */
    public static function getConnectionByTableName($tableName)
    {
        $loadedModels = self::getLoadedModels();
799

800 801 802
        foreach ($loadedModels as $name) {
            $model = new $name();
            $table = $model->getTable();
803

804
            if ($table->getTableName() == $tableName) {
805
               return $table->getConnection();
806 807
            }
        }
808

809 810 811 812 813 814
        return Doctrine_Manager::connection();
    }

    /**
     * generateModelsFromDb
     *
815
     * method for importing existing schema to Doctrine_Entity classes
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
     *
     * @param string $directory Directory to write your models to
     * @param array $databases Array of databases to generate models for
     * @return boolean
     * @throws Exception
     */
    public static function generateModelsFromDb($directory, array $databases = array())
    {
        return Doctrine_Manager::connection()->import->importSchema($directory, $databases);
    }

    /**
     * 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)
    {
838
        $directory = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'tmp_doctrine_models';
839 840 841 842

        Doctrine::generateModelsFromDb($directory);

        $export = new Doctrine_Export_Schema();
843

844
        $result = $export->exportSchema($yamlPath, 'yml', $directory);
845

846
        Doctrine_Lib::removeDirectories($directory);
847

848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
        return $result;
    }

    /**
     * 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
     * @param array  $options Array of options to pass to the schema importer
     * @return void
     */
    public static function generateModelsFromYaml($yamlPath, $directory, $options = array())
    {
        $import = new Doctrine_Import_Schema();
        $import->setOptions($options);
865

866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897
        return $import->importSchema($yamlPath, 'yml', $directory);
    }

    /**
     * createTablesFromModels
     *
     * Creates database tables for the models in the specified directory
     *
     * @param string $directory Directory containing your models
     * @return void
     */
    public static function createTablesFromModels($directory = null)
    {
        return Doctrine_Manager::connection()->export->exportSchema($directory);
    }

    /**
     * createTablesFromArray
     *
     * Creates database tables for the models in the supplied array
     *
     * @param array $array An array of models to be exported
     * @return void
     */
    public static function createTablesFromArray($array)
    {
        return Doctrine_Manager::connection()->export->exportClasses($array);
    }

    /**
     * generateSqlFromModels
     *
898
     * @param string $directory
899 900 901 902 903
     * @return string $build  String of sql queries. One query per line
     */
    public static function generateSqlFromModels($directory = null)
    {
        $sql = Doctrine_Manager::connection()->export->exportSql($directory);
904

905 906 907 908
        $build = '';
        foreach ($sql as $query) {
            $build .= $query.";\n";
        }
909

910 911 912 913 914 915 916 917 918 919 920 921 922 923 924
        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();
925

926 927 928 929 930 931 932 933 934 935 936 937 938
        return $export->exportSchema($yamlPath, 'yml', $directory);
    }

    /**
     * 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 = array())
    {
939
        return Doctrine_Manager::getInstance()->createDatabases($specifiedConnections);
940 941 942 943 944 945 946 947 948 949 950 951
    }

    /**
     * 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())
    {
952
        return Doctrine_Manager::getInstance()->dropDatabases($specifiedConnections);
953 954 955 956 957 958 959 960 961 962 963 964 965 966
    }

    /**
     * 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();
967

968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983
        return $data->exportData($yamlPath, 'yml', array(), $individualFiles);
    }

    /**
     * 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();
984

985 986 987
        if ( ! $append) {
            $data->purge();
        }
988

989 990 991 992 993
        return $data->importData($yamlPath, 'yml');
    }

    /**
     * migrate
994
     *
995 996 997 998 999 1000 1001 1002 1003 1004
     * Migrate database to specified $to version. Migrates from current to latest if you do not specify.
     *
     * @param string $migrationsPath Path to migrations directory which contains your migration classes
     * @param string $to Version you wish to migrate to.
     * @return bool true
     * @throws new Doctrine_Migration_Exception
     */
    public static function migrate($migrationsPath, $to = null)
    {
        $migration = new Doctrine_Migration($migrationsPath);
1005

1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
        return $migration->migrate($to);
    }

    /**
     * generateMigrationClass
     *
     * Generate new migration class skeleton
     *
     * @param string $className Name of the Migration class to generate
     * @param string $migrationsPath Path to directory which contains your migration classes
     */
    public static function generateMigrationClass($className, $migrationsPath)
    {
1019
        $builder = new Doctrine_Builder_Migration($migrationsPath);
1020

1021 1022 1023 1024 1025 1026
        return $builder->generateMigrationClass($className);
    }

    /**
     * generateMigrationsFromDb
     *
1027
     * @param string $migrationsPath
1028 1029 1030 1031 1032
     * @return void
     * @throws new Doctrine_Migration_Exception
     */
    public static function generateMigrationsFromDb($migrationsPath)
    {
1033
        $builder = new Doctrine_Builder_Migration($migrationsPath);
1034

1035 1036 1037 1038 1039 1040
        return $builder->generateMigrationsFromDb();
    }

    /**
     * generateMigrationsFromModels
     *
1041 1042
     * @param string $migrationsPath
     * @param string $modelsPath
1043 1044 1045 1046
     * @return void
     */
    public static function generateMigrationsFromModels($migrationsPath, $modelsPath = null)
    {
1047
        $builder = new Doctrine_Builder_Migration($migrationsPath);
1048

1049 1050 1051 1052 1053 1054
        return $builder->generateMigrationsFromModels($modelsPath);
    }

    /**
     * getTable
     *
1055
     * @param string $tableName
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
     * @return void
     */
    public static function getTable($tableName)
    {
        return Doctrine_Manager::table($tableName);
    }

    /**
     * autoload
     *
     * simple autoload function
     * returns true if the class was loaded, otherwise false
     *
     * @param string $classname
     * @return boolean
     */
    public static function autoload($className)
    {
1074
        if (class_exists($className, false) || interface_exists($className, false)) {
1075 1076
            return false;
        }
1077

1078 1079 1080
        if ( ! self::$_path) {
            self::$_path = dirname(__FILE__);
        }
1081

1082
        $class = self::$_path . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
1083
        
1084
        if (file_exists($class)) {
romanb's avatar
romanb committed
1085
            require $class;
1086

1087 1088
            return true;
        }
1089

romanb's avatar
romanb committed
1090 1091 1092
        /* TODO: Move the following code out of here. A generic Doctrine_Autoloader
           class that can be configured in various ways might be a good idea.
           Same goes for locate().*/
1093
        $loadedModels = self::$_loadedModelFiles;
1094

1095
        if (isset($loadedModels[$className]) && file_exists($loadedModels[$className])) {
romanb's avatar
romanb committed
1096
            require_once $loadedModels[$className];
1097

1098 1099 1100 1101 1102
            return true;
        }

        return false;
    }
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
    
    public static function locate($name)
    {
        $findPattern = self::$_path . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, str_replace('Doctrine_', '', $name));

        $matches = glob($findPattern);

        if ( isset($matches[0])) {
            return $matches[0];
        } else {
            return false;
        }
    }
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134

    /**
     * dump
     *
     * dumps a given variable
     *
     * @param mixed $var        a variable of any type
     * @param boolean $output   whether to output the content
     * @param string $indent    indention string
     * @return void|string
     */
    public static function dump($var, $output = true, $indent = "")
    {
        $ret = array();
        switch (gettype($var)) {
            case 'array':
                $ret[] = 'Array(';
                $indent .= "    ";
                foreach ($var as $k => $v) {
1135

1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
                    $ret[] = $indent . $k . ' : ' . self::dump($v, false, $indent);
                }
                $indent = substr($indent,0, -4);
                $ret[] = $indent . ")";
                break;
            case 'object':
                $ret[] = 'Object(' . get_class($var) . ')';
                break;
            default:
                $ret[] = var_export($var, true);
        }
1147

1148 1149 1150
        if ($output) {
            print implode("\n", $ret);
        }
1151

1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162
        return implode("\n", $ret);
    }

    /**
     * tableize
     *
     * returns table name from class name
     *
     * @param string $classname
     * @return string
     */
1163
    public static function tableize($className)
1164
    {
1165
         return Doctrine_Inflector::tableize($className);
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
    }

    /**
     * classify
     *
     * returns class name from table name
     *
     * @param string $tablename
     * @return string
     */
Jonathan.Wage's avatar
Jonathan.Wage committed
1176
    public static function classify($tableName)
1177
    {
1178
        return Doctrine_Inflector::classify($tableName);
1179
    }
1180
}