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