1<?php 2/* 3 * $Id$ 4 * 5 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 6 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 7 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 8 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 9 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 10 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 11 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 12 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 13 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 14 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 15 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 * 17 * This software consists of voluntary contributions made by many individuals 18 * and is licensed under the LGPL. For more information, see 19 * <http://www.doctrine-project.org>. 20 */ 21 22/** 23 * The base core class of Doctrine 24 * 25 * @package Doctrine 26 * @author Konsta Vesterinen <kvesteri@cc.hut.fi> 27 * @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library) 28 * @license http://www.opensource.org/licenses/lgpl-license.php LGPL 29 * @link www.doctrine-project.org 30 * @since 1.0 31 * @version $Revision$ 32 */ 33class Doctrine_Core 34{ 35 /** 36 * VERSION 37 */ 38 const VERSION = '1.2.4'; 39 40 /** 41 * ERROR CONSTANTS 42 */ 43 const ERR = -1; 44 const ERR_SYNTAX = -2; 45 const ERR_CONSTRAINT = -3; 46 const ERR_NOT_FOUND = -4; 47 const ERR_ALREADY_EXISTS = -5; 48 const ERR_UNSUPPORTED = -6; 49 const ERR_MISMATCH = -7; 50 const ERR_INVALID = -8; 51 const ERR_NOT_CAPABLE = -9; 52 const ERR_TRUNCATED = -10; 53 const ERR_INVALID_NUMBER = -11; 54 const ERR_INVALID_DATE = -12; 55 const ERR_DIVZERO = -13; 56 const ERR_NODBSELECTED = -14; 57 const ERR_CANNOT_CREATE = -15; 58 const ERR_CANNOT_DELETE = -16; 59 const ERR_CANNOT_DROP = -17; 60 const ERR_NOSUCHTABLE = -18; 61 const ERR_NOSUCHFIELD = -19; 62 const ERR_NEED_MORE_DATA = -20; 63 const ERR_NOT_LOCKED = -21; 64 const ERR_VALUE_COUNT_ON_ROW = -22; 65 const ERR_INVALID_DSN = -23; 66 const ERR_CONNECT_FAILED = -24; 67 const ERR_EXTENSION_NOT_FOUND = -25; 68 const ERR_NOSUCHDB = -26; 69 const ERR_ACCESS_VIOLATION = -27; 70 const ERR_CANNOT_REPLACE = -28; 71 const ERR_CONSTRAINT_NOT_NULL = -29; 72 const ERR_DEADLOCK = -30; 73 const ERR_CANNOT_ALTER = -31; 74 const ERR_MANAGER = -32; 75 const ERR_MANAGER_PARSE = -33; 76 const ERR_LOADMODULE = -34; 77 const ERR_INSUFFICIENT_DATA = -35; 78 const ERR_CLASS_NAME = -36; 79 80 /** 81 * PDO derived constants 82 */ 83 const CASE_LOWER = 2; 84 const CASE_NATURAL = 0; 85 const CASE_UPPER = 1; 86 const CURSOR_FWDONLY = 0; 87 const CURSOR_SCROLL = 1; 88 const ERRMODE_EXCEPTION = 2; 89 const ERRMODE_SILENT = 0; 90 const ERRMODE_WARNING = 1; 91 const FETCH_ASSOC = 2; 92 const FETCH_BOTH = 4; 93 const FETCH_BOUND = 6; 94 const FETCH_CLASS = 8; 95 const FETCH_CLASSTYPE = 262144; 96 const FETCH_COLUMN = 7; 97 const FETCH_FUNC = 10; 98 const FETCH_GROUP = 65536; 99 const FETCH_INTO = 9; 100 const FETCH_LAZY = 1; 101 const FETCH_NAMED = 11; 102 const FETCH_NUM = 3; 103 const FETCH_OBJ = 5; 104 const FETCH_ORI_ABS = 4; 105 const FETCH_ORI_FIRST = 2; 106 const FETCH_ORI_LAST = 3; 107 const FETCH_ORI_NEXT = 0; 108 const FETCH_ORI_PRIOR = 1; 109 const FETCH_ORI_REL = 5; 110 const FETCH_SERIALIZE = 524288; 111 const FETCH_UNIQUE = 196608; 112 const NULL_EMPTY_STRING = 1; 113 const NULL_NATURAL = 0; 114 const NULL_TO_STRING = NULL; 115 const PARAM_BOOL = 5; 116 const PARAM_INPUT_OUTPUT = -2147483648; 117 const PARAM_INT = 1; 118 const PARAM_LOB = 3; 119 const PARAM_NULL = 0; 120 const PARAM_STMT = 4; 121 const PARAM_STR = 2; 122 123 /** 124 * ATTRIBUTE CONSTANTS 125 */ 126 127 /** 128 * PDO derived attributes 129 */ 130 const ATTR_AUTOCOMMIT = 0; 131 const ATTR_PREFETCH = 1; 132 const ATTR_TIMEOUT = 2; 133 const ATTR_ERRMODE = 3; 134 const ATTR_SERVER_VERSION = 4; 135 const ATTR_CLIENT_VERSION = 5; 136 const ATTR_SERVER_INFO = 6; 137 const ATTR_CONNECTION_STATUS = 7; 138 const ATTR_CASE = 8; 139 const ATTR_CURSOR_NAME = 9; 140 const ATTR_CURSOR = 10; 141 const ATTR_ORACLE_NULLS = 11; 142 const ATTR_PERSISTENT = 12; 143 const ATTR_STATEMENT_CLASS = 13; 144 const ATTR_FETCH_TABLE_NAMES = 14; 145 const ATTR_FETCH_CATALOG_NAMES = 15; 146 const ATTR_DRIVER_NAME = 16; 147 const ATTR_STRINGIFY_FETCHES = 17; 148 const ATTR_MAX_COLUMN_LEN = 18; 149 150 /** 151 * Doctrine constants 152 */ 153 const ATTR_LISTENER = 100; 154 const ATTR_QUOTE_IDENTIFIER = 101; 155 const ATTR_FIELD_CASE = 102; 156 const ATTR_IDXNAME_FORMAT = 103; 157 const ATTR_SEQNAME_FORMAT = 104; 158 const ATTR_SEQCOL_NAME = 105; 159 const ATTR_CMPNAME_FORMAT = 118; 160 const ATTR_DBNAME_FORMAT = 117; 161 const ATTR_TBLCLASS_FORMAT = 119; 162 const ATTR_TBLNAME_FORMAT = 120; 163 const ATTR_FKNAME_FORMAT = 171; 164 const ATTR_EXPORT = 140; 165 const ATTR_DECIMAL_PLACES = 141; 166 167 const ATTR_PORTABILITY = 106; 168 const ATTR_VALIDATE = 107; 169 const ATTR_COLL_KEY = 108; 170 const ATTR_QUERY_LIMIT = 109; 171 const ATTR_DEFAULT_TABLE_TYPE = 112; 172 const ATTR_DEF_TEXT_LENGTH = 113; 173 const ATTR_DEF_VARCHAR_LENGTH = 114; 174 const ATTR_DEF_TABLESPACE = 115; 175 const ATTR_EMULATE_DATABASE = 116; 176 const ATTR_USE_NATIVE_ENUM = 117; 177 const ATTR_DEFAULT_SEQUENCE = 133; 178 179 const ATTR_FETCHMODE = 118; 180 const ATTR_NAME_PREFIX = 121; 181 const ATTR_CREATE_TABLES = 122; 182 const ATTR_COLL_LIMIT = 123; 183 184 const ATTR_CACHE = 150; 185 const ATTR_RESULT_CACHE = 150; 186 const ATTR_CACHE_LIFESPAN = 151; 187 const ATTR_RESULT_CACHE_LIFESPAN = 151; 188 const ATTR_LOAD_REFERENCES = 153; 189 const ATTR_RECORD_LISTENER = 154; 190 const ATTR_THROW_EXCEPTIONS = 155; 191 const ATTR_DEFAULT_PARAM_NAMESPACE = 156; 192 const ATTR_QUERY_CACHE = 157; 193 const ATTR_QUERY_CACHE_LIFESPAN = 158; 194 const ATTR_AUTOLOAD_TABLE_CLASSES = 160; 195 const ATTR_MODEL_LOADING = 161; 196 const ATTR_RECURSIVE_MERGE_FIXTURES = 162; 197 const ATTR_USE_DQL_CALLBACKS = 164; 198 const ATTR_AUTO_ACCESSOR_OVERRIDE = 165; 199 const ATTR_AUTO_FREE_QUERY_OBJECTS = 166; 200 const ATTR_DEFAULT_TABLE_CHARSET = 167; 201 const ATTR_DEFAULT_TABLE_COLLATE = 168; 202 const ATTR_DEFAULT_IDENTIFIER_OPTIONS = 169; 203 const ATTR_DEFAULT_COLUMN_OPTIONS = 170; 204 const ATTR_HYDRATE_OVERWRITE = 172; 205 const ATTR_QUERY_CLASS = 173; 206 const ATTR_CASCADE_SAVES = 174; 207 const ATTR_COLLECTION_CLASS = 175; 208 const ATTR_TABLE_CLASS = 176; 209 const ATTR_USE_NATIVE_SET = 177; 210 const ATTR_MODEL_CLASS_PREFIX = 178; 211 const ATTR_TABLE_CLASS_FORMAT = 179; 212 const ATTR_MAX_IDENTIFIER_LENGTH = 180; 213 const ATTR_USE_TABLE_REPOSITORY = 181; 214 const ATTR_USE_TABLE_IDENTITY_MAP = 182; 215 const ATTR_TABLE_CACHE = 183; 216 const ATTR_TABLE_CACHE_LIFESPAN = 184; 217 218 219 /** 220 * LIMIT CONSTANTS 221 */ 222 223 /** 224 * constant for row limiting 225 */ 226 const LIMIT_ROWS = 1; 227 const QUERY_LIMIT_ROWS = 1; 228 229 /** 230 * constant for record limiting 231 */ 232 const LIMIT_RECORDS = 2; 233 const QUERY_LIMIT_RECORDS = 2; 234 235 /** 236 * FETCHMODE CONSTANTS 237 */ 238 239 240 /** 241 * PORTABILITY CONSTANTS 242 */ 243 244 /** 245 * Portability: turn off all portability features. 246 * @see self::ATTR_PORTABILITY 247 */ 248 const PORTABILITY_NONE = 0; 249 250 /** 251 * Portability: convert names of tables and fields to case defined in the 252 * "field_case" option when using the query*(), fetch*() methods. 253 * @see self::ATTR_PORTABILITY 254 */ 255 const PORTABILITY_FIX_CASE = 1; 256 257 /** 258 * Portability: right trim the data output by query*() and fetch*(). 259 * @see self::ATTR_PORTABILITY 260 */ 261 const PORTABILITY_RTRIM = 2; 262 263 /** 264 * Portability: force reporting the number of rows deleted. 265 * @see self::ATTR_PORTABILITY 266 */ 267 const PORTABILITY_DELETE_COUNT = 4; 268 269 /** 270 * Portability: convert empty values to null strings in data output by 271 * query*() and fetch*(). 272 * @see self::ATTR_PORTABILITY 273 */ 274 const PORTABILITY_EMPTY_TO_NULL = 8; 275 276 /** 277 * Portability: removes database/table qualifiers from associative indexes 278 * @see self::ATTR_PORTABILITY 279 */ 280 const PORTABILITY_FIX_ASSOC_FIELD_NAMES = 16; 281 282 /** 283 * Portability: makes Doctrine_Expression throw exception for unportable RDBMS expressions 284 * @see self::ATTR_PORTABILITY 285 */ 286 const PORTABILITY_EXPR = 32; 287 288 /** 289 * Portability: turn on all portability features. 290 * @see self::ATTR_PORTABILITY 291 */ 292 const PORTABILITY_ALL = 63; 293 294 /** 295 * LOCKMODE CONSTANTS 296 */ 297 298 /** 299 * mode for optimistic locking 300 */ 301 const LOCK_OPTIMISTIC = 0; 302 303 /** 304 * mode for pessimistic locking 305 */ 306 const LOCK_PESSIMISTIC = 1; 307 308 /** 309 * EXPORT CONSTANTS 310 */ 311 312 /** 313 * EXPORT_NONE 314 */ 315 const EXPORT_NONE = 0; 316 317 /** 318 * EXPORT_TABLES 319 */ 320 const EXPORT_TABLES = 1; 321 322 /** 323 * EXPORT_CONSTRAINTS 324 */ 325 const EXPORT_CONSTRAINTS = 2; 326 327 /** 328 * EXPORT_PLUGINS 329 */ 330 const EXPORT_PLUGINS = 4; 331 332 /** 333 * EXPORT_ALL 334 */ 335 const EXPORT_ALL = 7; 336 337 /** 338 * HYDRATION CONSTANTS 339 */ 340 341 /** 342 * HYDRATE_RECORD 343 */ 344 const HYDRATE_RECORD = 2; 345 346 /** 347 * HYDRATE_ARRAY 348 */ 349 const HYDRATE_ARRAY = 3; 350 351 /** 352 * HYDRATE_NONE 353 */ 354 const HYDRATE_NONE = 4; 355 356 /** 357 * HYDRATE_SCALAR 358 */ 359 const HYDRATE_SCALAR = 5; 360 361 /** 362 * HYDRATE_SINGLE_SCALAR 363 */ 364 const HYDRATE_SINGLE_SCALAR = 6; 365 366 /** 367 * HYDRATE_ON_DEMAND 368 */ 369 const HYDRATE_ON_DEMAND = 7; 370 371 /** 372 * HYDRATE_ARRAY_HIERARCHY 373 */ 374 const HYDRATE_ARRAY_HIERARCHY = 8; 375 376 /** 377 * HYDRATE_RECORD_HIERARCHY 378 */ 379 const HYDRATE_RECORD_HIERARCHY = 9; 380 381 /** 382 * HYDRATE_ARRAY_SHALLOW 383 */ 384 const HYDRATE_ARRAY_SHALLOW = 10; 385 386 /** 387 * VALIDATION CONSTANTS 388 */ 389 const VALIDATE_NONE = 0; 390 391 /** 392 * VALIDATE_LENGTHS 393 */ 394 const VALIDATE_LENGTHS = 1; 395 396 /** 397 * VALIDATE_TYPES 398 */ 399 const VALIDATE_TYPES = 2; 400 401 /** 402 * VALIDATE_CONSTRAINTS 403 */ 404 const VALIDATE_CONSTRAINTS = 4; 405 406 /** 407 * VALIDATE_ALL 408 */ 409 const VALIDATE_ALL = 7; 410 411 /** 412 * VALIDATE_USER 413 */ 414 const VALIDATE_USER = 8; 415 416 /** 417 * IDENTIFIER_AUTOINC 418 * 419 * constant for auto_increment identifier 420 */ 421 const IDENTIFIER_AUTOINC = 1; 422 423 /** 424 * IDENTIFIER_SEQUENCE 425 * 426 * constant for sequence identifier 427 */ 428 const IDENTIFIER_SEQUENCE = 2; 429 430 /** 431 * IDENTIFIER_NATURAL 432 * 433 * constant for normal identifier 434 */ 435 const IDENTIFIER_NATURAL = 3; 436 437 /** 438 * IDENTIFIER_COMPOSITE 439 * 440 * constant for composite identifier 441 */ 442 const IDENTIFIER_COMPOSITE = 4; 443 444 /** 445 * MODEL_LOADING_AGGRESSIVE 446 * 447 * Constant for agressive model loading 448 * Will require_once() all found model files 449 */ 450 const MODEL_LOADING_AGGRESSIVE = 1; 451 452 /** 453 * MODEL_LOADING_CONSERVATIVE 454 * 455 * Constant for conservative model loading 456 * Will not require_once() found model files inititally instead it will build an array 457 * and reference it in autoload() when a class is needed it will require_once() it 458 */ 459 const MODEL_LOADING_CONSERVATIVE = 2; 460 461 /** 462 * MODEL_LOADING_PEAR 463 * 464 * Constant for pear model loading 465 * Will simply store the path passed to Doctrine_Core::loadModels() 466 * and Doctrine_Core::autoload() will check there 467 */ 468 const MODEL_LOADING_PEAR = 3; 469 470 /** 471 * Path to Doctrine root 472 * 473 * @var string $path doctrine root directory 474 */ 475 private static $_path; 476 477 /** 478 * Path to the Doctrine extensions directory 479 * 480 * @var string $extensionsPath 481 */ 482 private static $_extensionsPath; 483 484 /** 485 * Debug bool true/false option 486 * 487 * @var boolean $_debug 488 */ 489 private static $_debug = false; 490 491 /** 492 * Array of all the loaded models and the path to each one for autoloading 493 * 494 * @var array 495 */ 496 private static $_loadedModelFiles = array(); 497 498 /** 499 * Array of all the loaded validators 500 * 501 * @var array 502 */ 503 private static $_validators = array(); 504 505 /** 506 * Path to the models directory 507 * 508 * @var string 509 */ 510 private static $_modelsDirectory; 511 512 /** 513 * __construct 514 * 515 * @return void 516 * @throws Doctrine_Exception 517 */ 518 public function __construct() 519 { 520 throw new Doctrine_Exception('Doctrine is static class. No instances can be created.'); 521 } 522 523 /** 524 * Returns an array of all the loaded models and the path where each of them exists 525 * 526 * @return array 527 */ 528 public static function getLoadedModelFiles() 529 { 530 return self::$_loadedModelFiles; 531 } 532 533 /** 534 * Turn on/off the debugging setting 535 * 536 * @param string $bool 537 * @return void 538 */ 539 public static function debug($bool = null) 540 { 541 if ($bool !== null) { 542 self::$_debug = (bool) $bool; 543 } 544 545 return self::$_debug; 546 } 547 548 /** 549 * Set the path to your core Doctrine libraries 550 * 551 * @param string $path The path to your Doctrine libraries 552 * @return void 553 */ 554 public static function setPath($path) 555 { 556 self::$_path = $path; 557 } 558 559 /** 560 * Get the root path to Doctrine 561 * 562 * @return string 563 */ 564 public static function getPath() 565 { 566 if ( ! self::$_path) { 567 self::$_path = realpath(dirname(__FILE__) . '/..'); 568 } 569 570 return self::$_path; 571 } 572 573 /** 574 * Set the path to autoload extension classes from 575 * 576 * @param string $extensionsPath 577 * @return void 578 */ 579 public static function setExtensionsPath($extensionsPath) 580 { 581 self::$_extensionsPath = $extensionsPath; 582 } 583 584 /** 585 * Get the path to load extension classes from 586 * 587 * @return string $extensionsPath 588 */ 589 public static function getExtensionsPath() 590 { 591 return self::$_extensionsPath; 592 } 593 594 /** 595 * Load an individual model name and path in to the model loading registry 596 * 597 * @return null 598 */ 599 public static function loadModel($className, $path = null) 600 { 601 self::$_loadedModelFiles[$className] = $path; 602 } 603 604 /** 605 * Set the directory where your models are located for PEAR style 606 * naming convention autoloading. 607 * 608 * @param string $directory 609 * @return void 610 */ 611 public static function setModelsDirectory($directory) 612 { 613 self::$_modelsDirectory = $directory; 614 } 615 616 /** 617 * Get the directory where your models are located for PEAR style naming 618 * convention autoloading 619 * 620 * @return void 621 * @author Jonathan Wage 622 */ 623 public static function getModelsDirectory() 624 { 625 return self::$_modelsDirectory; 626 } 627 628 /** 629 * Recursively load all models from a directory or array of directories 630 * 631 * @param string $directory Path to directory of models or array of directory paths 632 * @param integer $modelLoading Pass value of Doctrine_Core::ATTR_MODEL_LOADING to force a certain style of model loading 633 * Allowed Doctrine_Core::MODEL_LOADING_AGGRESSIVE(default) or Doctrine_Core::MODEL_LOADING_CONSERVATIVE 634 * @param string $classPrefix The class prefix of the models to load. This is useful if the class name and file name are not the same 635 */ 636 public static function loadModels($directory, $modelLoading = null, $classPrefix = null) 637 { 638 $manager = Doctrine_Manager::getInstance(); 639 640 $modelLoading = $modelLoading === null ? $manager->getAttribute(Doctrine_Core::ATTR_MODEL_LOADING) : $modelLoading; 641 $classPrefix = $classPrefix === null ? $manager->getAttribute(Doctrine_Core::ATTR_MODEL_CLASS_PREFIX) : $classPrefix; 642 643 $loadedModels = array(); 644 645 if ($directory !== null) { 646 foreach ((array) $directory as $dir) { 647 $dir = rtrim($dir, '/'); 648 if ( ! is_dir($dir)) { 649 throw new Doctrine_Exception('You must pass a valid path to a directory containing Doctrine models'); 650 } 651 652 $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir), 653 RecursiveIteratorIterator::LEAVES_ONLY); 654 655 foreach ($it as $file) { 656 $e = explode('.', $file->getFileName()); 657 658 if (end($e) === 'php' && strpos($file->getFileName(), '.inc') === false) { 659 if ($modelLoading == Doctrine_Core::MODEL_LOADING_PEAR) { 660 $className = str_replace($dir . DIRECTORY_SEPARATOR, null, $file->getPathName()); 661 $className = str_replace(DIRECTORY_SEPARATOR, '_', $className); 662 $className = substr($className, 0, strpos($className, '.')); 663 } else { 664 $className = $e[0]; 665 } 666 667 if ($classPrefix && $classPrefix != substr($className, 0, strlen($classPrefix))) { 668 $className = $classPrefix . $className; 669 } 670 671 if ( ! class_exists($className, false)) { 672 if ($modelLoading == Doctrine_Core::MODEL_LOADING_CONSERVATIVE || $modelLoading == Doctrine_Core::MODEL_LOADING_PEAR) { 673 self::loadModel($className, $file->getPathName()); 674 675 $loadedModels[$className] = $className; 676 } else { 677 $declaredBefore = get_declared_classes(); 678 require_once($file->getPathName()); 679 $declaredAfter = get_declared_classes(); 680 681 if (defined('HHVM_VERSION')) { 682 // on HHVM get_declared_classes() returns in a different order, array_diff() works, so we have to use it 683 $foundClasses = array_diff($declaredAfter, $declaredBefore); 684 } else { 685 // Using array_slice because array_diff is broken is some PHP versions 686 // https://bugs.php.net/bug.php?id=47643 687 $foundClasses = array_slice($declaredAfter, count($declaredBefore)); 688 } 689 690 if ($foundClasses) { 691 foreach ($foundClasses as $className) { 692 if (self::isValidModelClass($className)) { 693 $loadedModels[$className] = $className; 694 695 self::loadModel($className, $file->getPathName()); 696 } 697 } 698 } 699 700 $previouslyLoaded = array_keys(self::$_loadedModelFiles, $file->getPathName()); 701 702 if ( ! empty($previouslyLoaded)) { 703 $previouslyLoaded = array_combine(array_values($previouslyLoaded), array_values($previouslyLoaded)); 704 $loadedModels = array_merge($loadedModels, $previouslyLoaded); 705 } 706 } 707 } else if (self::isValidModelClass($className)) { 708 $loadedModels[$className] = $className; 709 } 710 } 711 } 712 } 713 } 714 715 asort($loadedModels); 716 717 return $loadedModels; 718 } 719 720 /** 721 * Get all the loaded models, you can provide an array of classes or it will use get_declared_classes() 722 * 723 * Will filter through an array of classes and return the Doctrine_Records out of them. 724 * If you do not specify $classes it will return all of the currently loaded Doctrine_Records 725 * 726 * @param classes Array of classes to filter through, otherwise uses get_declared_classes() 727 * @return array $loadedModels 728 */ 729 public static function getLoadedModels($classes = null) 730 { 731 if ($classes === null) { 732 $classes = get_declared_classes(); 733 $classes = array_merge($classes, array_keys(self::$_loadedModelFiles)); 734 } 735 736 return self::filterInvalidModels($classes); 737 } 738 739 /** 740 * Initialize all models so everything is present and loaded in to memory 741 * This will also inheritently initialize any model behaviors and add 742 * the models generated by Doctrine generators and add them to the $models 743 * array 744 * 745 * @param string $models 746 * @return array $models 747 */ 748 public static function initializeModels($models) 749 { 750 $models = self::filterInvalidModels($models); 751 752 foreach ($models as $model) { 753 $declaredBefore = get_declared_classes(); 754 Doctrine_Core::getTable($model); 755 756 $declaredAfter = get_declared_classes(); 757 if (defined('HHVM_VERSION')) { 758 // on HHVM get_declared_classes() returns in a different order, array_diff() works, so we have to use it 759 $foundClasses = array_diff($declaredAfter, $declaredBefore); 760 } else { 761 // Using array_slice because array_diff is broken is some PHP versions 762 // https://bugs.php.net/bug.php?id=47643 763 $foundClasses = array_slice($declaredAfter, count($declaredBefore) - 1); 764 } 765 foreach ($foundClasses as $class) { 766 if (self::isValidModelClass($class)) { 767 $models[] = $class; 768 } 769 } 770 } 771 772 $models = self::filterInvalidModels($models); 773 774 return $models; 775 } 776 777 /** 778 * Filter through an array of classes and return all the classes that are valid models. 779 * This will inflect the class, causing it to be loaded in to memory. 780 * 781 * @param classes Array of classes to filter through, otherwise uses get_declared_classes() 782 * @return array $loadedModels 783 */ 784 public static function filterInvalidModels($classes) 785 { 786 $validModels = array(); 787 788 foreach ((array) $classes as $name) { 789 if (self::isValidModelClass($name) && ! in_array($name, $validModels)) { 790 $validModels[] = $name; 791 } 792 } 793 794 return $validModels; 795 } 796 797 /** 798 * Checks if what is passed is a valid Doctrine_Record 799 * Will load class in to memory in order to inflect it and find out information about the class 800 * 801 * @param mixed $class Can be a string named after the class, an instance of the class, or an instance of the class reflected 802 * @return boolean 803 */ 804 public static function isValidModelClass($class) 805 { 806 if ($class instanceof Doctrine_Record) { 807 $class = get_class($class); 808 } 809 810 if (is_string($class) && class_exists($class)) { 811 $class = new ReflectionClass($class); 812 } 813 814 if ($class instanceof ReflectionClass) { 815 // Skip the following classes 816 // - abstract classes 817 // - not a subclass of Doctrine_Record 818 if ( ! $class->isAbstract() && $class->isSubclassOf('Doctrine_Record')) { 819 820 return true; 821 } 822 } 823 824 return false; 825 } 826 827 /** 828 * Get the connection object for a table by the actual table name 829 * FIXME: I think this method is flawed because a individual connections could have the same table name 830 * 831 * @param string $tableName 832 * @return Doctrine_Connection 833 */ 834 public static function getConnectionByTableName($tableName) 835 { 836 $loadedModels = self::getLoadedModels(); 837 838 foreach ($loadedModels as $name) { 839 $table = Doctrine_Core::getTable($name); 840 841 if ($table->getTableName() == $tableName) { 842 return $table->getConnection(); 843 } 844 } 845 846 return Doctrine_Manager::connection(); 847 } 848 849 /** 850 * Method for importing existing schema to Doctrine_Record classes 851 * 852 * @param string $directory Directory to write your models to 853 * @param array $connections Array of connection names to generate models for 854 * @param array $options Array of options 855 * @return boolean 856 * @throws Exception 857 */ 858 public static function generateModelsFromDb($directory, array $connections = array(), array $options = array()) 859 { 860 return Doctrine_Manager::connection()->import->importSchema($directory, $connections, $options); 861 } 862 863 /** 864 * Generates models from database to temporary location then uses those models to generate a yaml schema file. 865 * This should probably be fixed. We should write something to generate a yaml schema file directly from the database. 866 * 867 * @param string $yamlPath Path to write oyur yaml schema file to 868 * @param array $connections Array of connection names to generate yaml for 869 * @param array $options Array of options 870 * @return void 871 */ 872 public static function generateYamlFromDb($yamlPath, array $connections = array(), array $options = array()) 873 { 874 $directory = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'tmp_doctrine_models'; 875 876 $options['generateBaseClasses'] = isset($options['generateBaseClasses']) ? $options['generateBaseClasses']:false; 877 $result = Doctrine_Core::generateModelsFromDb($directory, $connections, $options); 878 879 if ( empty($result) && ! is_dir($directory)) { 880 throw new Doctrine_Exception('No models generated from your databases'); 881 } 882 883 $export = new Doctrine_Export_Schema(); 884 885 $result = $export->exportSchema($yamlPath, 'yml', $directory, array(), Doctrine_Core::MODEL_LOADING_AGGRESSIVE); 886 887 Doctrine_Lib::removeDirectories($directory); 888 889 return $result; 890 } 891 892 /** 893 * Generate a yaml schema file from an existing directory of models 894 * 895 * @param string $yamlPath Path to your yaml schema files 896 * @param string $directory Directory to generate your models in 897 * @param array $options Array of options to pass to the schema importer 898 * @return void 899 */ 900 public static function generateModelsFromYaml($yamlPath, $directory, $options = array()) 901 { 902 $import = new Doctrine_Import_Schema(); 903 $import->setOptions($options); 904 905 return $import->importSchema($yamlPath, 'yml', $directory); 906 } 907 908 /** 909 * Creates database tables for the models in the specified directory 910 * 911 * @param string $directory Directory containing your models 912 * @return void 913 */ 914 public static function createTablesFromModels($directory = null) 915 { 916 return Doctrine_Manager::connection()->export->exportSchema($directory); 917 } 918 919 /** 920 * Creates database tables for the models in the supplied array 921 * 922 * @param array $array An array of models to be exported 923 * @return void 924 */ 925 public static function createTablesFromArray($array) 926 { 927 return Doctrine_Manager::connection()->export->exportClasses($array); 928 } 929 930 /** 931 * Generate a array of sql for the passed array of models 932 * 933 * @param array $array 934 * @return array $sql 935 */ 936 public static function generateSqlFromArray($array) 937 { 938 return Doctrine_Manager::connection()->export->exportClassesSql($array); 939 } 940 941 /** 942 * Generate a sql string to create the tables from all loaded models 943 * or the models found in the passed directory. 944 * 945 * @param string $directory 946 * @return string $build String of sql queries. One query per line 947 */ 948 public static function generateSqlFromModels($directory = null) 949 { 950 $conn = Doctrine_Manager::connection(); 951 $sql = $conn->export->exportSql($directory); 952 953 $build = ''; 954 foreach ($sql as $query) { 955 $build .= $query.$conn->sql_file_delimiter; 956 } 957 958 return $build; 959 } 960 961 /** 962 * Generate yaml schema file for the models in the specified directory 963 * 964 * @param string $yamlPath Path to your yaml schema files 965 * @param string $directory Directory to generate your models in 966 * @return void 967 */ 968 public static function generateYamlFromModels($yamlPath, $directory) 969 { 970 $export = new Doctrine_Export_Schema(); 971 972 return $export->exportSchema($yamlPath, 'yml', $directory); 973 } 974 975 /** 976 * Creates databases for connections 977 * 978 * @param string $specifiedConnections Array of connections you wish to create the database for 979 * @return void 980 */ 981 public static function createDatabases($specifiedConnections = array()) 982 { 983 return Doctrine_Manager::getInstance()->createDatabases($specifiedConnections); 984 } 985 986 /** 987 * Drops databases for connections 988 * 989 * @param string $specifiedConnections Array of connections you wish to drop the database for 990 * @return void 991 */ 992 public static function dropDatabases($specifiedConnections = array()) 993 { 994 return Doctrine_Manager::getInstance()->dropDatabases($specifiedConnections); 995 } 996 997 /** 998 * Dump data to a yaml fixtures file 999 * 1000 * @param string $yamlPath Path to write the yaml data fixtures to 1001 * @param string $individualFiles Whether or not to dump data to individual fixtures files 1002 * @return void 1003 */ 1004 public static function dumpData($yamlPath, $individualFiles = false) 1005 { 1006 $data = new Doctrine_Data(); 1007 1008 return $data->exportData($yamlPath, 'yml', array(), $individualFiles); 1009 } 1010 1011 /** 1012 * Load data from a yaml fixtures file. 1013 * The output of dumpData can be fed to loadData 1014 * 1015 * @param string $yamlPath Path to your yaml data fixtures 1016 * @param string $append Whether or not to append the data 1017 * @return void 1018 */ 1019 public static function loadData($yamlPath, $append = false, $charset = 'UTF-8') 1020 { 1021 $data = new Doctrine_Data(); 1022 1023 return $data->importData($yamlPath, 'yml', array(), $append, $charset); 1024 } 1025 1026 /** 1027 * Migrate database to specified $to version. Migrates from current to latest if you do not specify. 1028 * 1029 * @param string $migrationsPath Path to migrations directory which contains your migration classes 1030 * @param string $to Version you wish to migrate to. 1031 * @return bool true 1032 * @throws new Doctrine_Migration_Exception 1033 */ 1034 public static function migrate($migrationsPath, $to = null) 1035 { 1036 $migration = new Doctrine_Migration($migrationsPath); 1037 1038 return $migration->migrate($to); 1039 } 1040 1041 /** 1042 * Generate new migration class skeleton 1043 * 1044 * @param string $className Name of the Migration class to generate 1045 * @param string $migrationsPath Path to directory which contains your migration classes 1046 */ 1047 public static function generateMigrationClass($className, $migrationsPath) 1048 { 1049 $builder = new Doctrine_Migration_Builder($migrationsPath); 1050 1051 return $builder->generateMigrationClass($className); 1052 } 1053 1054 /** 1055 * Generate a set of migration classes from an existing database 1056 * 1057 * @param string $migrationsPath 1058 * @return void 1059 * @throws new Doctrine_Migration_Exception 1060 */ 1061 public static function generateMigrationsFromDb($migrationsPath) 1062 { 1063 $builder = new Doctrine_Migration_Builder($migrationsPath); 1064 1065 return $builder->generateMigrationsFromDb(); 1066 } 1067 1068 /** 1069 * Generate a set of migration classes from an existing set of models 1070 * 1071 * @param string $migrationsPath Path to your Doctrine migration classes 1072 * @param string $modelsPath Path to your Doctrine model classes 1073 * @param integer $modelLoading Style of model loading to use for loading the models in order to generate migrations 1074 * @return void 1075 */ 1076 public static function generateMigrationsFromModels($migrationsPath, $modelsPath = null, $modelLoading = null) 1077 { 1078 $builder = new Doctrine_Migration_Builder($migrationsPath); 1079 1080 return $builder->generateMigrationsFromModels($modelsPath, $modelLoading); 1081 } 1082 1083 /** 1084 * Generate a set of migration classes by generating differences between two sets 1085 * of schema information 1086 * 1087 * @param string $migrationsPath Path to your Doctrine migration classes 1088 * @param string $from From schema information 1089 * @param string $to To schema information 1090 * @return array $changes 1091 */ 1092 public static function generateMigrationsFromDiff($migrationsPath, $from, $to) 1093 { 1094 $diff = new Doctrine_Migration_Diff($from, $to, $migrationsPath); 1095 1096 return $diff->generateMigrationClasses(); 1097 } 1098 1099 /** 1100 * Get the Doctrine_Table object for the passed model 1101 * 1102 * @param string $componentName 1103 * @return Doctrine_Table 1104 */ 1105 public static function getTable($componentName) 1106 { 1107 return Doctrine_Manager::getInstance()->getConnectionForComponent($componentName)->getTable($componentName); 1108 } 1109 1110 /** 1111 * Method for making a single file of most used doctrine runtime components 1112 * including the compiled file instead of multiple files (in worst 1113 * cases dozens of files) can improve performance by an order of magnitude 1114 * 1115 * @param string $target 1116 * @param array $includedDrivers 1117 * @throws Doctrine_Exception 1118 * @return void 1119 */ 1120 public static function compile($target = null, $includedDrivers = array()) 1121 { 1122 return Doctrine_Compiler::compile($target, $includedDrivers); 1123 } 1124 1125 /** 1126 * simple autoload function 1127 * returns true if the class was loaded, otherwise false 1128 * 1129 * @param string $className 1130 * @return boolean 1131 */ 1132 public static function autoload($className) 1133 { 1134 if (strpos($className, 'sfYaml') === 0) { 1135 require dirname(__FILE__) . '/Parser/sfYaml/' . $className . '.php'; 1136 1137 return true; 1138 } 1139 1140 if (0 !== stripos($className, 'Doctrine') || class_exists($className, false) || interface_exists($className, false)) { 1141 return false; 1142 } 1143 1144 $class = self::getPath() . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php'; 1145 1146 if (file_exists($class)) { 1147 require $class; 1148 1149 return true; 1150 } 1151 1152 return false; 1153 } 1154 1155 public static function modelsAutoload($className) 1156 { 1157 if (class_exists($className, false) || interface_exists($className, false)) { 1158 return false; 1159 } 1160 1161 if ( ! self::$_modelsDirectory) { 1162 $loadedModels = self::$_loadedModelFiles; 1163 1164 if (isset($loadedModels[$className]) && file_exists($loadedModels[$className])) { 1165 require $loadedModels[$className]; 1166 1167 return true; 1168 } 1169 } else { 1170 $class = self::$_modelsDirectory . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php'; 1171 1172 if (file_exists($class)) { 1173 require $class; 1174 1175 return true; 1176 } 1177 } 1178 1179 return false; 1180 } 1181 1182 /** 1183 * Load classes from the Doctrine extensions directory/path 1184 * 1185 * @param string $className 1186 * @return boolean 1187 */ 1188 public static function extensionsAutoload($className) 1189 { 1190 if (class_exists($className, false) || interface_exists($className, false)) { 1191 return false; 1192 } 1193 1194 $extensions = Doctrine_Manager::getInstance() 1195 ->getExtensions(); 1196 1197 foreach ($extensions as $name => $path) { 1198 $class = $path . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php'; 1199 1200 if (file_exists($class)) { 1201 require $class; 1202 1203 return true; 1204 } 1205 } 1206 1207 return false; 1208 } 1209 1210 /** 1211 * dumps a given variable 1212 * 1213 * @param mixed $var a variable of any type 1214 * @param boolean $output whether to output the content 1215 * @param string $indent indention string 1216 * @return void|string 1217 */ 1218 public static function dump($var, $output = true, $indent = "") 1219 { 1220 $ret = array(); 1221 switch (gettype($var)) { 1222 case 'array': 1223 $ret[] = 'Array('; 1224 $indent .= " "; 1225 foreach ($var as $k => $v) { 1226 1227 $ret[] = $indent . $k . ' : ' . self::dump($v, false, $indent); 1228 } 1229 $indent = substr($indent,0, -4); 1230 $ret[] = $indent . ")"; 1231 break; 1232 case 'object': 1233 $ret[] = 'Object(' . get_class($var) . ')'; 1234 break; 1235 default: 1236 $ret[] = var_export($var, true); 1237 } 1238 1239 if ($output) { 1240 print implode("\n", $ret); 1241 } 1242 1243 return implode("\n", $ret); 1244 } 1245} 1246