Преглед изворни кода

ZF-8692 Adding Zend_App_Resource_Multidb

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@20111 44c647ce-9c0f-0410-b52a-842ac1e357ba
freak пре 16 година
родитељ
комит
6e99bada3d

+ 4 - 1
documentation/manual/en/module_specs/Zend_Application-AvailableResources-Db.xml

@@ -7,7 +7,10 @@
         <classname>Zend_Application_Resource_Db</classname> will initialize a
         <classname>Zend_Db</classname> adapter based on the options passed to it. By
         default, it also sets the adapter as the default adapter for use with
-        <classname>Zend_Db_Table</classname>.
+        <classname>Zend_Db_Table</classname>. If you want to use mutliple databases
+        simultaneously, you can use the <link
+        linkend="zend.application.available-resources.multidb">Multidb Resource
+        Plugin</link>.
     </para>
 
     <para>

+ 102 - 0
documentation/manual/en/module_specs/Zend_Application-AvailableResources-Multidb.xml

@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Reviewed: no -->
+<sect2 id="zend.application.available-resources.multidb">
+    <title>Zend_Application_Resource_Multidb</title>
+
+    <para>
+        <classname>Zend_Application_Resource_Multidb</classname> is used to initialize
+        multiple Database connections. You can use the same options as you can with
+        the <link linkend="zend.application.available-resources.db">Db Resource Plugin</link>.
+        However, for specifying a default connection, you can also use the 'default' directive.
+    </para>
+
+    <example id="zend.application.available-resources.multidb.configexample">
+        <title>Setting up multiple Db Connections</title>
+
+        <para>
+            Below is an example <acronym>INI</acronym> configuration that can be used to initialize
+            two Db Connections.
+        </para>
+
+        <programlisting language="ini"><![CDATA[
+[production]
+resources.multidb.db1.adapter = "pdo_mysql"
+resources.multidb.db1.host = "localhost"
+resources.multidb.db1.username = "webuser"
+resources.multidb.db1.password = "XXXX"
+resources.multidb.db1.dbname = "db1"
+
+resources.multidb.db2.adapter = "pdo_pgsql"
+resources.multidb.db2.host = "example.com"
+resources.multidb.db2.username = "dba"
+resources.multidb.db2.password = "notthatpublic"
+resources.multidb.db2.dbname = "db2"
+resources.multidb.db2.default = true
+]]></programlisting>
+    </example>
+
+    <example id="zend.application.available-resources.multidb.retrieveSpecificDb">
+        <title>Retrieving a specific database adapter</title>
+
+        <para>
+            When using this resource plugin you usually will want to retrieve
+            a specific database. This can be done by using the resource's
+            <methodname>getDb()</methodname>. The method
+            <methodname>getDb()</methodname> returns an instance of a class that
+            extends <classname>Zend_Db_Adapter_Abstract</classname>. If you have not
+            set a default database, an exception will be thrown when this method
+            is called without specifying a parameter. 
+         </para>   
+
+        <programlisting language="php"><![CDATA[
+$resource = $bootstrap->getPluginResource('multidb');
+$db1 = $resource->getDb('db1');
+$db2 = $resource->getDb('db2');
+$defaultDb = $resource->getDb();
+]]></programlisting>
+   </example>
+   
+       <example id="zend.application.available-resources.multidb.retrieveSpecificDb">
+        <title>Retrieving the default database adapter</title>
+
+        <para>
+            Additionally, you can retrieve the default database adapter
+            by using the method <methodname>getDefaultDb()</methodname>.
+            If you have not set a default adapter, the first configured db
+            adapter will be returned. Unless you specify 
+            <!-- @TODO: Should I use 'acronym' here? - Freeaqingme -->
+            <acronym>false</acronym> as first parameter, then <acronym>null</acronym>
+            will be returned when no default database adapter was set.
+         </para>   
+
+        <programlisting language="php"><![CDATA[
+$resource = $bootstrap->getPluginResource('multidb');
+$db1 = $resource->getDb('db1');
+$db2 = $resource->getDb('db2');
+$defaultDb = $resource->getDb();
+]]></programlisting>
+   </example>
+
+       <example id="zend.application.available-resources.multidb.retrieveDefaultDb">
+        <title>Retrieving the default database adapter</title>
+
+        <para>
+            Additionally, you can use
+            <methodname>getDefaultDb()</methodname> to retrieve the db that
+            was set as default. If you haven't set one, it will return the first
+            one in the stack.
+        </para>
+        
+        <para>Below is an example that assumes the Multidb resource plugin has been configured
+            with the INI sample above:</para>
+
+        <programlisting language="php"><![CDATA[
+$resource = $bootstrap->getPluginResource('multidb');
+$db2 = $resource->getDefaultDb();
+
+// Same config, but now without a default db:
+$db1 = $resource->getDefaultDb();
+$null = $resource->getDefaultDb(false); // null
+]]></programlisting>
+    </example>
+</sect2>

