Doctrine.php 26.8 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;
lsmith's avatar
lsmith committed
118 119 120
    /**
     * ATTRIBUTE CONSTANTS
     */
121

122 123 124 125 126
    /**
     * PDO derived attributes
     */
    const ATTR_AUTOCOMMIT           = 0;
    const ATTR_PREFETCH             = 1;
127
    const ATTR_TIMEOUT              = 2;
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
    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
144

145 146 147 148 149 150 151 152
    /**
     * 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
153
    const ATTR_SEQCOL_NAME          = 105;
154 155 156
    const ATTR_CMPNAME_FORMAT       = 118;
    const ATTR_DBNAME_FORMAT        = 117;
    const ATTR_TBLCLASS_FORMAT      = 119;
zYne's avatar
zYne committed
157
    const ATTR_EXPORT               = 140;
158
    const ATTR_DECIMAL_PLACES       = 141;
159

160
    const ATTR_PORTABILITY          = 106;
161
    const ATTR_VALIDATE             = 107;
162 163 164 165 166 167 168
    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;
169
    const ATTR_USE_NATIVE_ENUM      = 117;
zYne's avatar
zYne committed
170
    const ATTR_DEFAULT_SEQUENCE     = 133;
lsmith's avatar
lsmith committed
171

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

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

lsmith's avatar
lsmith committed
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233

    /**
     * LIMIT CONSTANTS
     */

    /**
     * constant for row limiting
     */
    const LIMIT_ROWS       = 1;
    /**
     * constant for record limiting
     */
    const LIMIT_RECORDS    = 2;

    /**
     * FETCHMODE CONSTANTS
     */

    /**
     * IMMEDIATE FETCHING
     * mode for immediate fetching
     */
    const FETCH_IMMEDIATE       = 0;
    /**
     * BATCH FETCHING
     * mode for batch fetching
     */
    const FETCH_BATCH           = 1;
    /**
     * LAZY FETCHING
     * mode for offset fetching
     */
    const FETCH_OFFSET          = 3;
    /**
     * LAZY OFFSET FETCHING
     * mode for lazy offset fetching
     */
    const FETCH_LAZY_OFFSET     = 4;

    /**
     * FETCH CONSTANTS
     */


    /**
     * FETCH VALUEHOLDER
     */
    const FETCH_VHOLDER         = 1;
    /**
     * FETCH RECORD
     *
lsmith's avatar
lsmith committed
234
     * Specifies that the fetch method shall return Doctrine_Record
lsmith's avatar
lsmith committed
235 236 237 238 239 240
     * objects as the elements of the result set.
     *
     * This is the default fetchmode.
     */
    const FETCH_RECORD          = 2;
    /**
lsmith's avatar
lsmith committed
241
     * FETCH ARRAY
lsmith's avatar
lsmith committed
242 243 244 245 246 247 248 249 250 251 252
     */

    const FETCH_ARRAY           = 3;
    /**
     * PORTABILITY CONSTANTS
     */

    /**
     * Portability: turn off all portability features.
     * @see Doctrine::ATTR_PORTABILITY
     */
zYne's avatar
zYne committed
253
    const PORTABILITY_NONE          = 0;
lsmith's avatar
lsmith committed
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
    /**
     * Portability: convert names of tables and fields to case defined in the
     * "field_case" option when using the query*(), fetch*() methods.
     * @see Doctrine::ATTR_PORTABILITY
     */
    const PORTABILITY_FIX_CASE      = 1;

    /**
     * Portability: right trim the data output by query*() and fetch*().
     * @see Doctrine::ATTR_PORTABILITY
     */
    const PORTABILITY_RTRIM         = 2;
    /**
     * Portability: force reporting the number of rows deleted.
     * @see Doctrine::ATTR_PORTABILITY
     */
    const PORTABILITY_DELETE_COUNT  = 4;
    /**
     * Portability: convert empty values to null strings in data output by
     * query*() and fetch*().
     * @see Doctrine::ATTR_PORTABILITY
     */
    const PORTABILITY_EMPTY_TO_NULL = 8;
    /**
     * Portability: removes database/table qualifiers from associative indexes
     * @see Doctrine::ATTR_PORTABILITY
     */
    const PORTABILITY_FIX_ASSOC_FIELD_NAMES = 16;
zYne's avatar
zYne committed
282 283 284 285 286
    /**
     * Portability: makes Doctrine_Expression throw exception for unportable RDBMS expressions
     * @see Doctrine::ATTR_PORTABILITY
     */
    const PORTABILITY_EXPR          = 32;
