propel
[ class tree: propel ] [ index: propel ] [ all elements ]

Source for file Propel.php

Documentation is available at Propel.php

  1. <?php
  2. /*
  3.  *  $Id: Propel.php 821 2007-11-20 12:47:17Z hans $
  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: 821 $
  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.      * @var        string The db name that is specified as the default in the property file
  97.      */
  98.     private static $defaultDBName;
  99.  
  100.     /**
  101.      * @var        array The global cache of database maps
  102.      */
  103.     private static $dbMaps array();
  104.  
  105.     /**
  106.      * @var        array The cache of DB adapter keys
  107.      */
  108.     private static $adapterMap array();
  109.  
  110.     /**
  111.      * @var        array Cache of established connections (to eliminate overhead).
  112.      */
  113.     private static $connectionMap array();
  114.  
  115.     /**
  116.      * @var        array Propel-specific configuration.
  117.      */
  118.     private static $configuration;
  119.  
  120.     /**
  121.      * @var        bool flag to set to true once this class has been initialized
  122.      */
  123.     private static $isInit false;
  124.  
  125.     /**
  126.      * @var        Log optional logger
  127.      */
  128.     private static $logger null;
  129.  
  130.     /**
  131.      * @var        string The name of the database mapper class
  132.      */
  133.     private static $databaseMapClass 'DatabaseMap';
  134.  
  135.     /**
  136.      * @var        bool Whether the object instance pooling is enabled
  137.      */
  138.     private static $instancePoolingEnabled true;
  139.  
  140.     /**
  141.      * @var        array A map of class names and their file paths for autoloading
  142.      */
  143.     private static $autoloadMap array(
  144.         'PropelException' => 'propel/PropelException.php',
  145.  
  146.         'DBAdapter' => 'propel/adapter/DBAdapter.php',
  147.         'DBMSSQL' => 'propel/adapter/DBMSSQL.php',
  148.         'DBMySQL' => 'propel/adapter/DBMySQL.php',
  149.         'DBMySQLi' => 'propel/adapter/DBMySQLi.php',
  150.         'DBNone' => 'propel/adapter/DBNone.php',
  151.         'DBOracle' => 'propel/adapter/DBOracle.php',
  152.         'DBPostgres' => 'propel/adapter/DBPostgres.php',
  153.         'DBSQLite' => 'propel/adapter/DBSQLite.php',
  154.         'DBSybase' => 'propel/adapter/DBSybase.php',
  155.  
  156.         'BasicLogger' => 'propel/logger/BasicLogger.php',
  157.         'MojaviLogAdapter' => 'propel/logger/MojaviLogAdapter.php',
  158.  
  159.         'ColumnMap' => 'propel/map/ColumnMap.php',
  160.         'DatabaseMap' => 'propel/map/DatabaseMap.php',
  161.         'MapBuilder' => 'propel/map/MapBuilder.php',
  162.         'TableMap' => 'propel/map/TableMap.php',
  163.         'ValidatorMap' => 'propel/map/ValidatorMap.php',
  164.  
  165.         'BaseObject' => 'propel/om/BaseObject.php',
  166.         'NodeObject' => 'propel/om/NodeObject.php',
  167.         'Persistent' => 'propel/om/Persistent.php',
  168.         'PreOrderNodeIterator' => 'propel/om/PreOrderNodeIterator.php',
  169.         'NestedSetPreOrderNodeIterator' => 'propel/om/NestedSetPreOrderNodeIterator.php',
  170.         'NestedSetRecursiveIterator' => 'propel/om/NestedSetRecursiveIterator.php',
  171.  
  172.         'BasePeer' => 'propel/util/BasePeer.php',
  173.         'NodePeer' => 'propel/util/NodePeer.php',
  174.         'Criteria' => 'propel/util/Criteria.php',
  175.         'PeerInfo' => 'propel/util/PeerInfo.php',
  176.         'PropelColumnTypes' => 'propel/util/PropelColumnTypes.php',
  177.         'PropelPDO' => 'propel/util/PropelPDO.php',
  178.         'PropelPager' => 'propel/util/PropelPager.php',
  179.         'PropelDateTime' => 'propel/util/PropelDateTime.php',
  180.  
  181.         'BasicValidator' => 'propel/validator/BasicValidator.php',
  182.         'MatchValidator' => 'propel/validator/MatchValidator.php',
  183.         'MaxLengthValidator' => 'propel/validator/MaxLengthValidator.php',
  184.         'MaxValueValidator' => 'propel/validator/MaxValueValidator.php',
  185.         'MinLengthValidator' => 'propel/validator/MinLengthValidator.php',
  186.         'MinValueValidator' => 'propel/validator/MinValueValidator.php',
  187.         'NotMatchValidator' => 'propel/validator/NotMatchValidator.php',
  188.         'RequiredValidator' => 'propel/validator/RequiredValidator.php',
  189.         'UniqueValidator' => 'propel/validator/UniqueValidator.php',
  190.         'ValidValuesValidator' => 'propel/validator/ValidValuesValidator.php',
  191.         'ValidationFailed' => 'propel/validator/ValidationFailed.php',
  192.     );
  193.  
  194.     /**
  195.      * Initializes Propel
  196.      *
  197.      * @throws     PropelException Any exceptions caught during processing will be
  198.      *                              rethrown wrapped into a PropelException.
  199.      */
  200.     public static function initialize()
  201.     {
  202.         if (self::$configuration === null{
  203.             throw new PropelException("Propel cannot be initialized without "
  204.             . "a valid configuration. Please check the log files "
  205.             . "for further details.");
  206.         }
  207.  
  208.         self::configureLogging();
  209.  
  210.         // Support having the configuration stored within a 'propel' sub-section or at the top-level
  211.         if (isset(self::$configuration['propel']&& is_array(self::$configuration['propel'])) {
  212.             self::$configuration self::$configuration['propel'];
  213.         }
  214.  
  215.         // reset the connection map (this should enable runtime changes of connection params)
  216.         self::$connectionMap array();
  217.  
  218.         foreach (self::$configuration['datasources'as $key => $datasource{
  219.             if ($key != 'default' && isset($datasource['classes'])) {
  220.                 // merge the classes to the autoload map
  221.                 self::$autoloadMap array_merge($datasource['classes']self::$autoloadMap);
  222.             }
  223.         }
  224.  
  225.         self::$isInit true;
  226.     }
  227.  
  228.     /**
  229.      * Configure Propel using an INI or PHP (array) config file.
  230.      *
  231.      * @param      string Path (absolute or relative to include_path) to config file.
  232.      *
  233.      * @throws     PropelException If configuration file cannot be opened.
  234.      *                              (E_WARNING probably will also be raised by PHP)
  235.      */
  236.     public static function configure($configFile)
  237.     {
  238.         self::$configuration include($configFile);
  239.         if (self::$configuration === false{
  240.             throw new PropelException("Unable to open configuration file: " var_export($configFiletrue));
  241.         }
  242.     }
  243.  
  244.     /**
  245.      * Configure the logging system, if config is specified in the runtime configuration.
  246.      */
  247.     protected static function configureLogging()
  248.     {
  249.         if (self::$logger === null{
  250.             if (isset(self::$configuration['log']&& is_array(self::$configuration['log']&& count(self::$configuration['log'])) {
  251.                 include_once 'Log.php'// PEAR Log class
  252.                 $c self::$configuration['log'];
  253.                 $type = isset($c['type']$c['type''file';
  254.                 $name = isset($c['name']$c['name''./propel.log';
  255.                 $ident = isset($c['ident']$c['ident''propel';
  256.                 $conf = isset($c['conf']$c['conf'array();
  257.                 $level = isset($c['level']$c['level'PEAR_LOG_DEBUG;
  258.                 self::$logger Log::singleton($type$name$ident$conf$level);
  259.             // if isset()
  260.         }
  261.     }
  262.  
  263.     /**
  264.      * Initialization of Propel with an INI or PHP (array) configuration file.
  265.      *
  266.      * @param      string $c The Propel configuration file path.
  267.      *
  268.      * @throws     PropelException Any exceptions caught during processing will be
  269.      *                              rethrown wrapped into a PropelException.
  270.      */
  271.     public static function init($c)
  272.     {
  273.         self::configure($c);
  274.         self::initialize();
  275.     }
  276.  
  277.     /**
  278.      * Determine whether Propel has already been initialized.
  279.      *
  280.      * @return     bool True if Propel is already initialized.
  281.      */
  282.     public static function isInit()
  283.     {
  284.         return self::$isInit;
  285.     }
  286.  
  287.     /**
  288.      * Sets the configuration for Propel and all dependencies.
  289.      *
  290.      * @param      array The Configuration
  291.      */
  292.     public static function setConfiguration($c)
  293.     {
  294.         self::$configuration $c;
  295.     }
  296.  
  297.     /**
  298.      * Get the configuration for this component.
  299.      *
  300.      * @return     array The Configuration
  301.      */
  302.     public static function getConfiguration()
  303.     {
  304.         return self::$configuration;
  305.     }
  306.  
  307.     /**
  308.      * Override the configured logger.
  309.      *
  310.      * This is primarily for things like unit tests / debugging where
  311.      * you want to change the logger without altering the configuration file.
  312.      *
  313.      * You can use any logger class that implements the propel.logger.BasicLogger
  314.      * interface.  This interface is based on PEAR::Log, so you can also simply pass
  315.      * a PEAR::Log object to this method.
  316.      *
  317.      * @param      object The new logger to use. ([PEAR] Log or BasicLogger)
  318.      */
  319.     public static function setLogger($logger)
  320.     {
  321.         self::$logger $logger;
  322.     }
  323.  
  324.     /**
  325.      * Returns true if a logger, for example PEAR::Log, has been configured,
  326.      * otherwise false.
  327.      *
  328.      * @return     bool True if Propel uses logging
  329.      */
  330.     public static function hasLogger()
  331.     {
  332.         return (self::$logger !== null);
  333.     }
  334.  
  335.     /**
  336.      * Get the configured logger.
  337.      *
  338.      * @return     object Configured log class ([PEAR] Log or BasicLogger).
  339.      */
  340.     public static function logger()
  341.     {
  342.         return self::$logger;
  343.     }
  344.  
  345.     /**
  346.      * Logs a message
  347.      * If a logger has been configured, the logger will be used, otherwrise the
  348.      * logging message will be discarded without any further action
  349.      *
  350.      * @param      string The message that will be logged.
  351.      * @param      string The logging level.
  352.      *
  353.      * @return     bool True if the message was logged successfully or no logger was used.
  354.      */
  355.     public static function log($message$level self::LOG_DEBUG)
  356.     {
  357.         if (self::hasLogger()) {
  358.             $logger self::logger();
  359.             switch ($level{
  360.                 case self::LOG_EMERG:
  361.                     return $logger->log($message$level);
  362.                 case self::LOG_ALERT:
  363.                     return $logger->alert($message);
  364.                 case self::LOG_CRIT:
  365.                     return $logger->crit($message);
  366.                 case self::LOG_ERR:
  367.                     return $logger->err($message);
  368.                 case self::LOG_WARNING:
  369.                     return $logger->warning($message);
  370.                 case self::LOG_NOTICE:
  371.                     return $logger->notice($message);
  372.                 case self::LOG_INFO:
  373.                     return $logger->info($message);
  374.                 default:
  375.                     return $logger->debug($message);
  376.             }
  377.         }
  378.         return true;
  379.     }
  380.  
  381.     /**
  382.      * Returns the database map information. Name relates to the name
  383.      * of the connection pool to associate with the map.
  384.      *
  385.      * The database maps are "registered" by the generated map builder classes.
  386.      *
  387.      * @param      string The name of the database corresponding to the DatabaseMap to retrieve.
  388.      *
  389.      * @return     DatabaseMap The named <code>DatabaseMap</code>.
  390.      *
  391.      * @throws     PropelException - if database map is null or propel was not initialized properly.
  392.      */
  393.     public static function getDatabaseMap($name null)
  394.     {
  395.         if ($name === null{
  396.             $name self::getDefaultDB();
  397.             if ($name === null{
  398.                 throw new PropelException("DatabaseMap name was null!");
  399.             }
  400.         }
  401.  
  402.         if (!isset(self::$dbMaps[$name])) {
  403.             $clazz self::$databaseMapClass;
  404.             self::$dbMaps[$namenew $clazz($name);
  405.         }
  406.  
  407.         return self::$dbMaps[$name];
  408.     }
  409.     
  410.     /**
  411.      * Sets the database map object to use for specified datasource.
  412.      *
  413.      * @param      string $name The datasource name.
  414.      * @param      DatabaseMap $map The database map object to use for specified datasource.
  415.      */
  416.     public static function setDatabaseMap($nameDatabaseMap $map)
  417.     {
  418.         if ($name === null{
  419.             $name self::getDefaultDB();
  420.         }
  421.         self::$dbMaps[$name$map;
  422.     }
  423.  
  424.     /**
  425.      * Gets an already-opened PDO connection or opens a new one for passed-in db name.
  426.      *
  427.      * @param      string The name that is used to look up the DSN from the runtime properties file.
  428.      *
  429.      * @return     PDO A database connection
  430.      *
  431.      * @throws     PropelException - if no conneciton params, or lower-level exception caught when trying to connect.
  432.      */
  433.     public static function getConnection($name null)
  434.     {
  435.         if ($name === null{
  436.             $name self::getDefaultDB();
  437.         }
  438.  
  439.         if (!isset(self::$connectionMap[$name])) {
  440.  
  441.             $conparams = isset(self::$configuration['datasources'][$name]['connection']self::$configuration['datasources'][$name]['connection'null;
  442.             if ($conparams === null{
  443.                 throw new PropelException('No connection information in your runtime configuration file for datasource ['.$name.']');
  444.             }
  445.  
  446.             $dsn $conparams['dsn'];
  447.             if ($dsn === null{
  448.                 throw new PropelException('No dsn specified in your connection parameters for datasource ['.$name.']');
  449.             }
  450.  
  451.             $user = isset($conparams['user']$conparams['user'null;
  452.             $password = isset($conparams['password']$conparams['password'null;
  453.  
  454.             // load any driver options from the config file
  455.             // driver options are those PDO settings that have to be passed during the connection construction
  456.             $driver_options array();
  457.             if isset($conparams['options']&& is_array($conparams['options']) ) {
  458.                 try {
  459.                     self::processDriverOptions$conparams['options']$driver_options );
  460.                 catch (PropelException $e{
  461.                     throw new PropelException('Error processing driver options for datasource ['.$name.']'$e);
  462.                 }
  463.             }
  464.  
  465.             try {
  466.                 $con new PropelPDO($dsn$user$password$driver_options);
  467.                 $con->setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION);
  468.                 self::$connectionMap[$name$con;
  469.             catch (PDOException $e{
  470.                 throw new PropelException("Unable to open PDO connection"$e);
  471.             }
  472.  
  473.             // load any connection options from the config file
  474.             // connection attributes are those PDO flags that have to be set on the initialized connection
  475.             if (isset($conparams['attributes']&& is_array($conparams['attributes'])) {
  476.                 $attributes array();
  477.                 try {
  478.                     self::processDriverOptions$conparams['attributes']$attributes );
  479.                 catch (PropelException $e{
  480.                     throw new PropelException('Error processing connection attributes for datasource ['.$name.']'$e);
  481.                 }
  482.                 foreach ($attributes as $key => $value{
  483.                     $con->setAttribute($key$value);
  484.                 }
  485.             }
  486.  
  487.             // initialize the connection using the settings provided in the config file. this could be a "SET NAMES <charset>" query for MySQL, for instance
  488.             $adapter self::getDB($name);
  489.             $adapter->initConnection($conisset($conparams['settings']&& is_array($conparams['settings']$conparams['settings'array());
  490.         }
  491.  
  492.         return self::$connectionMap[$name];
  493.     }
  494.  
  495.     /**
  496.      * Sets the connection to use for specified datasource.
  497.      *
  498.      * @param      string $name The datasource name.
  499.      * @param      PropelPDO $con The PDO connection object to use for specified datasource.
  500.      */
  501.     public static function setConnection($namePropelPDO $con)
  502.     {
  503.         if ($name === null{
  504.             $name self::getDefaultDB();
  505.         }
  506.         self::$connectionMap[$name$con;
  507.     }
  508.  
  509.     /**
  510.      * Internal function to handle driver options or conneciton attributes in PDO.
  511.      *
  512.      * Process the INI file flags to be passed to each connection.
  513.      *
  514.      * @param      array Where to find the list of constant flags and their new setting.
  515.      * @param      array Put the data into here
  516.      *
  517.      * @throws     PropelException If invalid options were specified.
  518.      */
  519.     private static function processDriverOptions($source&$write_to)
  520.     {
  521.         foreach ($source as $option => $optiondata{
  522.             if (is_string($option&& strpos($option'PDO::'!== false{
  523.                 $key $option;
  524.             elseif (is_string($option)) {
  525.                 $key 'PDO::' $option;
  526.             }
  527.             if (!defined($key)) {
  528.                 throw new PropelException("Invalid PDO option/attribute name specified: ".$key);
  529.             }
  530.             $key constant($key);
  531.  
  532.             $value $optiondata['value'];
  533.             if (is_string($value&& strpos($value'PDO::'!== false{
  534.                 if (!defined($value)) {
  535.                     throw new PropelException("Invalid PDO option/attribute value specified: ".$value);
  536.                 }
  537.               &nbs