diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 031103d47d8..c8831b78bcb 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -21,7 +21,7 @@ before_commands: tools: external_code_coverage: timeout: 3600 - runs: 29 # 24x Travis (jobs with COVERAGE=yes) + 3x AppVeyor (jobs with coverage=yes) + 2x ContinuousPHP + runs: 26 # 21x Travis (jobs with COVERAGE=yes) + 3x AppVeyor (jobs with coverage=yes) + 2x ContinuousPHP filter: excluded_paths: diff --git a/.travis.yml b/.travis.yml index 37fabf85aa7..392659b0858 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,11 @@ before_script: - if [[ "$DB" == "mysql" || "$DB" == "mysqli" || "$DB" == *"mariadb"* ]]; then mysql < tests/travis/create-mysql-schema.sql; fi; install: - - travis_retry composer -n install --prefer-dist + - | + if [[ $TRAVIS_PHP_VERSION = "nightly" ]]; then + export COMPOSER_FLAGS="--ignore-platform-reqs" + fi + - travis_retry composer -n install --prefer-dist $COMPOSER_FLAGS script: - | @@ -302,6 +306,63 @@ jobs: before_script: - bash ./tests/travis/install-db2.sh - bash ./tests/travis/install-db2-ibm_db2.sh + - stage: Test + php: nightly + env: DB=mysql.docker MYSQL_VERSION=8.0 + sudo: required + services: + - docker + before_script: + - bash ./tests/travis/install-mysql-8.0.sh + - stage: Test + php: nightly + env: DB=mysqli.docker MYSQL_VERSION=8.0 + sudo: required + services: + - docker + before_script: + - bash ./tests/travis/install-mysql-8.0.sh + - stage: Test + php: nightly + env: DB=mariadb MARIADB_VERSION=10.3 + addons: + mariadb: 10.3 + - stage: Test + php: nightly + env: DB=mariadb.mysqli MARIADB_VERSION=10.3 + addons: + mariadb: 10.3 + - stage: Test + php: nightly + env: DB=pgsql POSTGRESQL_VERSION=11.0 + sudo: required + services: + - docker + before_script: + - bash ./tests/travis/install-postgres-11.sh + - stage: Test + php: nightly + env: DB=sqlite + - stage: Test + php: nightly + env: DB=sqlsrv + sudo: required + services: + - docker + before_script: + - bash ./tests/travis/install-sqlsrv-dependencies.sh + - bash ./tests/travis/install-mssql-sqlsrv.sh + - bash ./tests/travis/install-mssql.sh + - stage: Test + php: nightly + env: DB=pdo_sqlsrv + sudo: required + services: + - docker + before_script: + - bash ./tests/travis/install-sqlsrv-dependencies.sh + - bash ./tests/travis/install-mssql-pdo_sqlsrv.sh + - bash ./tests/travis/install-mssql.sh - stage: Test if: type = cron @@ -313,3 +374,4 @@ jobs: allow_failures: - env: DEPENDENCIES=dev + - php: nightly diff --git a/UPGRADE.md b/UPGRADE.md index 420f2f3d391..edd817562d4 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -390,6 +390,21 @@ The Drizzle project is abandoned and is therefore not supported by Doctrine DBAL Use binary fields of a size which fits all target platforms, or use blob explicitly instead. - Binary fields are no longer represented as streams in PHP. They are represented as strings. +# Upgrade to 2.11 + +## Deprecated `ExpressionBuilder` methods + +The usage of the `andX()` and `orX()` methods of the `ExpressionBuilder` class has been deprecated. Use `and()` and `or()` instead. + +## Deprecated `CompositeExpression` methods + +The usage of the `add()` and `addMultiple()` methods of the `CompositeExpression` class has been deprecated. Use `with()` instead, which returns a new instance. +In the future, the `add*()` methods will be removed and the class will be effectively immutable. + +## Deprecated calling `QueryBuilder` methods with an array argument + +Calling the `select()`, `addSelect()`, `groupBy()` and `addGroupBy()` methods with an array argument is deprecated. + # Upgrade to 2.10 ## Deprecated `Doctrine\DBAL\Event\ConnectionEventArgs` methods diff --git a/docs/en/reference/query-builder.rst b/docs/en/reference/query-builder.rst index 059a70bef5f..3c201df41d2 100644 --- a/docs/en/reference/query-builder.rst +++ b/docs/en/reference/query-builder.rst @@ -332,13 +332,13 @@ Most notably you can use expressions to build nested And-/Or statements: ->select('id', 'name') ->from('users') ->where( - $queryBuilder->expr()->andX( + $queryBuilder->expr()->and( $queryBuilder->expr()->eq('username', '?'), $queryBuilder->expr()->eq('email', '?') ) ); -The ``andX()`` and ``orX()`` methods accept an arbitrary amount +The ``and()`` and ``or()`` methods accept an arbitrary amount of arguments and can be nested in each other. There is a bunch of methods to create comparisons and other SQL snippets diff --git a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php index d00cb26b0c9..e2030df85bc 100644 --- a/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php +++ b/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php @@ -17,7 +17,6 @@ use function array_key_exists; use function assert; use function count; -use function func_get_args; use function is_array; use function is_int; use function is_object; @@ -228,7 +227,7 @@ public function fetchAll(?int $fetchMode = null, ...$args) : array switch ($fetchMode) { case FetchMode::CUSTOM_OBJECT: - while (($row = $this->fetch(...func_get_args())) !== false) { + while (($row = $this->fetch($fetchMode, ...$args)) !== false) { $rows[] = $row; } diff --git a/lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php b/lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php index c62bc4d19e2..b69ffacbc94 100644 --- a/lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php +++ b/lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php @@ -51,6 +51,8 @@ public function __construct(string $type, array $parts = []) /** * Adds multiple parts to composite expression. * + * @deprecated This class will be made immutable. Use with() instead. + * * @param array $parts * * @return $this @@ -67,6 +69,8 @@ public function addMultiple(array $parts = []) : self /** * Adds an expression to composite expression. * + * @deprecated This class will be made immutable. Use with() instead. + * * @param self|string $part * * @return $this @@ -86,6 +90,25 @@ public function add($part) : self return $this; } + /** + * Returns a new CompositeExpression with the given parts added. + * + * @param self|string $part + * @param self|string ...$parts + */ + public function with($part, ...$parts) : self + { + $that = clone $this; + + $that->parts[] = $part; + + foreach ($parts as $part) { + $that->parts[] = $part; + } + + return $that; + } + /** * Retrieves the amount of expressions on composite expression. */ diff --git a/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php b/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php index 349cedd1e50..bee7a681053 100644 --- a/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php +++ b/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php @@ -5,6 +5,7 @@ namespace Doctrine\DBAL\Query\Expression; use Doctrine\DBAL\Connection; +use function array_merge; use function implode; use function sprintf; @@ -40,11 +41,27 @@ public function __construct(Connection $connection) /** * Creates a conjunction of the given expressions. * - * Example: + * @param string|CompositeExpression $expression + * @param string|CompositeExpression ...$expressions + */ + public function and($expression, ...$expressions) : CompositeExpression + { + return new CompositeExpression(CompositeExpression::TYPE_AND, array_merge([$expression], $expressions)); + } + + /** + * Creates a disjunction of the given expressions. * - * [php] - * // (u.type = ?) AND (u.role = ?) - * $expr->andX('u.type = ?', 'u.role = ?')); + * @param string|CompositeExpression $expression + * @param string|CompositeExpression ...$expressions + */ + public function or($expression, ...$expressions) : CompositeExpression + { + return new CompositeExpression(CompositeExpression::TYPE_OR, array_merge([$expression], $expressions)); + } + + /** + * @deprecated Use `and()` instead. * * @param string|CompositeExpression ...$expressions Requires at least one defined when converting to string. */ @@ -54,13 +71,7 @@ public function andX(...$expressions) : CompositeExpression } /** - * Creates a disjunction of the given expressions. - * - * Example: - * - * [php] - * // (u.type = ?) OR (u.role = ?) - * $qb->where($qb->expr()->orX('u.type = ?', 'u.role = ?')); + * @deprecated Use `or()` instead. * * @param string|CompositeExpression ...$expressions Requires at least one defined when converting to string. */ diff --git a/tests/Doctrine/Tests/DBAL/Functional/PDOStatementTest.php b/tests/Doctrine/Tests/DBAL/Functional/PDOStatementTest.php deleted file mode 100644 index 04a7627d1f9..00000000000 --- a/tests/Doctrine/Tests/DBAL/Functional/PDOStatementTest.php +++ /dev/null @@ -1,54 +0,0 @@ -connection->getWrappedConnection() instanceof PDOConnection) { - $this->markTestSkipped('PDO-only test'); - } - - $table = new Table('stmt_test'); - $table->addColumn('id', 'integer'); - $table->addColumn('name', 'string', ['length' => 8]); - $this->connection->getSchemaManager()->dropAndCreateTable($table); - } - - public function testPDOSpecificModeIsAccepted() : void - { - $this->connection->insert('stmt_test', [ - 'id' => 1, - 'name' => 'Alice', - ]); - $this->connection->insert('stmt_test', [ - 'id' => 2, - 'name' => 'Bob', - ]); - - $this->expectException(UnknownFetchMode::class); - $this->expectExceptionMessage('Unknown fetch mode 12.'); - - $data = $this->connection->query('SELECT id, name FROM stmt_test ORDER BY id') - ->fetchAll(PDO::FETCH_KEY_PAIR); - - self::assertSame([ - 1 => 'Alice', - 2 => 'Bob', - ], $data); - } -} diff --git a/tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php b/tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php index b98d5f0f152..49bd1326170 100644 --- a/tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php +++ b/tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php @@ -18,7 +18,7 @@ public function testCount() : void self::assertCount(1, $expr); - $expr->add('u.group_id = 2'); + $expr = $expr->with('u.group_id = 2'); self::assertCount(2, $expr); } @@ -42,6 +42,26 @@ public function testAdd() : void self::assertCount(3, $expr); } + public function testWith() : void + { + $expr = new CompositeExpression(CompositeExpression::TYPE_OR, ['u.group_id = 1']); + + self::assertCount(1, $expr); + + // test immutability + $expr->with(new CompositeExpression(CompositeExpression::TYPE_OR, ['u.user_id = 1'])); + + self::assertCount(1, $expr); + + $expr = $expr->with(new CompositeExpression(CompositeExpression::TYPE_OR, ['u.user_id = 1'])); + + self::assertCount(2, $expr); + + $expr = $expr->with('u.user_id = 1'); + + self::assertCount(3, $expr); + } + /** * @param string[]|CompositeExpression[] $parts * diff --git a/tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php b/tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php index 52b1b0aa43b..e5c1130fa2b 100644 --- a/tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php +++ b/tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php @@ -31,7 +31,19 @@ protected function setUp() : void /** * @param string[]|CompositeExpression[] $parts * - * @dataProvider provideDataForAndX + * @dataProvider provideDataForAnd + */ + public function testAnd(array $parts, string $expected) : void + { + $composite = $this->expr->and(...$parts); + + self::assertEquals($expected, (string) $composite); + } + + /** + * @param string[]|CompositeExpression[] $parts + * + * @dataProvider provideDataForAnd */ public function testAndX(array $parts, string $expected) : void { @@ -47,7 +59,7 @@ public function testAndX(array $parts, string $expected) : void /** * @return mixed[][] */ - public static function provideDataForAndX() : iterable + public static function provideDataForAnd() : iterable { return [ [ @@ -92,7 +104,19 @@ public static function provideDataForAndX() : iterable /** * @param string[]|CompositeExpression[] $parts * - * @dataProvider provideDataForOrX + * @dataProvider provideDataForOr + */ + public function testOr(array $parts, string $expected) : void + { + $composite = $this->expr->or(...$parts); + + self::assertEquals($expected, (string) $composite); + } + + /** + * @param string[]|CompositeExpression[] $parts + * + * @dataProvider provideDataForOr */ public function testOrX(array $parts, string $expected) : void { @@ -108,7 +132,7 @@ public function testOrX(array $parts, string $expected) : void /** * @return mixed[][] */ - public static function provideDataForOrX() : iterable + public static function provideDataForOr() : iterable { return [ [ diff --git a/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php b/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php index e8bf0519f04..8706664cc29 100644 --- a/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php +++ b/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php @@ -70,7 +70,7 @@ public function testSelectWithSimpleWhere() : void $qb->select('u.id') ->from('users', 'u') - ->where($expr->andX($expr->eq('u.nickname', '?'))); + ->where($expr->and($expr->eq('u.nickname', '?'))); self::assertEquals('SELECT u.id FROM users u WHERE u.nickname = ?', (string) $qb); }