mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-11-04 14:46:19 +08:00 
			
		
		
		
	Added support for cloning a db connection
improved fix #14020 fixes #13890 https://github.com/yiisoft/yii2/pull/14020/files#r115185865 close #14121
This commit is contained in:
		@ -46,7 +46,7 @@ Yii Framework 2 Change Log
 | 
				
			|||||||
- Bug #13790: Fixed error in `\yii\widgets\MaskedInput` JavaScript by raising version required (samdark)
 | 
					- Bug #13790: Fixed error in `\yii\widgets\MaskedInput` JavaScript by raising version required (samdark)
 | 
				
			||||||
- Bug #13807: Fixed `yii\db\QueryBuilder` to inherit subquery params when building a `INSERT INTO ... SELECT` query (sergeymakinen)
 | 
					- Bug #13807: Fixed `yii\db\QueryBuilder` to inherit subquery params when building a `INSERT INTO ... SELECT` query (sergeymakinen)
 | 
				
			||||||
- Bug #13848: `yii\di\Instance::ensure()` wasn't throwing an exception when `$type` is specified and `$reference` object isn't instance of `$type` (c-jonua)
 | 
					- Bug #13848: `yii\di\Instance::ensure()` wasn't throwing an exception when `$type` is specified and `$reference` object isn't instance of `$type` (c-jonua)
 | 
				
			||||||
- Bug #13890: DbTarget log transaction bug (shirase)
 | 
					- Bug #13890: `yii\log\DbTarget` log messages where not written when a database transaction was rolled back, added support for cloning a `yii\db\Connection` (shirase, cebe)
 | 
				
			||||||
- Bug #13901: Fixed passing unused parameter to `formatMessage()` call in `\yii\validators\IpValidator` (Kolyunya)
 | 
					- Bug #13901: Fixed passing unused parameter to `formatMessage()` call in `\yii\validators\IpValidator` (Kolyunya)
 | 
				
			||||||
- Bug #13961: Fixed `unserialize()` error during RBAC rule retrieving from PostgreSQL DBMS (vsguts)
 | 
					- Bug #13961: Fixed `unserialize()` error during RBAC rule retrieving from PostgreSQL DBMS (vsguts)
 | 
				
			||||||
- Bug #14012: `yii\db\pgsql\Schema::findViewNames()` was skipping materialized views (insolita)
 | 
					- Bug #14012: `yii\db\pgsql\Schema::findViewNames()` was skipping materialized views (insolita)
 | 
				
			||||||
 | 
				
			|||||||
