Propel.php 29 KB

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