lsmith's avatar
lsmith committed
287 288 289 290
    /**
     * Portability: turn on all portability features.
     * @see Doctrine::ATTR_PORTABILITY
     */
zYne's avatar
zYne committed
291
    const PORTABILITY_ALL           = 63;
lsmith's avatar
lsmith committed
292 293 294 295 296 297 298 299 300 301 302 303 304

    /**
     * LOCKMODE CONSTANTS
     */

    /**
     * mode for optimistic locking
     */
    const LOCK_OPTIMISTIC       = 0;
    /**
     * mode for pessimistic locking
     */
    const LOCK_PESSIMISTIC      = 1;
zYne's avatar
zYne committed
305 306 307
    /**
     * EXPORT CONSTANTS
     */
308

zYne's avatar
zYne committed
309 310 311 312 313
    /**
     * turns of exporting
     */
    const EXPORT_NONE               = 0;
    /**
zYne's avatar
zYne committed
314
     * export tables
zYne's avatar
zYne committed
315
     */
zYne's avatar
zYne committed
316
    const EXPORT_TABLES             = 1;
zYne's avatar
zYne committed
317
    /**
zYne's avatar
zYne committed
318
     * export constraints
zYne's avatar
zYne committed
319
     */
zYne's avatar
zYne committed
320
    const EXPORT_CONSTRAINTS        = 2;
zYne's avatar
zYne committed
321 322 323 324
    /**
     * export plugins
     */
    const EXPORT_PLUGINS            = 4;
zYne's avatar
zYne committed
325 326 327
    /**
     * export all
     */
zYne's avatar
zYne committed
328
    const EXPORT_ALL                = 7;
zYne's avatar
zYne committed
329
    
zYne's avatar
zYne committed
330 331 332 333 334 335
    /**
     * HYDRATION CONSTANTS
     */
    const HYDRATE_RECORD            = 2;
    
    const HYDRATE_ARRAY             = 3;
zYne's avatar
zYne committed
336

zYne's avatar
zYne committed
337 338 339 340 341 342 343 344 345 346 347 348
    /**
     * VALIDATION CONSTANTS
     */
    const VALIDATE_NONE             = 0;

    const VALIDATE_LENGTHS          = 1;
    
    const VALIDATE_TYPES            = 2;
    
    const VALIDATE_CONSTRAINTS      = 4;
    
    const VALIDATE_ALL              = 5;
zYne's avatar
zYne committed
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365

    /**
     * constant for auto_increment identifier
     */
    const IDENTIFIER_AUTOINC        = 1;
    /**
     * constant for sequence identifier
     */
    const IDENTIFIER_SEQUENCE       = 2;
    /**
     * constant for normal identifier
     */
    const IDENTIFIER_NATURAL        = 3;
    /**
     * constant for composite identifier
     */
    const IDENTIFIER_COMPOSITE      = 4;
lsmith's avatar
lsmith committed
366 367 368
    /**
     * constructor
     */
lsmith's avatar
lsmith committed
369 370
    public function __construct()
    {
lsmith's avatar
lsmith committed
371 372 373 374 375
        throw new Doctrine_Exception('Doctrine is static class. No instances can be created.');
    }
    /**
     * @var string $path            doctrine root directory
     */
376
    private static $_path;
zYne's avatar
zYne committed
377 378 379 380 381 382 383 384 385 386 387 388
    /**
     * @var boolean $_debug
     */
    private static $_debug = false;

    public static function debug($bool = null)
    {
        if ($bool !== null) {
            self::$_debug = (bool) $bool;
        }
        return self::$_debug;
    }
lsmith's avatar
lsmith committed
389 390 391 392 393 394
    /**
     * getPath
     * returns the doctrine root
     *
     * @return string
     */
lsmith's avatar
lsmith committed
395 396
    public static function getPath()
    {
397 398
        if ( ! self::$_path) {
            self::$_path = dirname(__FILE__);
lsmith's avatar
lsmith committed
399
        }
400
        return self::$_path;
lsmith's avatar
lsmith committed
401 402 403 404 405 406 407
    }
    /**
     * loadAll
     * loads all runtime classes
     *
     * @return void
     */
lsmith's avatar
lsmith committed
408 409
    public static function loadAll()
    {
lsmith's avatar
lsmith committed
410 411 412 413 414 415
        $classes = Doctrine_Compiler::getRuntimeClasses();

        foreach ($classes as $class) {
            Doctrine::autoload($class);
        }
    }
Jonathan.Wage's avatar
Jonathan.Wage committed
416 417 418 419 420 421 422 423 424 425
    /**
     * 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
     * @return void
     */
    public static function loadModels($directory)
    {
426
        $declared = get_declared_classes();
427
        
Jonathan.Wage's avatar
Jonathan.Wage committed
428 429 430 431 432 433 434 435 436 437 438 439 440
        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();
                    }
                }
            }
            
