Source for file Manager.php

Documentation is available at Manager.php

  1. <?php
  2. /*
  3.  *  $Id: Manager.php 2290 2007-08-29 21:57:46Z zYne $
  4.  *
  5.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  6.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  7.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  8.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  9.  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  10.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  11.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  12.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  13.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  14.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  15.  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16.  *
  17.  * This software consists of voluntary contributions made by many individuals
  18.  * and is licensed under the LGPL. For more information, see
  19.  * <http://www.phpdoctrine.com>.
  20.  */
  21. /**
  22.  *
  23.  * Doctrine_Manager is the base component of all doctrine based projects.
  24.  * It opens and keeps track of all connections (database connections).
  25.  *
  26.  * @package     Doctrine
  27.  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
  28.  * @category    Object Relational Mapping
  29.  * @link        www.phpdoctrine.com
  30.  * @since       1.0
  31.  * @version     $Revision: 2290 $
  32.  * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
  33.  */
  34. class Doctrine_Manager extends Doctrine_Configurable implements CountableIteratorAggregate
  35. {
  36.     /**
  37.      * @var array $connections      an array containing all the opened connections
  38.      */
  39.     protected $_connections   = array();
  40.     /**
  41.      * @var array $bound            an array containing all components that have a bound connection
  42.      */
  43.     protected $_bound         = array();
  44.     /**
  45.      * @var integer $index          the incremented index
  46.      */
  47.     protected $_index         = 0;
  48.     /**
  49.      * @var integer $currIndex      the current connection index
  50.      */
  51.     protected $_currIndex     = 0;
  52.     /**
  53.      * @var string $root            root directory
  54.      */
  55.     protected $_root;
  56.     /**
  57.      * @var array $_integrityActions    an array containing all registered integrity actions
  58.      *                                   used when emulating these actions
  59.      */
  60.     protected $_integrityActions = array();
  61.     
  62.     protected static $driverMap array('oci' => 'oracle');
  63.     /**
  64.      * constructor
  65.      *
  66.      * this is private constructor (use getInstance to get an instance of this class)
  67.      */
  68.     private function __construct()
  69.     {
  70.         $this->_root = dirname(__FILE__);
  71.  
  72.     }
  73.     public function addDeleteAction($componentName$foreignComponent$action)
  74.     {
  75.         $this->_integrityActions[$componentName]['onDelete'][$foreignComponent$action;
  76.     }
  77.     public function addUpdateAction($componentName$foreignComponent$action)
  78.     {
  79.         $this->_integrityActions[$componentName]['onUpdate'][$foreignComponent$action;
  80.     }
  81.     public function getDeleteActions($componentName)
  82.     {
  83.         if isset($this->_integrityActions[$componentName]['onDelete'])) {
  84.             return null;
  85.         }
  86.         
  87.         return $this->_integrityActions[$componentName]['onDelete'];
  88.     }
  89.     public function getUpdateActions($componentName)
  90.     {
  91.         if isset($this->_integrityActions[$componentName]['onUpdate'])) {
  92.             return null;
  93.         }
  94.         
  95.         return $this->_integrityActions[$componentName]['onUpdate'];
  96.     }
  97.     /**
  98.      * setDefaultAttributes
  99.      * sets default attributes
  100.      *
  101.      * @return boolean 
  102.      */
  103.     public function setDefaultAttributes()
  104.     {
  105.         static $init false;
  106.         if $init{
  107.             $init true;
  108.             $attributes array(
  109.                         Doctrine::ATTR_CACHE            => null,
  110.                         Doctrine::ATTR_LOAD_REFERENCES  => true,
  111.                         Doctrine::ATTR_LISTENER         => new Doctrine_EventListener(),
  112.                         Doctrine::ATTR_RECORD_LISTENER  => new Doctrine_Record_Listener(),
  113.                         Doctrine::ATTR_THROW_EXCEPTIONS => true,
  114.                         Doctrine::ATTR_LOCKMODE         => 1,
  115.                         Doctrine::ATTR_VLD              => false,
  116.                         Doctrine::ATTR_AUTO_LENGTH_VLD  => true,
  117.                         Doctrine::ATTR_AUTO_TYPE_VLD    => true,
  118.                         Doctrine::ATTR_QUERY_LIMIT      => Doctrine::LIMIT_RECORDS,
  119.                         Doctrine::ATTR_IDXNAME_FORMAT   => "%s_idx",
  120.                         Doctrine::ATTR_SEQNAME_FORMAT   => "%s_seq",
  121.                         Doctrine::ATTR_QUOTE_IDENTIFIER => false,
  122.                         Doctrine::ATTR_SEQCOL_NAME      => 'id',
  123.                         Doctrine::ATTR_PORTABILITY      => Doctrine::PORTABILITY_ALL,
  124.                         Doctrine::ATTR_EXPORT           => Doctrine::EXPORT_ALL,
  125.                         Doctrine::ATTR_DECIMAL_PLACES   => 2,
  126.                         );
  127.             foreach ($attributes as $attribute => $value{
  128.                 $old $this->getAttribute($attribute);
  129.                 if ($old === null{
  130.                     $this->setAttribute($attribute,$value);
  131.                 }
  132.             }
  133.             return true;
  134.         }
  135.         return false;
  136.     }
  137.     /**
  138.      * returns the root directory of Doctrine
  139.      *
  140.      * @return string 
  141.      */
  142.     final public function getRoot()
  143.     {
  144.         return $this->_root;
  145.     }
  146.     /**
  147.      * getInstance
  148.      * returns an instance of this class
  149.      * (this class uses the singleton pattern)
  150.      *
  151.      * @return Doctrine_Manager 
  152.      */
  153.     public static function getInstance()
  154.     {
  155.         static $instance;
  156.         if isset($instance)) {
  157.             $instance new self();
  158.         }
  159.         return $instance;
  160.     }
  161.     /**
  162.      * connection
  163.      *
  164.      * if the adapter parameter is set this method acts as
  165.      * a short cut for Doctrine_Manager::getInstance()->openConnection($adapter, $name);
  166.      *
  167.      * if the adapter paramater is not set this method acts as
  168.      * a short cut for Doctrine_Manager::getInstance()->getCurrentConnection()
  169.      *
  170.      * @param PDO|Doctrine_Adapter_Interface$adapter   database driver
  171.      * @param string $name                              name of the connection, if empty numeric key is used
  172.      * @throws Doctrine_Manager_Exception               if trying to bind a connection with an existing name
  173.      * @return Doctrine_Connection 
  174.      */
  175.     public static function connection($adapter null$name null)
  176.     {
  177.         if ($adapter == null{
  178.             return Doctrine_Manager::getInstance()->getCurrentConnection();
  179.         else {
  180.             return Doctrine_Manager::getInstance()->openConnection($adapter$name);
  181.         }
  182.     }
  183.     /**
  184.      * openConnection
  185.      * opens a new connection and saves it to Doctrine_Manager->connections
  186.      *
  187.      * @param PDO|Doctrine_Adapter_Interface$adapter   database driver
  188.      * @param string $name                              name of the connection, if empty numeric key is used
  189.      * @throws Doctrine_Manager_Exception               if trying to bind a connection with an existing name
  190.      * @throws Doctrine_Manager_Exception               if trying to open connection for unknown driver
  191.      * @return Doctrine_Connection 
  192.      */
  193.     public function openConnection($adapter$name null$setCurrent true)
  194.     {
  195.         if (is_object($adapter)) {
  196.             if ($adapter instanceof PDO&& in_array('Doctrine_Adapter_Interface'class_implements($adapter))) {
  197.                 throw new Doctrine_Manager_Exception("First argument should be an instance of PDO or implement Doctrine_Adapter_Interface");
  198.             }
  199.  
  200.             $driverName $adapter->getAttribute(Doctrine::ATTR_DRIVER_NAME);
  201.         elseif (is_array($adapter)) {
  202.             if isset($adapter[0])) {
  203.                 throw new Doctrine_Manager_Exception('Empty data source name given.');
  204.             }
  205.             $e explode(':'$adapter[0]);
  206.  
  207.             if($e[0== 'uri'{
  208.                 $e[0'odbc';
  209.             }
  210.  
  211.             $parts['dsn']    $adapter[0];
  212.             $parts['scheme'$e[0];
  213.             $parts['user']   (isset($adapter[1])) $adapter[1null;
  214.             $parts['pass']   (isset($adapter[2])) $adapter[2null;
  215.             
  216.             $driverName $e[0];
  217.             $adapter $parts;
  218.         else {
  219.             $parts $this->parseDsn($adapter);
  220.             
  221.             $driverName $parts['scheme'];
  222.             
  223.             $adapter $parts;
  224.         }
  225.  
  226.         // initialize the default attributes
  227.         $this->setDefaultAttributes();
  228.  
  229.         if ($name !== null{
  230.             $name = (string) $name;
  231.             if (isset($this->_connections[$name])) {
  232.                 return $this->_connections[$name];
  233.             }
  234.         else {
  235.             $name $this->_index;
  236.             $this->_index++;
  237.         }
  238.  
  239.         $drivers array('mysql'    => 'Doctrine_Connection_Mysql',
  240.                          'sqlite'   => 'Doctrine_Connection_Sqlite',
  241.                          'pgsql'    => 'Doctrine_Connection_Pgsql',
  242.                          'oci'      => 'Doctrine_Connection_Oracle',
  243.                          'oci8'     => 'Doctrine_Connection_Oracle',
  244.                          'oracle'   => 'Doctrine_Connection_Oracle',
  245.                          'mssql'    => 'Doctrine_Connection_Mssql',
  246.                          'dblib'    => 'Doctrine_Connection_Mssql',
  247.                          'firebird' => 'Doctrine_Connection_Firebird',
  248.                          'informix' => 'Doctrine_Connection_Informix',
  249.                          'mock'     => 'Doctrine_Connection_Mock');
  250.         if isset($drivers[$driverName])) {
  251.             throw new Doctrine_Manager_Exception('Unknown driver ' $driverName);
  252.         }
  253.         $className $drivers[$driverName];
  254.         $conn new $className($this$adapter);
  255.  
  256.         $this->_connections[$name$conn;
  257.  
  258.         if ($setCurrent{
  259.             $this->_currIndex $name;
  260.         }
  261.         return $this->_connections[$name];
  262.     }
  263.     /**
  264.      * parseDsn
  265.      *
  266.      * @param string $dsn 
  267.      * @return array Parsed contents of DSN
  268.      */
  269.     public function parseDsn($dsn)
  270.     {
  271.         // silence any warnings
  272.         $parts @parse_url($dsn);
  273.  
  274.         $names array('dsn''scheme''host''port''user''pass''path''query''fragment');
  275.  
  276.         foreach ($names as $name{
  277.             if isset($parts[$name])) {
  278.                 $parts[$namenull;
  279.             }
  280.         }
  281.  
  282.         if (count($parts== || isset($parts['scheme'])) {
  283.             throw new Doctrine_Manager_Exception('Empty data source name');
  284.         }
  285.  
  286.         switch ($parts['scheme']{
  287.             case 'sqlite':
  288.             case 'sqlite2':
  289.             case 'sqlite3':
  290.                 if (isset($parts['host']&& $parts['host'== ':memory'{
  291.                     $parts['database'':memory:';
  292.                     $parts['dsn']      'sqlite::memory:';
  293.                 else {
  294.                     $parts['database'$parts['path'];
  295.                     $parts['dsn'$parts['scheme'':' $parts['path'];         
  296.                 }
  297.  
  298.                 break;
  299.             case 'mysql':
  300.             case 'informix':
  301.             case 'oci8':
  302.             case 'oci':
  303.             case 'mssql':
  304.             case 'firebird':
  305.             case 'dblib':
  306.             case 'pgsql':
  307.             case 'odbc':
  308.             case 'mock':
  309.             case 'oracle':
  310.                 if isset($parts['path']|| $parts['path'== '/'{
  311.                     throw new Doctrine_Manager_Exception('No database available in data source name');
  312.                 }
  313.                 if (isset($parts['path'])) {
  314.                     $parts['database'substr($parts['path']1);
  315.                 }
  316.                 if isset($parts['host'])) {
  317.                     throw new Doctrine_Manager_Exception('No hostname set in data source name');
  318.                 }
  319.                 
  320.                 if (isset(self::$driverMap[$parts['scheme']])) {
  321.                     $parts['scheme'self::$driverMap[$parts['scheme']];
  322.                 }
  323.  
  324.                 $parts['dsn'$parts['scheme'':host='
  325.                               . $parts['host'';dbname='
  326.                               . $parts['database'];
  327.                 
  328.                 if (isset($parts['port'])) {
  329.                     // append port to dsn if supplied
  330.                     $parts['dsn'.= ';port=' $parts['port'];
  331.                 }
  332.                 break;
  333.             default:
  334.                 throw new Doctrine_Manager_Exception('Unknown driver '.$parts['scheme']);
  335.         }
  336.  
  337.  
  338.         return $parts;
  339.     }
  340.     /**
  341.      * getConnection
  342.      * @param integer $index 
  343.      * @return object Doctrine_Connection 
  344.      * @throws Doctrine_Manager_Exception   if trying to get a non-existent connection
  345.      */
  346.     public function getConnection($name)
  347.     {
  348.         if isset($this->_connections[$name])) {
  349.             throw new Doctrine_Manager_Exception('Unknown connection: ' $name);
  350.         }
  351.  
  352.         return $this->_connections[$name];
  353.     }
  354.     /**
  355.      * getComponentAlias
  356.      * retrieves the alias for given component name
  357.      * if the alias couldn't be found, this method returns the given
  358.      * component name
  359.      *
  360.      * @param string $componentName 
  361.      * @return string                   the component alias
  362.      */
  363.     public function getComponentAlias($componentName)
  364.     {
  365.         if (isset($this->componentAliases[$componentName])) {
  366.             return $this->componentAliases[$componentName];
  367.         }
  368.  
  369.         return $componentName;
  370.     }
  371.     /**
  372.      * sets an alias for given component name
  373.      * very useful when building a large framework with a possibility
  374.      * to override any given class
  375.      *
  376.      * @param string $componentName         the name of the component
  377.      * @param string $alias 
  378.      * @return Doctrine_Manager 
  379.      */
  380.     public function setComponentAlias($componentName$alias)
  381.     {
  382.         $this->componentAliases[$componentName$alias;
  383.  
  384.         return $this;
  385.     }
  386.     /**
  387.      * getConnectionName
  388.      *
  389.      * @param Doctrine_Connection $conn     connection object to be searched for
  390.      * @return string                       the name of the connection
  391.      */
  392.     public function getConnectionName(Doctrine_Connection $conn)
  393.     {
  394.         return array_search($conn$this->_connectionstrue);
  395.     }
  396.     /**
  397.      * bindComponent
  398.      * binds given component to given connection
  399.      * this means that when ever the given component uses a connection
  400.      * it will be using the bound connection instead of the current connection
  401.      *
  402.      * @param string $componentName 
  403.      * @param string $connectionName 
  404.      * @return boolean 
  405.      */
  406.     public function bindComponent($componentName$connectionName)
  407.     {
  408.         $this->_bound[$componentName$connectionName;
  409.     }
  410.     /**
  411.      * getConnectionForComponent
  412.      *
  413.      * @param string $componentName 
  414.      * @return Doctrine_Connection 
  415.      */
  416.     public function getConnectionForComponent($componentName null)
  417.     {
  418.         if (isset($this->_bound[$componentName])) {
  419.             return $this->getConnection($this->_bound[$componentName]);
  420.         }
  421.         return $this->getCurrentConnection();
  422.     }
  423.     /**
  424.      * getTable
  425.      * this is the same as Doctrine_Connection::getTable() except
  426.      * that it works seamlessly in multi-server/connection environment
  427.      *
  428.      * @see Doctrine_Connection::getTable()
  429.      * @param string $componentName 
  430.      * @return Doctrine_Table 
  431.      */
  432.     public function getTable($componentName)
  433.     {
  434.         return $this->getConnectionForComponent($componentName)->getTable($componentName);
  435.     }
  436.     /**
  437.      * table
  438.      * this is the same as Doctrine_Connection::getTable() except
  439.      * that it works seamlessly in multi-server/connection environment
  440.      *
  441.      * @see Doctrine_Connection::getTable()
  442.      * @param string $componentName 
  443.      * @return Doctrine_Table 
  444.      */
  445.     public static function table($componentName)
  446.     {
  447.         return Doctrine_Manager::getInstance()
  448.                ->getConnectionForComponent($componentName)
  449.                ->getTable($componentName);
  450.     }
  451.     /**
  452.      * closes the connection
  453.      *
  454.      * @param Doctrine_Connection $connection 
  455.      * @return void 
  456.      */
  457.     public function closeConnection(Doctrine_Connection $connection)
  458.     {
  459.         $connection->close();
  460.  
  461.         $key array_search($connection$this->_connectionstrue);
  462.  
  463.         if ($key !== false{
  464.             unset($this->_connections[$key]);
  465.         }
  466.         $this->_currIndex key($this->_connections);
  467.  
  468.         unset($connection);
  469.     }
  470.     /**
  471.      * getConnections
  472.      * returns all opened connections
  473.      *
  474.      * @return array 
  475.      */
  476.     public function getConnections()
  477.     {
  478.         return $this->_connections;
  479.     }
  480.     /**
  481.      * setCurrentConnection
  482.      * sets the current connection to $key
  483.      *
  484.      * @param mixed $key                        the connection key
  485.      * @throws InvalidKeyException
  486.      * @return void 
  487.      */
  488.     public function setCurrentConnection($key)
  489.     {
  490.         $key = (string) $key;
  491.         if isset($this->_connections[$key])) {
  492.             throw new InvalidKeyException();
  493.         }
  494.         $this->_currIndex $key;
  495.     }
  496.     /**
  497.      * contains
  498.      * whether or not the manager contains specified connection
  499.      *
  500.      * @param mixed $key                        the connection key
  501.      * @return boolean 
  502.      */
  503.     public function contains($key)
  504.     {
  505.         return isset($this->_connections[$key]);
  506.     }
  507.     /**
  508.      * count
  509.      * returns the number of opened connections
  510.      *
  511.      * @return integer 
  512.      */
  513.     public function count()
  514.     {
  515.         return count($this->_connections);
  516.     }
  517.     /**
  518.      * getIterator
  519.      * returns an ArrayIterator that iterates through all connections
  520.      *
  521.      * @return ArrayIterator 
  522.      */
  523.     public function getIterator()
  524.     {
  525.         return new ArrayIterator($this->_connections);
  526.     }
  527.     /**
  528.      * getCurrentConnection
  529.      * returns the current connection
  530.      *
  531.      * @throws Doctrine_Connection_Exception       if there are no open connections
  532.      * @return Doctrine_Connection 
  533.      */
  534.     public function getCurrentConnection()
  535.     {
  536.         $i $this->_currIndex;
  537.         if isset($this->_connections[$i])) {
  538.             throw new Doctrine_Connection_Exception();
  539.         }
  540.         return $this->_connections[$i];
  541.     }
  542.     /**
  543.      * __toString
  544.      * returns a string representation of this object
  545.      *
  546.      * @return string 
  547.      */
  548.     public function __toString()
  549.     {
  550.         $r["<pre>";
  551.         $r["Doctrine_Manager";
  552.         $r["Connections : ".count($this->_connections);
  553.         $r["</pre>";
  554.         return implode("\n",$r);
  555.     }
  556. }