+ 1 - 0
documentation/manual/en/module_specs/Zend_Application-AvailableResources.xml

@@ -16,6 +16,7 @@
     <xi:include href="Zend_Application-AvailableResources-Log.xml" />
     <xi:include href="Zend_Application-AvailableResources-Mail.xml" />
     <xi:include href="Zend_Application-AvailableResources-Modules.xml" />
+    <xi:include href="Zend_Application-AvailableResources-Multidb.xml" />
     <xi:include href="Zend_Application-AvailableResources-Navigation.xml" />
     <xi:include href="Zend_Application-AvailableResources-Router.xml" />
     <xi:include href="Zend_Application-AvailableResources-Session.xml" />

+ 164 - 0
library/Zend/Application/Resource/Multidb.php

@@ -0,0 +1,164 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Application
+ * @subpackage Resource
+ * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+require_once 'Zend/Application/Resource/ResourceAbstract.php';
+
+require_once 'Zend/Db/Table.php';
+
+/**
+ */
+
+/**
+ * Cache Manager resource
+ *
+ * Example configuration:
+ * <pre>
+ *   resources.multidb.db1.adapter = "pdo_mysql"
+ *   resources.multidb.db1.host = "localhost"
+ *   resources.multidb.db1.username = "webuser"
+ *   resources.multidb.db1.password = "XXXX"
+ *   resources.multidb.db1.dbname = "db1"
+ *   resources.multidb.db1.default = true
+ *   
+ *   resources.multidb.db2.adapter = "pdo_pgsql"
+ *   resources.multidb.db2.host = "example.com"
+ *   resources.multidb.db2.username = "dba"
+ *   resources.multidb.db2.password = "notthatpublic"
+ *   resources.multidb.db2.dbname = "db2"
+ * </pre>
+ *
+ * @category   Zend
+ * @package    Zend_Application
+ * @subpackage Resource
+ * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Application_Resource_Multidb extends Zend_Application_Resource_ResourceAbstract
+{
+    /**
+     * Associative array containing all configured db's
+     * 
+     * @var array
+     */   
+    protected $_dbs = array();
+    
+    /**
+     * An instance of the default db, if set
+     * 
+     * @var null|Zend_Db_Adapter_Abstract
+     */
+    protected $_defaultDb;
+
+    /**
+     * Initialize the Database Connections (instances of Zend_Db_Table_Abstract)
+     *
+     * @return Zend_Application_Resource_Multidb
+     */    
+    public function init() 
+    {
+        $options = $this->getOptions();
+        
+        foreach ($options as $id => $params) {
+            $this->_dbs[$id] = Zend_Db::factory($params['adapter'], $params);
+
+            if ((isset($params['default']) && $params['default'] == true) 
+                // For consistency with the Db Resource Plugin
+                || (isset($params['isDefaultTableAdapter']) 
+                    && $params['isDefaultTableAdapter'] == true)
+            ) {
+                $this->_setDefault($this->_dbs[$id]);
+            }
+        }
+        
+        return $this;
+    }
+
+    /**
+     * Determine if the given db(identifier) is the default db.
+     *
+     * @param  string|Zend_Db_Adapter_Abstract $db The db to determine whether it's set as default
+     * @return boolean True if the given parameter is configured as default. False otherwise
+     */
+    public function isDefault($db)
+    {
+        if(!$db instanceof Zend_Db_Adapter_Abstract) {
+            $db = $this->getDb($db);
+        }
+
+        return $db === $this->_defaultDb;
+    }
+
+    /**
+     * Retrieve the specified database connection
+     * 
+     * @param  null|string|Zend_Db_Adapter_Abstract $db The adapter to retrieve.
+     *                                               Null to retrieve the default connection
+     * @return Zend_Db_Adapter_Abstract
+     * @throws Zend_Application_Resource_Exception if the given parameter could not be found
+     */
+    public function getDb($db = null) 
+    {
+        if ($db === null) {
+            return $this->getDefaultDb();
+        }
+        
+        if (isset($this->_dbs[$db])) {
+            return $this->_dbs[$db];
+        }
+        
+        throw new Zend_Application_Resource_Exception(
+            'A DB adapter was tried to retrieve, but was not configured'
+        );
+    }
+
+    /**
+     * Get the default db connection
+     * 
+     * @param  boolean $justPickOne If true, a random (the first one in the stack)
+     *                           connection is returned if no default was set.
+     *                           If false, null is returned if no default was set.
+     * @return null|Zend_Db_Adapter_Abstract
+     */
+    public function getDefaultDb($justPickOne = true) 
+    {
+        if ($this->_defaultDb !== null) {
+            return $this->_defaultDb;
+        }
+
+        if ($justPickOne) {
+            return reset($this->_dbs); // Return first db in db pool
+        }
+        
+        return null;
+    }
+
+    /**
+     * Set the default db adapter
+     * 
+     * @var Zend_Db_Adapter_Abstract $adapter Adapter to set as default
+     */
+    protected function _setDefault(Zend_Db_Adapter_Abstract $adapter) 
+    {
+        Zend_Db_Table::setDefaultAdapter($adapter);
+        $this->_defaultDb = $adapter;
+    }
+}