441
            $declared = array_diff(get_declared_classes(), $declared);
Jonathan.Wage's avatar
Jonathan.Wage committed
442 443 444 445 446 447 448
        }
        
        return self::getLoadedModels($declared);
    }
    /**
     * getLoadedModels
     *
449 450
     * Get all the loaded models, you can provide an array of classes or it will use get_declared_classes()
     * 
Jonathan.Wage's avatar
Jonathan.Wage committed
451 452
     * @param $classes Array of classes to filter through, otherwise uses get_declared_classes()
     * @return void
Jonathan.Wage's avatar
Jonathan.Wage committed
453 454 455 456 457 458 459 460
     */
    public static function getLoadedModels($classes = null)
    {
        if ($classes === null) {
            $classes = get_declared_classes();
        }
        
        $parent = new ReflectionClass('Doctrine_Record');
461
        
Jonathan.Wage's avatar
Jonathan.Wage committed
462 463 464 465 466 467 468
        $loadedModels = array();
        
        // we iterate trhough the diff of previously declared classes
        // and currently declared classes
        foreach ($classes as $name) {
            $class = new ReflectionClass($name);
            
469 470 471 472 473 474 475
            // 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')) {
Jonathan.Wage's avatar
Jonathan.Wage committed
476 477 478 479 480 481 482 483
                continue;
            }
            
            $loadedModels[] = $name;
        }
        
        return $loadedModels;
    }
484 485 486 487 488 489 490 491 492
    /**
     * getConnectionByTableName
     *
     * Get the connection object for a table by the actual table name
     * 
     * @param string $tableName 
     * @return void
     */
    public static function getConnectionByTableName($tableName)
Jonathan.Wage's avatar
Jonathan.Wage committed
493
    {
494
        $loadedModels = self::getLoadedModels();
Jonathan.Wage's avatar
Jonathan.Wage committed
495
        
496
        foreach ($loadedModels as $name) {
497
            $model = new $name();
Jonathan.Wage's avatar
Jonathan.Wage committed
498 499 500 501 502 503 504
            $table = $model->getTable();
            
            if ($table->getTableName() == $tableName) {
               return $table->getConnection(); 
            }
        }
    }
lsmith's avatar
lsmith committed
505
    /**
506
     * importSchema
lsmith's avatar
lsmith committed
507 508
     * method for importing existing schema to Doctrine_Record classes
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
509 510
     * @param string $directory Directory to write your models to
     * @param array $databases Array of databases to generate models for
zYne's avatar
zYne committed
511
     * @return boolean
lsmith's avatar
lsmith committed
512
     */
513
    public static function importSchema($directory, array $databases = array())
lsmith's avatar
lsmith committed
514
    {
515
        return Doctrine_Manager::connection()->import->importSchema($directory, $databases);
lsmith's avatar
lsmith committed
516
    }