@ -1080,4 +1080,18 @@ class Connection extends Component
 | 
				
			|||||||
        $this->close();
 | 
					        $this->close();
 | 
				
			||||||
        return array_keys((array) $this);
 | 
					        return array_keys((array) $this);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Reset the connection after cloning.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __clone()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::__clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->_master = false;
 | 
				
			||||||
 | 
					        $this->_slave = false;
 | 
				
			||||||
 | 
					        $this->pdo = null;
 | 
				
			||||||
 | 
					        $this->_schema = null;
 | 
				
			||||||
 | 
					        $this->_transaction = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -61,9 +61,9 @@ class DbTarget extends Target
 | 
				
			|||||||
    public function export()
 | 
					    public function export()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ($this->db->getTransaction()) {
 | 
					        if ($this->db->getTransaction()) {
 | 
				
			||||||
 | 
					            // create new database connection, if there is an open transaction
 | 
				
			||||||
 | 
					            // to ensure insert statement is not affected by a rollback
 | 
				
			||||||
            $this->db = clone $this->db;
 | 
					            $this->db = clone $this->db;
 | 
				
			||||||
            $this->db->pdo = null;
 | 
					 | 
				
			||||||
            $this->db->open();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $tableName = $this->db->quoteTableName($this->logTable);
 | 
					        $tableName = $this->db->quoteTableName($this->logTable);
 | 
				
			||||||
 | 
				
			|||||||
@ -331,4 +331,41 @@ abstract class ConnectionTest extends DatabaseTestCase
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        $this->assertTrue($thrown, 'An exception should have been thrown by the command.');
 | 
					        $this->assertTrue($thrown, 'An exception should have been thrown by the command.');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Ensure database connection is reset on when a connection is cloned.
 | 
				
			||||||
 | 
					     * Make sure each connection element has its own PDO instance i.e. own connection to the DB.
 | 
				
			||||||
 | 
					     * Also transaction elements should not be shared between two connections.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function testClone()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $connection = $this->getConnection(true, false);
 | 
				
			||||||
 | 
					        $this->assertNull($connection->transaction);
 | 
				
			||||||
 | 
					        $this->assertNull($connection->pdo);
 | 
				
			||||||
 | 
					        $connection->open();
 | 
				
			||||||
 | 
					        $this->assertNull($connection->transaction);
 | 
				
			||||||
 | 
					        $this->assertNotNull($connection->pdo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $conn2 = clone $connection;
 | 
				
			||||||
 | 
					        $this->assertNull($connection->transaction);
 | 
				
			||||||
 | 
					        $this->assertNotNull($connection->pdo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertNull($conn2->transaction);
 | 
				
			||||||
 | 
					        $this->assertNull($conn2->pdo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $connection->beginTransaction();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertNotNull($connection->transaction);
 | 
				
			||||||
 | 
					        $this->assertNotNull($connection->pdo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertNull($conn2->transaction);
 | 
				
			||||||
 | 
					        $this->assertNull($conn2->pdo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $conn3 = clone $connection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertNotNull($connection->transaction);
 | 
				
			||||||
 | 
					        $this->assertNotNull($connection->pdo);
 | 
				
			||||||
 | 
					        $this->assertNull($conn3->transaction);
 | 
				
			||||||
 | 
					        $this->assertNull($conn3->pdo);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -37,7 +37,7 @@ abstract class DbTargetTest extends TestCase
 | 
				
			|||||||
                    'db' => static::getConnection(),
 | 
					                    'db' => static::getConnection(),
 | 
				
			||||||
                    'log' => [
 | 
					                    'log' => [
 | 
				
			||||||
                        'targets' => [
 | 
					                        'targets' => [
 | 
				
			||||||
                            [
 | 
					                            'db' => [
 | 
				
			||||||
                                'class' => 'yii\log\DbTarget',
 | 
					                                'class' => 'yii\log\DbTarget',
 | 
				
			||||||
                                'levels' => ['warning'],
 | 
					                                'levels' => ['warning'],
 | 
				
			||||||
                                'logTable' => self::$logTable,
 | 
					                                'logTable' => self::$logTable,
 | 
				
			||||||
@ -58,9 +58,9 @@ abstract class DbTargetTest extends TestCase
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static function setUpBeforeClass()
 | 
					    public function setUp()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        parent::setUpBeforeClass();
 | 
					        parent::setUp();
 | 
				
			||||||
        $databases = static::getParam('databases');
 | 
					        $databases = static::getParam('databases');
 | 
				
			||||||
        static::$database = $databases[static::$driverName];
 | 
					        static::$database = $databases[static::$driverName];
 | 
				
			||||||
        $pdo_database = 'pdo_' . static::$driverName;
 | 
					        $pdo_database = 'pdo_' . static::$driverName;
 | 
				
			||||||
@ -72,20 +72,14 @@ abstract class DbTargetTest extends TestCase
 | 
				
			|||||||
        static::runConsoleAction('migrate/up', ['migrationPath' => '@yii/log/migrations/', 'interactive' => false]);
 | 
					        static::runConsoleAction('migrate/up', ['migrationPath' => '@yii/log/migrations/', 'interactive' => false]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static function tearDownAfterClass()
 | 
					    public function tearDown()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        self::getConnection()->createCommand()->truncateTable(self::$logTable)->execute();
 | 
				
			||||||
        static::runConsoleAction('migrate/down', ['migrationPath' => '@yii/log/migrations/', 'interactive' => false]);
 | 
					        static::runConsoleAction('migrate/down', ['migrationPath' => '@yii/log/migrations/', 'interactive' => false]);
 | 
				
			||||||
        if (static::$db) {
 | 
					        if (static::$db) {
 | 
				
			||||||
            static::$db->close();
 | 
					            static::$db->close();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Yii::$app = null;
 | 
					 | 
				
			||||||
        parent::tearDownAfterClass();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected function tearDown()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        parent::tearDown();
 | 
					        parent::tearDown();
 | 
				
			||||||
        self::getConnection()->createCommand()->truncateTable(self::$logTable)->execute();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -159,6 +153,11 @@ abstract class DbTargetTest extends TestCase
 | 
				
			|||||||
        $logger->messages[] = $messsageData;
 | 
					        $logger->messages[] = $messsageData;
 | 
				
			||||||
        $logger->flush(true);
 | 
					        $logger->flush(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // current db connection should still have a transaction
 | 
				
			||||||
 | 
					        $this->assertNotNull($db->transaction);
 | 
				
			||||||
 | 
					        // log db connection should not have transaction
 | 
				
			||||||
 | 
					        $this->assertNull(Yii::$app->log->targets['db']->db->transaction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $tx->rollBack();
 | 
					        $tx->rollBack();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $query = (new Query())->select('COUNT(*)')->from(self::$logTable)->where(['category' => 'test', 'message' => 'test']);
 | 
					        $query = (new Query())->select('COUNT(*)')->from(self::$logTable)->where(['category' => 'test', 'message' => 'test']);
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user