+ 2 - 0
tests/Zend/Application/Resource/AllTests.php

@@ -36,6 +36,7 @@ require_once 'Zend/Application/Resource/LocaleTest.php';
 require_once 'Zend/Application/Resource/LogTest.php';
 require_once 'Zend/Application/Resource/MailTest.php';
 require_once 'Zend/Application/Resource/ModulesTest.php';
+require_once 'Zend/Application/Resource/MultidbTest.php';
 require_once 'Zend/Application/Resource/NavigationTest.php';
 require_once 'Zend/Application/Resource/SessionTest.php';
 require_once 'Zend/Application/Resource/ViewTest.php';
@@ -70,6 +71,7 @@ class Zend_Application_Resource_AllTests
         $suite->addTestSuite('Zend_Application_Resource_LogTest');
         $suite->addTestSuite('Zend_Application_Resource_MailTest');
         $suite->addTestSuite('Zend_Application_Resource_ModulesTest');
+        $suite->addTestSuite('Zend_Application_Resource_MultidbTest');
         $suite->addTestSuite('Zend_Application_Resource_NavigationTest');
         $suite->addTestSuite('Zend_Application_Resource_SessionTest');
         $suite->addTestSuite('Zend_Application_Resource_ViewTest');

+ 176 - 0
tests/Zend/Application/Resource/MultidbTest.php