517 518 519 520 521
    /**
     * generateModelsFromDb
     *
     * Generate your model definitions from an existing database
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
522 523
     * @param string $directory Directory to write your models to
     * @param string $databases Array of databases to generate models for
524 525 526 527 528 529 530 531 532 533 534 535
     * @return void
     */
    public static function generateModelsFromDb($directory, array $databases = array())
    {
        return self::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.
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
536
     * @param string $yamlPath Path to write oyur yaml schema file to
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
     * @return void
     */
    public static function generateYamlFromDb($yamlPath)
    {
        $directory = '/tmp/tmp_doctrine_models';

        Doctrine::generateModelsFromDb($directory);

        $export = new Doctrine_Export_Schema();
        
        return $export->exportSchema($yamlPath, 'yml', $directory);
    }
    /**
     * generateModelsFromYaml
     *
     * Generate a yaml schema file from an existing directory of models
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
554 555
     * @param string $yamlPath Path to your yaml schema files
     * @param string $directory Directory to generate your models in
556 557 558 559 560 561 562 563
     * @return void
     */
    public static function generateModelsFromYaml($yamlPath, $directory)
    {
        $import = new Doctrine_Import_Schema();
        
        return $import->importSchema($yamlPath, 'yml', $directory);
    }
lsmith's avatar
lsmith committed
564
    /**
565
     * exportSchema
lsmith's avatar
lsmith committed
566 567
     * method for exporting Doctrine_Record classes to a schema
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
568 569
     * @param string $directory Directory containing your models
     * @return void
lsmith's avatar
lsmith committed
570
     */
571
    public static function exportSchema($directory = null)
lsmith's avatar
lsmith committed
572
    {
573
        return Doctrine_Manager::connection()->export->exportSchema($directory);
zYne's avatar
zYne committed
574
    }
575 576 577 578 579
    /**
     * createTablesFromModels
     *
     * Creates database tables for the models in the specified directory
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
580
     * @param string $directory Directory containing your models
581 582 583 584 585 586 587 588 589 590 591
     * @return void
     */
    public static function createTablesFromModels($directory = null)
    {
        return self::exportSchema($directory);
    }
    /**
     * generateYamlFromModels
     *
     * Generate yaml schema file for the models in the specified directory
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
592 593
     * @param string $yamlPath Path to your yaml schema files
     * @param string $directory Directory to generate your models in
594 595 596 597 598 599 600 601 602 603 604 605 606
     * @return void
     */
    public static function generateYamlFromModels($yamlPath, $directory)
    {
        $export = new Doctrine_Export_Schema();
        
        return $export->exportSchema($yamlPath, 'yml', $directory);
    }
    /**
     * createDatabases
     *
     * Creates databases for connections
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
607
     * @param string $specifiedConnections Array of connections you wish to create the database for
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
     * @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);
        }
    }
    /**
     * dropDatabases
     *
     * Drops databases for connections
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
631
     * @param string $specifiedConnections Array of connections you wish to drop the database for
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
     * @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);
        }
    }
    /**
     * dumpData
     *
     * Dump data to a yaml fixtures file
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
655 656
     * @param string $yamlPath Path to write the yaml data fixtures to
     * @param string $individualFiles Whether or not to dump data to individual fixtures files
657 658 659 660 661 662 663 664 665 666 667 668 669 670
     * @return void
     */
    public static function dumpData($yamlPath, $individualFiles = false)
    {
        $data = new Doctrine_Data();
        
        return $data->exportData($yamlPath, 'yml', array(), $individualFiles);
    }
    /**
     * loadData
     *
     * Load data from a yaml fixtures file.
     * The output of dumpData can be fed to loadData
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
671 672
     * @param string $yamlPath Path to your yaml data fixtures
     * @param string $append Whether or not to append the data
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
     * @return void
     */
    public static function loadData($yamlPath, $append = false)
    {
        $delete = isset($append) ? ($append ? false : true) : true;

        if ($delete)
        {
          $models = Doctrine::getLoadedModels();

          foreach ($models as $model)
          {
            $model = new $model();

            $model->getTable()->createQuery()->delete($model)->execute();
          }
        }

        $data = new Doctrine_Data();
        
        return $data->importData($yamlPath, 'yml');
    }
    /**
     * loadDummyData
     *
     * Populdate your models with dummy data
     *
Jonathan.Wage's avatar
Jonathan.Wage committed
700 701
     * @param string $append Whether or not to append the data
     * @param string $num Number of records to populate
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723
     * @return void
     */
    public static function loadDummyData($append, $num = 5)
    {
        $delete = isset($append) ? ($append ? false : true) : true;

        if ($delete)
        {
          $models = Doctrine::getLoadedModels();

          foreach ($models as $model)
          {
            $model = new $model();

            $model->getTable()->createQuery()->delete($model)->execute();
          }
        }
        
        $data = new Doctrine_Data();
        
        return $data->importDummyData($num);
    }
Jonathan.Wage's avatar
Jonathan.Wage committed
724 725 726 727 728 729 730 731 732
    /**
     * migrate
     * 
     * Migrate database to specified $to version. Migrates from current to latest if you do not specify.
     *
     * @param string $directory Directory which contains your migration classes
     * @param string $to Version you wish to migrate to.
     * @return void
     */
733 734 735 736 737 738
    public static function migrate($directory, $to = null)
    {
        $migration = new Doctrine_Migration($directory);
        
        return $migration->migrate($to);
    }
Jonathan.Wage's avatar
Jonathan.Wage committed
739 740 741 742 743 744 745 746 747
    /**
     * generateMigrationClass
     *
     * Generate new migration class skeleton
     *
     * @param string $className Name of the Migration class to generate
     * @param string $directory Directory which contains your migration classes
     * @package default
     */
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
    public static function generateMigrationClass($className, $directory)
    {
        $migration = new Doctrine_Migration($directory);
        $next = (string) $migration->getNextVersion();
        
        $fileName = str_repeat('0', (3 - strlen($next))) . $next . '_' . Doctrine::tableize($className) . '.class.php';
        $path = $directory . DIRECTORY_SEPARATOR . $fileName;
        
        $code  = '<?php' . PHP_EOL;
        $code .= "// Automatically generated by Doctrine\n";
        $code .= "class " . $className . " extends Doctrine_Migration\n";
        $code .= "{\n";
        $code .= "\tpublic function up()\n\t{ }\n\n";
        $code .= "\tpublic function down()\n\t{ }\n";
        $code .= "}";
        
        file_put_contents($path, $code);
    }
    
zYne's avatar
zYne committed
767 768 769 770 771 772
    /**
     * exportSql
     * method for exporting Doctrine_Record classes to a schema
     *
     * @param string $directory
     */
zYne's avatar
zYne committed
773
    public static function exportSql($directory = null)
zYne's avatar
zYne committed
774 775
    {
        return Doctrine_Manager::connection()->export->exportSql($directory);
lsmith's avatar
lsmith committed
776
    }
777 778 779 780
    public static function generateSqlFromModels($directory)
    {
        return self::exportSql($directory);
    }
lsmith's avatar
lsmith committed
781 782 783 784 785 786
    /**
     * 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
     *
787 788
     * @param string $target
     *
lsmith's avatar
lsmith committed
789 790 791
     * @throws Doctrine_Exception
     * @return void
     */
792
    public static function compile($target = null)
lsmith's avatar
lsmith committed
793
    {
794
        Doctrine_Compiler::compile($target);
lsmith's avatar
lsmith committed
795 796 797 798 799 800 801 802
    }
    /**
     * simple autoload function
     * returns true if the class was loaded, otherwise false
     *
     * @param string $classname
     * @return boolean
     */
lsmith's avatar
lsmith committed
803
    public static function autoload($classname)
804
    {
zYne's avatar
zYne committed
805
        if (class_exists($classname, false)) {
lsmith's avatar
lsmith committed
806 807
            return false;
        }
808 809
        if ( ! self::$_path) {
            self::$_path = dirname(__FILE__);
lsmith's avatar
lsmith committed
810
        }
811
        $class = self::$_path . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR,$classname) . '.php';
lsmith's avatar
lsmith committed
812 813 814 815 816 817 818 819 820

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

        require_once($class);

        return true;
    }
