PageRenderTime 44ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/runtime/lib/Propel.php

https://github.com/1989gaurav/Propel
PHP | 924 lines | 447 code | 106 blank | 371 comment | 65 complexity | 8da97e618bec53c17ac4c16d977b83ab MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Propel package.
  4. * For the full copyright and license information, please view the LICENSE
  5. * file that was distributed with this source code.
  6. *
  7. * @license MIT License
  8. */
  9. /**
  10. * Propel's main resource pool and initialization & configuration class.
  11. *
  12. * This static class is used to handle Propel initialization and to maintain all of the
  13. * open database connections and instantiated database maps.
  14. *
  15. * @author Hans Lellelid <hans@xmpl.rg> (Propel)
  16. * @author Daniel Rall <dlr@finemaltcoding.com> (Torque)
  17. * @author Magnús Þór Torfason <magnus@handtolvur.is> (Torque)
  18. * @author Jason van Zyl <jvanzyl@apache.org> (Torque)
  19. * @author Rafal Krzewski <Rafal.Krzewski@e-point.pl> (Torque)
  20. * @author Martin Poeschl <mpoeschl@marmot.at> (Torque)
  21. * @author Henning P. Schmiedehausen <hps@intermeta.de> (Torque)
  22. * @author Kurt Schrader <kschrader@karmalab.org> (Torque)
  23. * @version $Revision$
  24. * @package propel.runtime
  25. */
  26. class Propel
  27. {
  28. /**
  29. * The Propel version.
  30. */
  31. const VERSION = '1.6.3-dev';
  32. /**
  33. * A constant for <code>default</code>.
  34. */
  35. const DEFAULT_NAME = "default";
  36. /**
  37. * A constant defining 'System is unusuable' logging level
  38. */
  39. const LOG_EMERG = 0;
  40. /**
  41. * A constant defining 'Immediate action required' logging level
  42. */
  43. const LOG_ALERT = 1;
  44. /**
  45. * A constant defining 'Critical conditions' logging level
  46. */
  47. const LOG_CRIT = 2;
  48. /**
  49. * A constant defining 'Error conditions' logging level
  50. */
  51. const LOG_ERR = 3;
  52. /**
  53. * A constant defining 'Warning conditions' logging level
  54. */
  55. const LOG_WARNING = 4;
  56. /**
  57. * A constant defining 'Normal but significant' logging level
  58. */
  59. const LOG_NOTICE = 5;
  60. /**
  61. * A constant defining 'Informational' logging level
  62. */
  63. const LOG_INFO = 6;
  64. /**
  65. * A constant defining 'Debug-level messages' logging level
  66. */
  67. const LOG_DEBUG = 7;
  68. /**
  69. * The class name for a PDO object.
  70. */
  71. const CLASS_PDO = 'PDO';
  72. /**
  73. * The class name for a PropelPDO object.
  74. */
  75. const CLASS_PROPEL_PDO = 'PropelPDO';
  76. /**
  77. * The class name for a DebugPDO object.
  78. */
  79. const CLASS_DEBUG_PDO = 'DebugPDO';
  80. /**
  81. * Constant used to request a READ connection (applies to replication).
  82. */
  83. const CONNECTION_READ = 'read';
  84. /**
  85. * Constant used to request a WRITE connection (applies to replication).
  86. */
  87. const CONNECTION_WRITE = 'write';
  88. /**
  89. * @var string The db name that is specified as the default in the property file
  90. */
  91. private static $defaultDBName;
  92. /**
  93. * @var array The global cache of database maps
  94. */
  95. private static $dbMaps = array();
  96. /**
  97. * @var array The cache of DB adapter keys
  98. */
  99. private static $adapterMap = array();
  100. /**
  101. * @var array Cache of established connections (to eliminate overhead).
  102. */
  103. private static $connectionMap = array();
  104. /**
  105. * @var PropelConfiguration Propel-specific configuration.
  106. */
  107. private static $configuration;
  108. /**
  109. * @var bool flag to set to true once this class has been initialized
  110. */
  111. private static $isInit = false;
  112. /**
  113. * @var Log optional logger
  114. */
  115. private static $logger = null;
  116. /**
  117. * @var string The name of the database mapper class
  118. */
  119. private static $databaseMapClass = 'DatabaseMap';
  120. /**
  121. * @var bool Whether the object instance pooling is enabled
  122. */
  123. private static $instancePoolingEnabled = true;
  124. /**
  125. * @var bool For replication, whether to force the use of master connection.
  126. */
  127. private static $forceMasterConnection = false;
  128. /**
  129. * @var string Base directory to use for autoloading. Initialized in self::initBaseDir()
  130. */
  131. protected static $baseDir;
  132. /**
  133. * @var array A map of class names and their file paths for autoloading
  134. */
  135. protected static $autoloadMap = array(
  136. 'DBAdapter' => 'adapter/DBAdapter.php',
  137. 'DBMSSQL' => 'adapter/DBMSSQL.php',
  138. 'MssqlPropelPDO' => 'adapter/MSSQL/MssqlPropelPDO.php',
  139. 'MssqlDebugPDO' => 'adapter/MSSQL/MssqlDebugPDO.php',
  140. 'MssqlDateTime' => 'adapter/MSSQL/MssqlDateTime.class.php',
  141. 'DBMySQL' => 'adapter/DBMySQL.php',
  142. 'DBMySQLi' => 'adapter/DBMySQLi.php',
  143. 'DBNone' => 'adapter/DBNone.php',
  144. 'DBOracle' => 'adapter/DBOracle.php',
  145. 'DBPostgres' => 'adapter/DBPostgres.php',
  146. 'DBSQLite' => 'adapter/DBSQLite.php',
  147. 'DBSybase' => 'adapter/DBSybase.php',
  148. 'DBSQLSRV' => 'adapter/DBSQLSRV.php',
  149. 'PropelArrayCollection' => 'collection/PropelArrayCollection.php',
  150. 'PropelCollection' => 'collection/PropelCollection.php',
  151. 'PropelObjectCollection' => 'collection/PropelObjectCollection.php',
  152. 'PropelOnDemandCollection' => 'collection/PropelOnDemandCollection.php',
  153. 'PropelOnDemandIterator' => 'collection/PropelOnDemandIterator.php',
  154. 'PropelConfiguration' => 'config/PropelConfiguration.php',
  155. 'PropelConfigurationIterator' => 'config/PropelConfigurationIterator.php',
  156. 'PropelPDO' => 'connection/PropelPDO.php',
  157. 'DebugPDO' => 'connection/DebugPDO.php',
  158. 'DebugPDOStatement' => 'connection/DebugPDOStatement.php',
  159. 'PropelException' => 'exception/PropelException.php',
  160. 'ModelWith' => 'formatter/ModelWith.php',
  161. 'PropelArrayFormatter' => 'formatter/PropelArrayFormatter.php',
  162. 'PropelFormatter' => 'formatter/PropelFormatter.php',
  163. 'PropelObjectFormatter' => 'formatter/PropelObjectFormatter.php',
  164. 'PropelOnDemandFormatter' => 'formatter/PropelOnDemandFormatter.php',
  165. 'PropelStatementFormatter' => 'formatter/PropelStatementFormatter.php',
  166. 'PropelSimpleArrayFormatter' => 'formatter/PropelSimpleArrayFormatter.php',
  167. 'BasicLogger' => 'logger/BasicLogger.php',
  168. 'MojaviLogAdapter' => 'logger/MojaviLogAdapter.php',
  169. 'ColumnMap' => 'map/ColumnMap.php',
  170. 'DatabaseMap' => 'map/DatabaseMap.php',
  171. 'TableMap' => 'map/TableMap.php',
  172. 'RelationMap' => 'map/RelationMap.php',
  173. 'ValidatorMap' => 'map/ValidatorMap.php',
  174. 'BaseObject' => 'om/BaseObject.php',
  175. 'NodeObject' => 'om/NodeObject.php',
  176. 'Persistent' => 'om/Persistent.php',
  177. 'PreOrderNodeIterator' => 'om/PreOrderNodeIterator.php',
  178. 'NestedSetPreOrderNodeIterator' => 'om/NestedSetPreOrderNodeIterator.php',
  179. 'NestedSetRecursiveIterator' => 'om/NestedSetRecursiveIterator.php',
  180. 'PropelCSVParser' => 'parser/PropelCSVParser.php',
  181. 'PropelJSONParser' => 'parser/PropelJSONParser.php',
  182. 'PropelParser' => 'parser/PropelParser.php',
  183. 'PropelXMLParser' => 'parser/PropelXMLParser.php',
  184. 'PropelYAMLParser' => 'parser/PropelYAMLParser.php',
  185. 'Criteria' => 'query/Criteria.php',
  186. 'Criterion' => 'query/Criterion.php',
  187. 'CriterionIterator' => 'query/CriterionIterator.php',
  188. 'Join' => 'query/Join.php',
  189. 'ModelCriteria' => 'query/ModelCriteria.php',
  190. 'ModelCriterion' => 'query/ModelCriterion.php',
  191. 'ModelJoin' => 'query/ModelJoin.php',
  192. 'PropelQuery' => 'query/PropelQuery.php',
  193. 'BasePeer' => 'util/BasePeer.php',
  194. 'NodePeer' => 'util/NodePeer.php',
  195. 'PeerInfo' => 'util/PeerInfo.php',
  196. 'PropelAutoloader' => 'util/PropelAutoloader.php',
  197. 'PropelColumnTypes' => 'util/PropelColumnTypes.php',
  198. 'PropelConditionalProxy' => 'util/PropelConditionalProxy.php',
  199. 'PropelModelPager' => 'util/PropelModelPager.php',
  200. 'PropelPager' => 'util/PropelPager.php',
  201. 'PropelDateTime' => 'util/PropelDateTime.php',
  202. 'BasicValidator' => 'validator/BasicValidator.php',
  203. 'MatchValidator' => 'validator/MatchValidator.php',
  204. 'MaxLengthValidator' => 'validator/MaxLengthValidator.php',
  205. 'MaxValueValidator' => 'validator/MaxValueValidator.php',
  206. 'MinLengthValidator' => 'validator/MinLengthValidator.php',
  207. 'MinValueValidator' => 'validator/MinValueValidator.php',
  208. 'NotMatchValidator' => 'validator/NotMatchValidator.php',
  209. 'RequiredValidator' => 'validator/RequiredValidator.php',
  210. 'TypeValidator' => 'validator/TypeValidator.php',
  211. 'UniqueValidator' => 'validator/UniqueValidator.php',
  212. 'ValidValuesValidator' => 'validator/ValidValuesValidator.php',
  213. 'ValidationFailed' => 'validator/ValidationFailed.php',
  214. );
  215. /**
  216. * Initializes Propel
  217. *
  218. * @throws PropelException Any exceptions caught during processing will be
  219. * rethrown wrapped into a PropelException.
  220. */
  221. public static function initialize()
  222. {
  223. if (self::$configuration === null) {
  224. throw new PropelException("Propel cannot be initialized without a valid configuration. Please check the log files for further details.");
  225. }
  226. self::configureLogging();
  227. // reset the connection map (this should enable runtime changes of connection params)
  228. self::$connectionMap = array();
  229. if (isset(self::$configuration['classmap']) && is_array(self::$configuration['classmap'])) {
  230. PropelAutoloader::getInstance()->addClassPaths(self::$configuration['classmap']);
  231. PropelAutoloader::getInstance()->register();
  232. }
  233. self::$isInit = true;
  234. }
  235. /**
  236. * Configure Propel a PHP (array) config file.
  237. *
  238. * @param string Path (absolute or relative to include_path) to config file.
  239. *
  240. * @throws PropelException If configuration file cannot be opened.
  241. * (E_WARNING probably will also be raised by PHP)
  242. */
  243. public static function configure($configFile)
  244. {
  245. $configuration = include($configFile);
  246. if ($configuration === false) {
  247. throw new PropelException("Unable to open configuration file: " . var_export($configFile, true));
  248. }
  249. self::setConfiguration($configuration);
  250. }
  251. /**
  252. * Configure the logging system, if config is specified in the runtime configuration.
  253. */
  254. protected static function configureLogging()
  255. {
  256. if (self::$logger === null) {
  257. if (isset(self::$configuration['log']) && is_array(self::$configuration['log']) && count(self::$configuration['log'])) {
  258. include_once 'Log.php'; // PEAR Log class
  259. $c = self::$configuration['log'];
  260. $type = isset($c['type']) ? $c['type'] : 'file';
  261. $name = isset($c['name']) ? $c['name'] : './propel.log';
  262. $ident = isset($c['ident']) ? $c['ident'] : 'propel';
  263. $conf = isset($c['conf']) ? $c['conf'] : array();
  264. $level = isset($c['level']) ? $c['level'] : PEAR_LOG_DEBUG;
  265. self::$logger = Log::singleton($type, $name, $ident, $conf, $level);
  266. } // if isset()
  267. }
  268. }
  269. /**
  270. * Initialization of Propel a PHP (array) configuration file.
  271. *
  272. * @param string $c The Propel configuration file path.
  273. *
  274. * @throws PropelException Any exceptions caught during processing will be
  275. * rethrown wrapped into a PropelException.
  276. */
  277. public static function init($c)
  278. {
  279. self::configure($c);
  280. self::initialize();
  281. }
  282. /**
  283. * Determine whether Propel has already been initialized.
  284. *
  285. * @return bool True if Propel is already initialized.
  286. */
  287. public static function isInit()
  288. {
  289. return self::$isInit;
  290. }
  291. /**
  292. * Sets the configuration for Propel and all dependencies.
  293. *
  294. * @param mixed The Configuration (array or PropelConfiguration)
  295. */
  296. public static function setConfiguration($c)
  297. {
  298. if (is_array($c)) {
  299. if (isset($c['propel']) && is_array($c['propel'])) {
  300. $c = $c['propel'];
  301. }
  302. $c = new PropelConfiguration($c);
  303. }
  304. self::$configuration = $c;
  305. }
  306. /**
  307. * Get the configuration for this component.
  308. *
  309. * @param int - PropelConfiguration::TYPE_ARRAY: return the configuration as an array
  310. * (for backward compatibility this is the default)
  311. * - PropelConfiguration::TYPE_ARRAY_FLAT: return the configuration as a flat array
  312. * ($config['name.space.item'])
  313. * - PropelConfiguration::TYPE_OBJECT: return the configuration as a PropelConfiguration instance
  314. * @return mixed The Configuration (array or PropelConfiguration)
  315. */
  316. public static function getConfiguration($type = PropelConfiguration::TYPE_ARRAY)
  317. {
  318. return self::$configuration->getParameters($type);
  319. }
  320. /**
  321. * Override the configured logger.
  322. *
  323. * This is primarily for things like unit tests / debugging where
  324. * you want to change the logger without altering the configuration file.
  325. *
  326. * You can use any logger class that implements the propel.logger.BasicLogger
  327. * interface. This interface is based on PEAR::Log, so you can also simply pass
  328. * a PEAR::Log object to this method.
  329. *
  330. * @param object The new logger to use. ([PEAR] Log or BasicLogger)
  331. */
  332. public static function setLogger($logger)
  333. {
  334. self::$logger = $logger;
  335. }
  336. /**
  337. * Returns true if a logger, for example PEAR::Log, has been configured,
  338. * otherwise false.
  339. *
  340. * @return bool True if Propel uses logging
  341. */
  342. public static function hasLogger()
  343. {
  344. return (self::$logger !== null);
  345. }
  346. /**
  347. * Get the configured logger.
  348. *
  349. * @return object Configured log class ([PEAR] Log or BasicLogger).
  350. */
  351. public static function logger()
  352. {
  353. return self::$logger;
  354. }
  355. /**
  356. * Logs a message
  357. * If a logger has been configured, the logger will be used, otherwrise the
  358. * logging message will be discarded without any further action
  359. *
  360. * @param string The message that will be logged.
  361. * @param string The logging level.
  362. *
  363. * @return bool True if the message was logged successfully or no logger was used.
  364. */
  365. public static function log($message, $level = self::LOG_DEBUG)
  366. {
  367. if (self::hasLogger()) {
  368. $logger = self::logger();
  369. switch ($level) {
  370. case self::LOG_EMERG:
  371. return $logger->log($message, $level);
  372. case self::LOG_ALERT:
  373. return $logger->alert($message);
  374. case self::LOG_CRIT:
  375. return $logger->crit($message);
  376. case self::LOG_ERR:
  377. return $logger->err($message);
  378. case self::LOG_WARNING:
  379. return $logger->warning($message);
  380. case self::LOG_NOTICE:
  381. return $logger->notice($message);
  382. case self::LOG_INFO:
  383. return $logger->info($message);
  384. default:
  385. return $logger->debug($message);
  386. }
  387. }
  388. return true;
  389. }
  390. /**
  391. * Returns the database map information. Name relates to the name
  392. * of the connection pool to associate with the map.
  393. *
  394. * The database maps are "registered" by the generated map builder classes.
  395. *
  396. * @param string The name of the database corresponding to the DatabaseMap to retrieve.
  397. *
  398. * @return DatabaseMap The named <code>DatabaseMap</code>.
  399. *
  400. * @throws PropelException - if database map is null or propel was not initialized properly.
  401. */
  402. public static function getDatabaseMap($name = null)
  403. {
  404. if ($name === null) {
  405. $name = self::getDefaultDB();
  406. if ($name === null) {
  407. throw new PropelException("DatabaseMap name is null!");
  408. }
  409. }
  410. if (!isset(self::$dbMaps[$name])) {
  411. $clazz = self::$databaseMapClass;
  412. self::$dbMaps[$name] = new $clazz($name);
  413. }
  414. return self::$dbMaps[$name];
  415. }
  416. /**
  417. * Sets the database map object to use for specified datasource.
  418. *
  419. * @param string $name The datasource name.
  420. * @param DatabaseMap $map The database map object to use for specified datasource.
  421. */
  422. public static function setDatabaseMap($name, DatabaseMap $map)
  423. {
  424. if ($name === null) {
  425. $name = self::getDefaultDB();
  426. }
  427. self::$dbMaps[$name] = $map;
  428. }
  429. /**
  430. * For replication, set whether to always force the use of a master connection.
  431. *
  432. * @param boolean $bit True or False
  433. */
  434. public static function setForceMasterConnection($bit)
  435. {
  436. self::$forceMasterConnection = (bool) $bit;
  437. }
  438. /**
  439. * For replication, whether to always force the use of a master connection.
  440. *
  441. * @return boolean
  442. */
  443. public static function getForceMasterConnection()
  444. {
  445. return self::$forceMasterConnection;
  446. }
  447. /**
  448. * Sets a Connection for specified datasource name.
  449. *
  450. * @param string $name The datasource name for the connection being set.
  451. * @param PropelPDO $con The PDO connection.
  452. * @param string $mode Whether this is a READ or WRITE connection (Propel::CONNECTION_READ, Propel::CONNECTION_WRITE)
  453. */
  454. public static function setConnection($name, PropelPDO $con, $mode = Propel::CONNECTION_WRITE)
  455. {
  456. if ($name === null) {
  457. $name = self::getDefaultDB();
  458. }
  459. if ($mode == Propel::CONNECTION_READ) {
  460. self::$connectionMap[$name]['slave'] = $con;
  461. } else {
  462. self::$connectionMap[$name]['master'] = $con;
  463. }
  464. }
  465. /**
  466. * Gets an already-opened PDO connection or opens a new one for passed-in db name.
  467. *
  468. * @param string $name The datasource name that is used to look up the DSN from the runtime configuation file.
  469. * @param string $mode The connection mode (this applies to replication systems).
  470. *
  471. * @return PDO A database connection
  472. *
  473. * @throws PropelException - if connection cannot be configured or initialized.
  474. */
  475. public static function getConnection($name = null, $mode = Propel::CONNECTION_WRITE)
  476. {
  477. if ($name === null) {
  478. $name = self::getDefaultDB();
  479. }
  480. // IF a WRITE-mode connection was requested
  481. // or Propel is configured to always use the master connection
  482. // THEN return the master connection.
  483. if ($mode != Propel::CONNECTION_READ || self::$forceMasterConnection) {
  484. return self::getMasterConnection($name);
  485. } else {
  486. return self::getSlaveConnection($name);
  487. }
  488. }
  489. /**
  490. * Gets an already-opened write PDO connection or opens a new one for passed-in db name.
  491. *
  492. * @param string $name The datasource name that is used to look up the DSN
  493. * from the runtime configuation file. Empty name not allowed.
  494. *
  495. * @return PDO A database connection
  496. *
  497. * @throws PropelException - if connection cannot be configured or initialized.
  498. */
  499. public static function getMasterConnection($name)
  500. {
  501. if (!isset(self::$connectionMap[$name]['master'])) {
  502. // load connection parameter for master connection
  503. $conparams = isset(self::$configuration['datasources'][$name]['connection']) ? self::$configuration['datasources'][$name]['connection'] : null;
  504. if (empty($conparams)) {
  505. throw new PropelException('No connection information in your runtime configuration file for datasource ['.$name.']');
  506. }
  507. // initialize master connection
  508. $con = Propel::initConnection($conparams, $name);
  509. self::$connectionMap[$name]['master'] = $con;
  510. }
  511. return self::$connectionMap[$name]['master'];
  512. }
  513. /**
  514. * Gets an already-opened read PDO connection or opens a new one for passed-in db name.
  515. *
  516. * @param string $name The datasource name that is used to look up the DSN
  517. * from the runtime configuation file. Empty name not allowed.
  518. *
  519. * @return PDO A database connection
  520. *
  521. * @throws PropelException - if connection cannot be configured or initialized.
  522. */
  523. public static function getSlaveConnection($name)
  524. {
  525. if (!isset(self::$connectionMap[$name]['slave'])) {
  526. $slaveconfigs = isset(self::$configuration['datasources'][$name]['slaves']) ? self::$configuration['datasources'][$name]['slaves'] : null;
  527. if (empty($slaveconfigs)) {
  528. // no slaves configured for this datasource
  529. // fallback to the master connection
  530. self::$connectionMap[$name]['slave'] = self::getMasterConnection($name);
  531. } else {
  532. // Initialize a new slave
  533. if (isset($slaveconfigs['connection']['dsn'])) {
  534. // only one slave connection configured
  535. $conparams = $slaveconfigs['connection'];
  536. } else {
  537. // more than one sleve connection configured
  538. // pickup a random one
  539. $randkey = array_rand($slaveconfigs['connection']);
  540. $conparams = $slaveconfigs['connection'][$randkey];
  541. if (empty($conparams)) {
  542. throw new PropelException('No connection information in your runtime configuration file for SLAVE ['.$randkey.'] to datasource ['.$name.']');
  543. }
  544. }
  545. // initialize slave connection
  546. $con = Propel::initConnection($conparams, $name);
  547. self::$connectionMap[$name]['slave'] = $con;
  548. }
  549. } // if datasource slave not set
  550. return self::$connectionMap[$name]['slave'];
  551. }
  552. /**
  553. * Opens a new PDO connection for passed-in db name.
  554. *
  555. * @param array $conparams Connection paramters.
  556. * @param string $name Datasource name.
  557. * @param string $defaultClass The PDO subclass to instantiate if there is no explicit classname
  558. * specified in the connection params (default is Propel::CLASS_PROPEL_PDO)
  559. *
  560. * @return PDO A database connection of the given class (PDO, PropelPDO, SlavePDO or user-defined)
  561. *
  562. * @throws PropelException - if lower-level exception caught when trying to connect.
  563. */
  564. public static function initConnection($conparams, $name, $defaultClass = Propel::CLASS_PROPEL_PDO)
  565. {
  566. $adapter = self::getDB($name);
  567. if (null === $conparams['dsn']) {
  568. throw new PropelException('No dsn specified in your connection parameters for datasource ['.$name.']');
  569. }
  570. $conparams = $adapter->prepareParams($conparams);
  571. if (isset($conparams['classname']) && !empty($conparams['classname'])) {
  572. $classname = $conparams['classname'];
  573. if (!class_exists($classname)) {
  574. throw new PropelException('Unable to load specified PDO subclass: ' . $classname);
  575. }
  576. } else {
  577. $classname = $defaultClass;
  578. }
  579. $dsn = $conparams['dsn'];
  580. $user = isset($conparams['user']) ? $conparams['user'] : null;
  581. $password = isset($conparams['password']) ? $conparams['password'] : null;
  582. // load any driver options from the config file
  583. // driver options are those PDO settings that have to be passed during the connection construction
  584. $driver_options = array();
  585. if ( isset($conparams['options']) && is_array($conparams['options']) ) {
  586. try {
  587. self::processDriverOptions( $conparams['options'], $driver_options );
  588. } catch (PropelException $e) {
  589. throw new PropelException('Error processing driver options for datasource ['.$name.']', $e);
  590. }
  591. }
  592. try {
  593. $con = new $classname($dsn, $user, $password, $driver_options);
  594. $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  595. } catch (PDOException $e) {
  596. throw new PropelException("Unable to open PDO connection", $e);
  597. }
  598. // load any connection options from the config file
  599. // connection attributes are those PDO flags that have to be set on the initialized connection
  600. if (isset($conparams['attributes']) && is_array($conparams['attributes'])) {
  601. $attributes = array();
  602. try {
  603. self::processDriverOptions( $conparams['attributes'], $attributes );
  604. } catch (PropelException $e) {
  605. throw new PropelException('Error processing connection attributes for datasource ['.$name.']', $e);
  606. }
  607. foreach ($attributes as $key => $value) {
  608. $con->setAttribute($key, $value);
  609. }
  610. }
  611. // initialize the connection using the settings provided in the config file. this could be a "SET NAMES <charset>" query for MySQL, for instance
  612. $adapter->initConnection($con, isset($conparams['settings']) && is_array($conparams['settings']) ? $conparams['settings'] : array());
  613. return $con;
  614. }
  615. /**
  616. * Internal function to handle driver options or conneciton attributes in PDO.
  617. *
  618. * Process the INI file flags to be passed to each connection.
  619. *
  620. * @param array Where to find the list of constant flags and their new setting.
  621. * @param array Put the data into here
  622. *
  623. * @throws PropelException If invalid options were specified.
  624. */
  625. private static function processDriverOptions($source, &$write_to)
  626. {
  627. foreach ($source as $option => $optiondata) {
  628. if (is_string($option) && strpos($option, '::') !== false) {
  629. $key = $option;
  630. } elseif (is_string($option)) {
  631. $key = 'PropelPDO::' . $option;
  632. }
  633. if (!defined($key)) {
  634. throw new PropelException("Invalid PDO option/attribute name specified: ".$key);
  635. }
  636. $key = constant($key);
  637. $value = $optiondata['value'];
  638. if (is_string($value) && strpos($value, '::') !== false) {
  639. if (!defined($value)) {
  640. throw new PropelException("Invalid PDO option/attribute value specified: ".$value);
  641. }
  642. $value = constant($value);
  643. }
  644. $write_to[$key] = $value;
  645. }
  646. }
  647. /**
  648. * Returns database adapter for a specific datasource.
  649. *
  650. * @param string The datasource name.
  651. *
  652. * @return DBAdapter The corresponding database adapter.
  653. *
  654. * @throws PropelException If unable to find DBdapter for specified db.
  655. */
  656. public static function getDB($name = null)
  657. {
  658. if ($name === null) {
  659. $name = self::getDefaultDB();
  660. }
  661. if (!isset(self::$adapterMap[$name])) {
  662. if (!isset(self::$configuration['datasources'][$name]['adapter'])) {
  663. throw new PropelException("Unable to find adapter for datasource [" . $name . "].");
  664. }
  665. $db = DBAdapter::factory(self::$configuration['datasources'][$name]['adapter']);
  666. // register the adapter for this name
  667. self::$adapterMap[$name] = $db;
  668. }
  669. return self::$adapterMap[$name];
  670. }
  671. /**
  672. * Sets a database adapter for specified datasource.
  673. *
  674. * @param string $name The datasource name.
  675. * @param DBAdapter $adapter The DBAdapter implementation to use.
  676. */
  677. public static function setDB($name, DBAdapter $adapter)
  678. {
  679. if ($name === null) {
  680. $name = self::getDefaultDB();
  681. }
  682. self::$adapterMap[$name] = $adapter;
  683. }
  684. /**
  685. * Returns the name of the default database.
  686. *
  687. * @return string Name of the default DB
  688. */
  689. public static function getDefaultDB()
  690. {
  691. if (self::$defaultDBName === null) {
  692. // Determine default database name.
  693. self::$defaultDBName = isset(self::$configuration['datasources']['default']) && is_scalar(self::$configuration['datasources']['default']) ? self::$configuration['datasources']['default'] : self::DEFAULT_NAME;
  694. }
  695. return self::$defaultDBName;
  696. }
  697. /**
  698. * Closes any associated resource handles.
  699. *
  700. * This method frees any database connection handles that have been
  701. * opened by the getConnection() method.
  702. */
  703. public static function close()
  704. {
  705. foreach (self::$connectionMap as $idx => $cons) {
  706. // Propel::log("Closing connections for " . $idx, Propel::LOG_DEBUG);
  707. unset(self::$connectionMap[$idx]);
  708. }
  709. }
  710. /**
  711. * Autoload function for loading propel dependencies.
  712. *
  713. * @param string The class name needing loading.
  714. *
  715. * @return boolean TRUE if the class was loaded, false otherwise.
  716. */
  717. public static function autoload($className)
  718. {
  719. if (isset(self::$autoloadMap[$className])) {
  720. require self::$baseDir . self::$autoloadMap[$className];
  721. return true;
  722. }
  723. return false;
  724. }
  725. /**
  726. * Initialize the base directory for the autoloader.
  727. * Avoids a call to dirname(__FILE__) each time self::autoload() is called.
  728. * FIXME put in the constructor if the Propel class ever becomes a singleton
  729. */
  730. public static function initBaseDir()
  731. {
  732. self::$baseDir = dirname(__FILE__) . '/';
  733. }
  734. /**
  735. * Include once a file specified in DOT notation and return unqualified classname.
  736. *
  737. * Typically, Propel uses autoload is used to load classes and expects that all classes
  738. * referenced within Propel are included in Propel's autoload map. This method is only
  739. * called when a specific non-Propel classname was specified -- for example, the
  740. * classname of a validator in the schema.xml. This method will attempt to include that
  741. * class via autoload and then relative to a location on the include_path.
  742. *
  743. * @param string $class dot-path to clas (e.g. path.to.my.ClassName).
  744. * @return string unqualified classname
  745. */
  746. public static function importClass($path) {
  747. // extract classname
  748. if (($pos = strrpos($path, '.')) === false) {
  749. $class = $path;
  750. } else {
  751. $class = substr($path, $pos + 1);
  752. }
  753. // check if class exists, using autoloader to attempt to load it.
  754. if (class_exists($class, $useAutoload=true)) {
  755. return $class;
  756. }
  757. // turn to filesystem path
  758. $path = strtr($path, '.', DIRECTORY_SEPARATOR) . '.php';
  759. // include class
  760. $ret = include_once($path);
  761. if ($ret === false) {
  762. throw new PropelException("Unable to import class: " . $class . " from " . $path);
  763. }
  764. // return qualified name
  765. return $class;
  766. }
  767. /**
  768. * Set your own class-name for Database-Mapping. Then
  769. * you can change the whole TableMap-Model, but keep its
  770. * functionality for Criteria.
  771. *
  772. * @param string The name of the class.
  773. */
  774. public static function setDatabaseMapClass($name)
  775. {
  776. self::$databaseMapClass = $name;
  777. }
  778. /**
  779. * Disable instance pooling.
  780. *
  781. * @return boolean true if the method changed the instance pooling state,
  782. * false if it was already disabled
  783. */
  784. public static function disableInstancePooling()
  785. {
  786. if (!self::$instancePoolingEnabled) {
  787. return false;
  788. }
  789. self::$instancePoolingEnabled = false;
  790. return true;
  791. }
  792. /**
  793. * Enable instance pooling (enabled by default).
  794. *
  795. * @return boolean true if the method changed the instance pooling state,
  796. * false if it was already enabled
  797. */
  798. public static function enableInstancePooling()
  799. {
  800. if (self::$instancePoolingEnabled) {
  801. return false;
  802. }
  803. self::$instancePoolingEnabled = true;
  804. return true;
  805. }
  806. /**
  807. * the instance pooling behaviour. True by default.
  808. *
  809. * @return boolean Whether the pooling is enabled or not.
  810. */
  811. public static function isInstancePoolingEnabled()
  812. {
  813. return self::$instancePoolingEnabled;
  814. }
  815. }
  816. // Since the Propel class is not a true singleton, this code cannot go into the __construct()
  817. Propel::initBaseDir();
  818. spl_autoload_register(array('Propel', 'autoload'));