TestUtil.php 7.02 KB
Newer Older
1
<?php
romanb's avatar
romanb committed
2

Michael Moravec's avatar
Michael Moravec committed
3 4
declare(strict_types=1);

5
namespace Doctrine\DBAL\Tests;
romanb's avatar
romanb committed
6

7
use Doctrine\DBAL\Connection;
8
use Doctrine\DBAL\DriverManager;
9
use Doctrine\DBAL\Platforms\AbstractPlatform;
10
use Doctrine\DBAL\Platforms\OraclePlatform;
11
use InvalidArgumentException;
12
use PHPUnit\Framework\Assert;
13

14 15 16
use function array_keys;
use function array_map;
use function array_values;
17 18
use function explode;
use function extension_loaded;
19 20
use function implode;
use function is_string;
21
use function unlink;
22

romanb's avatar
romanb committed
23 24 25
/**
 * TestUtil is a class with static utility methods used during tests.
 */
26
class TestUtil
27
{
Sergei Morozov's avatar
Sergei Morozov committed
28
    /** @var bool Whether the database schema is initialized. */
29 30
    private static $initialized = false;

romanb's avatar
romanb committed
31
    /**
32
     * Creates a new <b>test</b> database connection using the following parameters
romanb's avatar
romanb committed
33
     * of the $GLOBALS array:
34
     *
35 36 37 38 39 40 41 42
     * 'db_driver':   The name of the Doctrine DBAL database driver to use.
     * 'db_user':     The username to use for connecting.
     * 'db_password': The password to use for connecting.
     * 'db_host':     The hostname of the database to connect to.
     * 'db_server':   The server name of the database to connect to
     *                (optional, some vendors allow multiple server instances with different names on the same host).
     * 'db_dbname':   The name of the database to connect to.
     * 'db_port':     The port of the database to connect to.
43
     *
romanb's avatar
romanb committed
44 45 46
     * Usually these variables of the $GLOBALS array are filled by PHPUnit based
     * on an XML configuration file. If no such parameters exist, an SQLite
     * in-memory database is used.
47
     *
48
     * @return Connection The database connection instance.
romanb's avatar
romanb committed
49
     */
50
    public static function getConnection(): Connection
romanb's avatar
romanb committed
51
    {
52 53 54 55 56
        if (self::hasRequiredConnectionParams() && ! self::$initialized) {
            self::initializeDatabase();
            self::$initialized = true;
        }

57
        $conn = DriverManager::getConnection(self::getConnectionParams());
58

59
        self::addDbEventSubscribers($conn);
60

61 62
        return $conn;
    }
63

64 65 66
    /**
     * @return mixed[]
     */
67
    public static function getConnectionParams(): array
Sergei Morozov's avatar
Sergei Morozov committed
68
    {
69
        if (self::hasRequiredConnectionParams()) {
70
            return self::getTestConnectionParameters();
71 72
        }

73
        return self::getFallbackConnectionParams();
romanb's avatar
romanb committed
74
    }
75

76
    private static function hasRequiredConnectionParams(): bool
77
    {
78
        return isset($GLOBALS['db_driver']);
79 80
    }

81
    private static function initializeDatabase(): void
Sergei Morozov's avatar
Sergei Morozov committed
82
    {
83 84
        $testConnParams = self::getTestConnectionParameters();
        $privConnParams = self::getPrivilegedConnectionParameters();
85

86
        $testConn = DriverManager::getConnection($testConnParams);
87

88 89
        // Connect as a privileged user to create and drop the test database.
        $privConn = DriverManager::getConnection($privConnParams);
90

91
        $platform = $privConn->getDatabasePlatform();
92

93
        if ($platform->supportsCreateDropDatabase()) {
94
            if (! $platform instanceof OraclePlatform) {
95
                $dbname = $testConnParams['dbname'];
96
            } else {
97
                $dbname = $testConnParams['user'];
98 99
            }

100
            $testConn->close();
101

102 103 104 105 106 107
            if ($dbname === null) {
                throw new InvalidArgumentException(
                    'You must have a database configured in your connection.'
                );
            }

108
            $privConn->getSchemaManager()->dropAndCreateDatabase($dbname);
109

110
            $privConn->close();
111
        } else {
112
            $sm = $testConn->getSchemaManager();
113

114
            $schema = $sm->createSchema();
115
            $stmts  = $schema->toDropSql($testConn->getDatabasePlatform());
116

117
            foreach ($stmts as $stmt) {
118
                $testConn->exec($stmt);
119 120 121 122
            }
        }
    }

123 124 125
    /**
     * @return mixed[]
     */
126
    private static function getFallbackConnectionParams(): array
127
    {
Sergei Morozov's avatar
Sergei Morozov committed
128
        if (! extension_loaded('pdo_sqlite')) {
129 130 131
            Assert::markTestSkipped('PDO SQLite extension is not loaded');
        }

Sergei Morozov's avatar
Sergei Morozov committed
132
        $params = [
133
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
134 135
            'memory' => true,
        ];
136 137 138 139 140 141 142 143 144

        if (isset($GLOBALS['db_path'])) {
            $params['path'] = $GLOBALS['db_path'];
            unlink($GLOBALS['db_path']);
        }

        return $params;
    }

145
    private static function addDbEventSubscribers(Connection $conn): void
Sergei Morozov's avatar
Sergei Morozov committed
146 147 148 149 150 151 152 153 154
    {
        if (! isset($GLOBALS['db_event_subscribers'])) {
            return;
        }

        $evm = $conn->getEventManager();
        foreach (explode(',', $GLOBALS['db_event_subscribers']) as $subscriberClass) {
            $subscriberInstance = new $subscriberClass();
            $evm->addEventSubscriber($subscriberInstance);
155 156 157
        }
    }

158 159 160
    /**
     * @return mixed[]
     */
161
    private static function getPrivilegedConnectionParameters(): array
162
    {
163 164
        if (isset($GLOBALS['tmpdb_driver'])) {
            return self::mapConnectionParameters($GLOBALS, 'tmpdb_');
165 166
        }

167 168
        $parameters = self::mapConnectionParameters($GLOBALS, 'db_');
        unset($parameters['dbname']);
169

170
        return $parameters;
171 172
    }

173 174 175
    /**
     * @return mixed[]
     */
176
    private static function getTestConnectionParameters(): array
177
    {
178 179
        return self::mapConnectionParameters($GLOBALS, 'db_');
    }
180

181 182 183 184 185
    /**
     * @param array<string,mixed> $configuration
     *
     * @return array<string,mixed>
     */
186
    private static function mapConnectionParameters(array $configuration, string $prefix): array
187 188 189
    {
        $parameters = [];

190 191 192 193 194 195 196 197 198 199 200 201
        foreach (
            [
                'driver',
                'user',
                'password',
                'host',
                'dbname',
                'port',
                'server',
                'unix_socket',
            ] as $parameter
        ) {
202 203 204
            if (! isset($configuration[$prefix . $parameter])) {
                continue;
            }
205

206
            $parameters[$parameter] = $configuration[$prefix . $parameter];
207 208
        }

Sergei Morozov's avatar
Sergei Morozov committed
209 210
        if (isset($parameters['port'])) {
            $parameters['port'] = (int) $parameters['port'];
211 212
        }

213
        return $parameters;
214 215
    }

216
    public static function getPrivilegedConnection(): Connection
217
    {
218
        return DriverManager::getConnection(self::getPrivilegedConnectionParameters());
219
    }
220 221 222 223 224 225

    /**
     * Generates a query that will return the given rows without the need to create a temporary table.
     *
     * @param array<int,array<string,mixed>> $rows
     */
226
    public static function generateResultSetQuery(array $rows, AbstractPlatform $platform): string
227
    {
228
        return implode(' UNION ALL ', array_map(static function (array $row) use ($platform): string {
229
            return $platform->getDummySelectSQL(
230
                implode(', ', array_map(static function (string $column, $value) use ($platform): string {
231 232 233 234 235 236 237 238 239
                    if (is_string($value)) {
                        $value = $platform->quoteStringLiteral($value);
                    }

                    return $value . ' ' . $platform->quoteIdentifier($column);
                }, array_keys($row), array_values($row)))
            );
        }, $rows));
    }
240
}