zYne's avatar
zYne committed
821 822 823 824 825 826
    /**
     * dump
     *
     * dumps a given variable
     *
     * @param mixed $var        a variable of any type
827
     * @param boolean $output   whether to output the content
zYne's avatar
zYne committed
828 829
     * @return void|string
     */
830
    public static function dump($var, $output = true)
zYne's avatar
zYne committed
831
    {
832
        $ret = array();
zYne's avatar
zYne committed
833 834 835 836
        switch (gettype($var)) {
            case 'array':
                $ret[] = 'Array(';
                foreach ($var as $k => $v) {
zYne's avatar
zYne committed
837
                    $ret[] = $k . ' : ' . Doctrine::dump($v, false);
zYne's avatar
zYne committed
838
                }
zYne's avatar
zYne committed
839
                $ret[] = ")";
zYne's avatar
zYne committed
840
                break;
841
            case 'object':
zYne's avatar
zYne committed
842 843 844 845 846
                $ret[] = 'Object(' . get_class($var) . ')';
                break;
            default:
                $ret[] = var_export($var, true);
        }
847 848 849
        if ($output) {
            print implode("\n", $ret);
        }
zYne's avatar
zYne committed
850 851
        return implode("\n", $ret);
    }
lsmith's avatar
lsmith committed
852 853 854 855 856 857
    /**
     * returns table name from class name
     *
     * @param string $classname
     * @return string
     */
lsmith's avatar
lsmith committed
858 859
    public static function tableize($classname)
    {
lsmith's avatar
lsmith committed
860 861 862 863 864 865 866 867
         return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $classname));
    }
    /**
     * returns class name from table name
     *
     * @param string $tablename
     * @return string
     */
lsmith's avatar
lsmith committed
868 869
    public static function classify($tablename)
    {
870 871 872 873 874 875 876 877 878 879 880 881
        return preg_replace_callback('~(_?)(_)([\w])~', array("Doctrine", "classifyCallback"), ucfirst($tablename));
    }

    /**
     * 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
882 883 884 885 886 887 888
    }
    /**
     * checks for valid class name (uses camel case and underscores)
     *
     * @param string $classname
     * @return boolean
     */
lsmith's avatar
lsmith committed
889 890
    public static function isValidClassname($classname)
    {
zYne's avatar
zYne committed
891
        if (preg_match('~(^[a-z])|(_[a-z])|([\W])|(_{2})~', $classname)) {
lsmith's avatar
lsmith committed
892
            return false;
893
        }
lsmith's avatar
lsmith committed
894 895 896

        return true;
    }
897
}