@@ -0,0 +1,176 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Application
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Application_Resource_MailTest::main');
+}
+
+/**
+ * Test helper
+ */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+/**
+ * Zend_Loader_Autoloader
+ */
+require_once 'Zend/Loader/Autoloader.php';
+
+/**
+ * @see Zend_Application_Resource_Multidb
+ */
+require_once 'Zend/Application/Resource/Multidb.php';
+
+require_once 'Zend/Db/Table.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Application
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @group      Zend_Application
+ */
+class Zend_Application_Resource_MultidbTest extends PHPUnit_Framework_TestCase
+{
+    protected $_dbOptions = array('db1' => array('adapter' => 'pdo_mysql','dbname' => 'db1','password' => 'XXXX','username' => 'webuser'),
+                                'db2' => array('adapter' => 'pdo_pgsql', 'dbname' => 'db2', 'password' => 'notthatpublic', 'username' => 'dba'));
+    
+    public static function main()
+    {
+        $suite  = new PHPUnit_Framework_TestSuite(__CLASS__);
+        $result = PHPUnit_TextUI_TestRunner::run($suite);
+    }
+
+    public function setUp()
+    {
+        // Store original autoloaders
+        $this->loaders = spl_autoload_functions();
+        if (!is_array($this->loaders)) {
+            // spl_autoload_functions does not return empty array when no
+            // autoloaders registered...
+            $this->loaders = array();
+        }
+
+        Zend_Loader_Autoloader::resetInstance();
+        $this->autoloader = Zend_Loader_Autoloader::getInstance();
+        $this->application = new Zend_Application('testing');
+        $this->bootstrap = new Zend_Application_Bootstrap_Bootstrap($this->application);
+
+        Zend_Controller_Front::getInstance()->resetInstance();
+    }
+
+    public function tearDown()
+    {
+        Zend_Db_Table::setDefaultAdapter(null);
+        
+        // Restore original autoloaders
+        $loaders = spl_autoload_functions();
+        foreach ($loaders as $loader) {
+            spl_autoload_unregister($loader);
+        }
+
+        foreach ($this->loaders as $loader) {
+            spl_autoload_register($loader);
+        }
+
+        // Reset autoloader instance so it doesn't affect other tests
+        Zend_Loader_Autoloader::resetInstance();
+    }
+
+    public function testInitializationInitializesResourcePluginObject()
+    {
+        $resource = new Zend_Application_Resource_Multidb(array());
+        $resource->setBootstrap($this->bootstrap);
+        $resource->setOptions($this->_dbOptions);
+        $res = $resource->init();
+        $this->assertTrue($res instanceof Zend_Application_Resource_Multidb);
+    }
+    
+    public function testDbsAreSetupCorrectlyObject()
+    {
+        $resource = new Zend_Application_Resource_Multidb(array());
+        $resource->setBootstrap($this->bootstrap);
+        $resource->setOptions($this->_dbOptions);
+        $res = $resource->init();
+        $this->assertTrue($res->getDb('db1') instanceof Zend_Db_Adapter_Pdo_Mysql);
+        $this->assertTrue($res->getDb('db2') instanceof Zend_Db_Adapter_Pdo_Pgsql);
+    }
+    
+    public function testGetDefaultIsSetAndReturnedObject()
+    {
+        $options = $this->_dbOptions;
+        $options['db2']['default'] = true;
+        
+        $resource = new Zend_Application_Resource_Multidb(array());
+        $resource->setBootstrap($this->bootstrap);
+        $resource->setOptions($options);
+        $res = $resource->init();
+        $this->assertTrue($res->getDb() instanceof Zend_Db_Adapter_Pdo_Pgsql);
+        $this->assertTrue($res->isDefault($res->getDb('db2')));
+        $this->assertTrue($res->isDefault('db2'));
+        
+        $options = $this->_dbOptions;
+        $options['db2']['isDefaultTableAdapter'] = true;
+        
+        $resource = new Zend_Application_Resource_Multidb(array());
+        $resource->setBootstrap($this->bootstrap);
+        $resource->setOptions($options);
+        $res = $resource->init();
+        $this->assertTrue($res->getDb() instanceof Zend_Db_Adapter_Pdo_Pgsql);
+        $this->assertTrue($res->isDefault($res->getDb('db2')));
+        $this->assertTrue($res->isDefault('db2'));
+        $this->assertTrue(Zend_Db_Table::getDefaultAdapter() instanceof Zend_Db_Adapter_Pdo_Pgsql);
+        
+    }
+    
+    public function testGetDefaultRandomWhenNoDefaultWasSetObject()
+    {
+        $resource = new Zend_Application_Resource_Multidb(array());
+        $resource->setBootstrap($this->bootstrap);
+        $resource->setOptions($this->_dbOptions);
+        $res = $resource->init();
+        $this->assertTrue($res->getDefaultDb() instanceof Zend_Db_Adapter_Pdo_Mysql);
+        $this->assertTrue($res->getDefaultDb(true) instanceof Zend_Db_Adapter_Pdo_Mysql);
+        $this->assertNull($res->getDefaultDb(false));
+    }
+    
+    public function testGetDbWithFaultyDbNameThrowsException()
+    {
+        $resource = new Zend_Application_Resource_Multidb(array());
+        $resource->setBootstrap($this->bootstrap);
+        $resource->setOptions($this->_dbOptions);
+        $res = $resource->init();
+
+        try {
+            $res->getDb('foobar');
+            $this->fail('An exception should have been thrown');
+        } catch(Zend_Application_Resource_Exception $e) {
+            $this->assertEquals($e->getMessage(), 'A DB adapter was tried to retrieve, but was not configured');
+        }
+    }
+    
+}
+
+if (PHPUnit_MAIN_METHOD == 'Zend_Application_Resource_LogTest::main') {
+    Zend_Application_Resource_LogTest::main();
+}