diff --git a/.github/workflows/backend-ci.yaml b/.github/workflows/backend-ci.yaml index 780c1ecb70..bbc7d56728 100644 --- a/.github/workflows/backend-ci.yaml +++ b/.github/workflows/backend-ci.yaml @@ -107,7 +107,7 @@ jobs: - name: Run integration test suite vs Postgresql run: composer run-script integration env: - DATABASE_URL: "pgsql://postgres:postgres@localhost:${{ job.services.postgres.ports[5432] }}/testdb?server_version=10" + DATABASE_URL: "pgsql://postgres:postgres@localhost:${{ job.services.postgres.ports[5432] }}/testdb?serverVersion=${{ matrix.image == 'postgres:18' && '18' || '14' }}" # Required by old repository tests DATABASE: "pgsql://postgres:postgres@localhost:${{ job.services.postgres.ports[5432] }}/testdb" diff --git a/composer.json b/composer.json index 8ab252a362..1034b8e0a6 100644 --- a/composer.json +++ b/composer.json @@ -21,14 +21,14 @@ "ext-xsl": "*", "composer/package-versions-deprecated": "^1.11", "doctrine/annotations": "^2.0", - "doctrine/dbal": "^3.8.2", + "doctrine/dbal": "^4.4.4", "doctrine/doctrine-bundle": "^2.19", "doctrine/orm": "^3.3", "doctrine/persistence": "^3.3.1", "friendsofphp/proxy-manager-lts": "^1.0", "friendsofsymfony/http-cache-bundle": "^3.0", "friendsofsymfony/jsrouting-bundle": "^3.5", - "ibexa/doctrine-schema": "~6.0.x-dev", + "ibexa/doctrine-schema": "dev-dbal-4-upgrade as 6.0.x-dev", "ibexa/jms-translation-bundle": "^2.6.0", "league/flysystem-memory": "^2.0.6", "liip/imagine-bundle": "^2.3", diff --git a/phpstan-baseline-lte-8.3.neon b/phpstan-baseline-lte-8.3.neon index 7df68615ee..44ab8b2edf 100644 --- a/phpstan-baseline-lte-8.3.neon +++ b/phpstan-baseline-lte-8.3.neon @@ -12,11 +12,6 @@ parameters: count: 1 path: src/bundle/Core/Features/Context/UserContext.php - - - message: '#^Dead catch \- Doctrine\\DBAL\\Exception is never thrown in the try block\.$#' - identifier: catch.neverThrown - count: 1 - path: src/lib/Persistence/Legacy/Notification/Gateway/ExceptionConversion.php - message: '#^Dead catch \- PDOException is never thrown in the try block\.$#' @@ -24,11 +19,6 @@ parameters: count: 1 path: src/lib/Persistence/Legacy/Notification/Gateway/ExceptionConversion.php - - - message: '#^Dead catch \- Doctrine\\DBAL\\Exception is never thrown in the try block\.$#' - identifier: catch.neverThrown - count: 1 - path: src/lib/Persistence/Legacy/URL/Gateway/ExceptionConversion.php - message: '#^Dead catch \- PDOException is never thrown in the try block\.$#' @@ -42,11 +32,6 @@ parameters: count: 1 path: src/lib/Repository/UserPreferenceService.php - - - message: '#^Dead catch \- Doctrine\\DBAL\\Exception is never thrown in the try block\.$#' - identifier: catch.neverThrown - count: 1 - path: src/lib/Search/Legacy/Content/Gateway/ExceptionConversion.php - message: '#^Dead catch \- PDOException is never thrown in the try block\.$#' @@ -54,11 +39,6 @@ parameters: count: 1 path: src/lib/Search/Legacy/Content/Gateway/ExceptionConversion.php - - - message: '#^Dead catch \- Doctrine\\DBAL\\Exception is never thrown in the try block\.$#' - identifier: catch.neverThrown - count: 1 - path: src/lib/Search/Legacy/Content/Location/Gateway/ExceptionConversion.php - message: '#^Dead catch \- PDOException is never thrown in the try block\.$#' diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index a3ed987b63..16bd8f49e1 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -252,12 +252,6 @@ parameters: count: 1 path: src/bundle/Core/Command/UpdateTimestampsToUTCCommand.php - - - message: '#^Parameter \#2 \$value of method Doctrine\\DBAL\\Query\\QueryBuilder\:\:set\(\) expects string, int given\.$#' - identifier: argument.type - count: 2 - path: src/bundle/Core/Command/UpdateTimestampsToUTCCommand.php - - message: '#^Property Ibexa\\Bundle\\Core\\Command\\UpdateTimestampsToUTCCommand\:\:\$from \(string\) does not accept int\.$#' identifier: assign.propertyType @@ -6264,12 +6258,6 @@ parameters: count: 1 path: src/lib/FieldType/Image/ImageStorage/Gateway/DoctrineStorage.php - - - message: '#^Parameter \#1 \$select of method Doctrine\\DBAL\\Query\\QueryBuilder\:\:select\(\) expects array\\|string\|null, int given\.$#' - identifier: argument.type - count: 2 - path: src/lib/FieldType/Image/ImageStorage/Gateway/DoctrineStorage.php - - message: '#^Parameter \#3 \$pad_string of function str_pad expects string, int given\.$#' identifier: argument.type @@ -11790,12 +11778,6 @@ parameters: count: 1 path: src/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabase.php - - - message: '#^Parameter \#2 \$value2 of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getBitAndComparisonExpression\(\) expects string, int given\.$#' - identifier: argument.type - count: 2 - path: src/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabase.php - - message: '#^Property Ibexa\\Contracts\\Core\\Persistence\\Content\\MetadataUpdateStruct\:\:\$alwaysAvailable \(bool\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -11823,7 +11805,7 @@ parameters: - message: '#^Dead catch \- Doctrine\\DBAL\\Exception is never thrown in the try block\.$#' identifier: catch.neverThrown - count: 14 + count: 1 path: src/lib/Persistence/Legacy/Content/Gateway/ExceptionConversion.php - @@ -12324,24 +12306,12 @@ parameters: count: 1 path: src/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php - - - message: '#^Parameter \#2 \$value2 of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getBitAndComparisonExpression\(\) expects string, int given\.$#' - identifier: argument.type - count: 1 - path: src/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php - - message: '#^Parameter \#2 \$y of method Doctrine\\DBAL\\Query\\Expression\\ExpressionBuilder\:\:in\(\) expects array\\|string, list\ given\.$#' identifier: argument.type count: 1 path: src/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php - - - message: '#^Dead catch \- Doctrine\\DBAL\\Exception is never thrown in the try block\.$#' - identifier: catch.neverThrown - count: 8 - path: src/lib/Persistence/Legacy/Content/Location/Gateway/ExceptionConversion.php - - message: '#^Dead catch \- PDOException is never thrown in the try block\.$#' identifier: catch.neverThrown @@ -12708,12 +12678,6 @@ parameters: count: 1 path: src/lib/Persistence/Legacy/Content/ObjectState/Gateway/DoctrineDatabase.php - - - message: '#^Dead catch \- Doctrine\\DBAL\\Exception is never thrown in the try block\.$#' - identifier: catch.neverThrown - count: 4 - path: src/lib/Persistence/Legacy/Content/ObjectState/Gateway/ExceptionConversion.php - - message: '#^Dead catch \- PDOException is never thrown in the try block\.$#' identifier: catch.neverThrown @@ -13140,12 +13104,6 @@ parameters: count: 1 path: src/lib/Persistence/Legacy/Content/Type/Gateway/DoctrineDatabase.php - - - message: '#^Parameter \#4 \$condition of method Doctrine\\DBAL\\Query\\QueryBuilder\:\:leftJoin\(\) expects string\|null, Doctrine\\DBAL\\Query\\Expression\\CompositeExpression given\.$#' - identifier: argument.type - count: 5 - path: src/lib/Persistence/Legacy/Content/Type/Gateway/DoctrineDatabase.php - - message: '#^Property Ibexa\\Contracts\\Core\\Persistence\\Content\\Type\\Group\:\:\$isSystem \(bool\) on left side of \?\? is not nullable\.$#' identifier: nullCoalesce.property @@ -13158,12 +13116,6 @@ parameters: count: 1 path: src/lib/Persistence/Legacy/Content/Type/Gateway/DoctrineDatabase.php - - - message: '#^Dead catch \- Doctrine\\DBAL\\Exception is never thrown in the try block\.$#' - identifier: catch.neverThrown - count: 4 - path: src/lib/Persistence/Legacy/Content/Type/Gateway/ExceptionConversion.php - - message: '#^Dead catch \- PDOException is never thrown in the try block\.$#' identifier: catch.neverThrown @@ -13752,12 +13704,6 @@ parameters: count: 1 path: src/lib/Persistence/Legacy/Content/UrlAlias/Gateway/DoctrineDatabase.php - - - message: '#^Dead catch \- Doctrine\\DBAL\\Exception is never thrown in the try block\.$#' - identifier: catch.neverThrown - count: 2 - path: src/lib/Persistence/Legacy/Content/UrlAlias/Gateway/ExceptionConversion.php - - message: '#^Dead catch \- PDOException is never thrown in the try block\.$#' identifier: catch.neverThrown @@ -14124,12 +14070,6 @@ parameters: count: 1 path: src/lib/Persistence/Legacy/Content/UrlWildcard/Gateway/DoctrineDatabase.php - - - message: '#^Dead catch \- Doctrine\\DBAL\\Exception is never thrown in the try block\.$#' - identifier: catch.neverThrown - count: 1 - path: src/lib/Persistence/Legacy/Content/UrlWildcard/Gateway/ExceptionConversion.php - - message: '#^Dead catch \- PDOException is never thrown in the try block\.$#' identifier: catch.neverThrown @@ -14844,12 +14784,6 @@ parameters: count: 1 path: src/lib/Persistence/Legacy/Setting/Gateway/DoctrineDatabase.php - - - message: '#^Dead catch \- PDOException is never thrown in the try block\.$#' - identifier: catch.neverThrown - count: 5 - path: src/lib/Persistence/Legacy/Setting/Gateway/ExceptionConversion.php - - message: '#^Method Ibexa\\Core\\Persistence\\Legacy\\Setting\\Gateway\\ExceptionConversion\:\:loadSetting\(\) return type has no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -15090,12 +15024,6 @@ parameters: count: 1 path: src/lib/Persistence/Legacy/URL/Query/CriteriaConverter.php - - - message: '#^Parameter \#4 \$condition of method Doctrine\\DBAL\\Query\\QueryBuilder\:\:innerJoin\(\) expects string\|null, Doctrine\\DBAL\\Query\\Expression\\CompositeExpression given\.$#' - identifier: argument.type - count: 1 - path: src/lib/Persistence/Legacy/URL/Query/CriterionHandler/Base.php - - message: '#^Access to an undefined property Ibexa\\Contracts\\Core\\Repository\\Values\\URL\\Query\\Criterion\:\:\$criteria\.$#' identifier: property.notFound @@ -19104,12 +19032,6 @@ parameters: count: 1 path: src/lib/Search/Legacy/Content/Gateway/DoctrineDatabase.php - - - message: '#^Parameter \#1 \$firstResult of method Doctrine\\DBAL\\Query\\QueryBuilder\:\:setFirstResult\(\) expects int, int\|null given\.$#' - identifier: argument.type - count: 1 - path: src/lib/Search/Legacy/Content/Gateway/DoctrineDatabase.php - - message: '#^Method Ibexa\\Core\\Search\\Legacy\\Content\\Gateway\\ExceptionConversion\:\:find\(\) has parameter \$languageFilter with no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -51972,12 +51894,6 @@ parameters: count: 1 path: tests/lib/Persistence/Legacy/SharedGateway/GatewayFactoryTest.php - - - message: '#^PHPDoc tag @var with type Doctrine\\DBAL\\Platforms\\AbstractPlatform is not subtype of native type Doctrine\\DBAL\\Platforms\\MySQL80Platform\|Doctrine\\DBAL\\Platforms\\MySQLPlatform\|Doctrine\\DBAL\\Platforms\\PostgreSQLPlatform\|Doctrine\\DBAL\\Platforms\\SqlitePlatform\.$#' - identifier: varTag.nativeType - count: 1 - path: tests/lib/Persistence/Legacy/SharedGateway/GatewayFactoryTest.php - - message: '#^Parameter \#1 \$expected of static method PHPUnit\\Framework\\Assert\:\:assertInstanceOf\(\) expects class\-string\, string given\.$#' identifier: argument.type diff --git a/src/bundle/Core/Command/UpdateTimestampsToUTCCommand.php b/src/bundle/Core/Command/UpdateTimestampsToUTCCommand.php index 4f97727a12..c694dae830 100644 --- a/src/bundle/Core/Command/UpdateTimestampsToUTCCommand.php +++ b/src/bundle/Core/Command/UpdateTimestampsToUTCCommand.php @@ -465,11 +465,11 @@ protected function updateTimestampToUTC( ) { $query = $this->connection->createQueryBuilder(); $query - ->update(Gateway::CONTENT_FIELD_TABLE, 'a') - ->set('a.data_int', $newTimestamp) - ->set('a.sort_key_int', $newTimestamp) - ->where('a.id = :id') - ->andWhere('a.version = :version') + ->update(Gateway::CONTENT_FIELD_TABLE) + ->set('data_int', (string)$newTimestamp) + ->set('sort_key_int', (string)$newTimestamp) + ->where('id = :id') + ->andWhere('version = :version') ->setParameter('id', $contentAttributeId) ->setParameter('version', $contentAttributeVersion); diff --git a/src/bundle/Core/DependencyInjection/IbexaCoreExtension.php b/src/bundle/Core/DependencyInjection/IbexaCoreExtension.php index 5473aeff52..38c7986d78 100644 --- a/src/bundle/Core/DependencyInjection/IbexaCoreExtension.php +++ b/src/bundle/Core/DependencyInjection/IbexaCoreExtension.php @@ -23,6 +23,7 @@ use Ibexa\Contracts\Core\MVC\EventSubscriber\ConfigScopeChangeSubscriber; use Ibexa\Contracts\Core\Repository\Values\Filter\CriterionQueryBuilder as FilteringCriterionQueryBuilder; use Ibexa\Contracts\Core\Repository\Values\Filter\SortClauseQueryBuilder as FilteringSortClauseQueryBuilder; +use Ibexa\Contracts\DoctrineSchema\Database\DefaultTableOptions; use Ibexa\Core\MVC\Symfony\MVCEvents; use Ibexa\Core\MVC\Symfony\Routing\ChainRouter; use Ibexa\Core\QueryType\QueryType; @@ -644,6 +645,9 @@ static function (array $repository): string { ); $doctrineConfig = [ + 'dbal' => [ + 'connections' => [], + ], 'orm' => [ 'entity_managers' => [], ], @@ -652,6 +656,13 @@ static function (array $repository): string { $entityMappingConfig = !empty($entityMappings) ? array_merge_recursive(...$entityMappings) : []; foreach ($connections as $connection) { + // Tables generated from Ibexa's Yaml schema state these options themselves, so + // entity-backed tables on the same connection have to agree or MySQL rejects joins + // between their character columns. Prepended, so a project can still override it. + $doctrineConfig['dbal']['connections'][$connection] = [ + 'default_table_options' => DefaultTableOptions::AS_ARRAY, + ]; + $doctrineConfig['orm']['entity_managers'][sprintf('ibexa_%s', $connection)] = array_merge( self::ENTITY_MANAGER_TEMPLATE, ['connection' => $connection, 'mappings' => $entityMappingConfig] diff --git a/src/bundle/Core/Doctrine/ManagedTablesSchemaAssetFilter.php b/src/bundle/Core/Doctrine/ManagedTablesSchemaAssetFilter.php index 3025d507f8..d9a865b00b 100644 --- a/src/bundle/Core/Doctrine/ManagedTablesSchemaAssetFilter.php +++ b/src/bundle/Core/Doctrine/ManagedTablesSchemaAssetFilter.php @@ -46,6 +46,9 @@ public function __construct(private readonly ManagerRegistry $managerRegistry) { } + /** + * @param string|\Doctrine\DBAL\Schema\AbstractAsset $asset + */ public function __invoke(string|AbstractAsset $asset): bool { $tableName = $asset instanceof AbstractAsset ? $asset->getName() : $asset; diff --git a/src/bundle/RepositoryInstaller/Installer/CoreInstaller.php b/src/bundle/RepositoryInstaller/Installer/CoreInstaller.php index 85ed4f4e0f..368dde8470 100644 --- a/src/bundle/RepositoryInstaller/Installer/CoreInstaller.php +++ b/src/bundle/RepositoryInstaller/Installer/CoreInstaller.php @@ -13,6 +13,7 @@ use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Table; use Ibexa\Contracts\DoctrineSchema\Builder\SchemaBuilderInterface; +use Ibexa\Contracts\DoctrineSchema\DbPlatformFactoryInterface; use Ibexa\Contracts\DoctrineSchema\SchemaAssetsFilterBypassInterface; use Symfony\Component\Console\Helper\ProgressBar; @@ -26,6 +27,8 @@ class CoreInstaller extends DbBasedInstaller implements Installer private SchemaAssetsFilterBypassInterface $schemaAssetsFilterBypass; + private DbPlatformFactoryInterface $dbPlatformFactory; + /** * @param \Doctrine\DBAL\Connection $db * @param \Ibexa\Contracts\DoctrineSchema\Builder\SchemaBuilderInterface $schemaBuilder @@ -33,12 +36,22 @@ class CoreInstaller extends DbBasedInstaller implements Installer public function __construct( Connection $db, SchemaBuilderInterface $schemaBuilder, - SchemaAssetsFilterBypassInterface $schemaAssetsFilterBypass + SchemaAssetsFilterBypassInterface $schemaAssetsFilterBypass, + DbPlatformFactoryInterface $dbPlatformFactory ) { parent::__construct($db); $this->schemaBuilder = $schemaBuilder; $this->schemaAssetsFilterBypass = $schemaAssetsFilterBypass; + $this->dbPlatformFactory = $dbPlatformFactory; + } + + private function getIbexaDatabasePlatform(): AbstractPlatform + { + $driverName = $this->db->getParams()['driver'] ?? ''; + + return $this->dbPlatformFactory->createDatabasePlatformFromDriverName($driverName) + ?? $this->db->getDatabasePlatform(); } /** @@ -55,7 +68,7 @@ public function importSchema() { // note: schema is built using Schema Builder event-driven API $schema = $this->schemaBuilder->buildSchema(); - $databasePlatform = $this->db->getDatabasePlatform(); + $databasePlatform = $this->getIbexaDatabasePlatform(); $queries = array_merge( $this->getDropSqlStatementsForExistingSchema($schema, $databasePlatform), // generate schema DDL queries @@ -125,7 +138,7 @@ protected function getDropSqlStatementsForExistingSchema( // cleanup pre-existing database foreach ($tables as $table) { if (in_array($table->getName(), $existingTableNames, true)) { - $statements[] = $databasePlatform->getDropTableSQL($table); + $statements[] = $databasePlatform->getDropTableSQL($table->getName()); } } diff --git a/src/bundle/RepositoryInstaller/Installer/DbBasedInstaller.php b/src/bundle/RepositoryInstaller/Installer/DbBasedInstaller.php index 429f8095fe..862bbc7ceb 100644 --- a/src/bundle/RepositoryInstaller/Installer/DbBasedInstaller.php +++ b/src/bundle/RepositoryInstaller/Installer/DbBasedInstaller.php @@ -8,8 +8,8 @@ namespace Ibexa\Bundle\RepositoryInstaller\Installer; use Doctrine\DBAL\Connection; +use Ibexa\Contracts\DoctrineSchema\Database\DatabasePlatformResolver; use Ibexa\Core\Base\Exceptions\InvalidArgumentException; -use Ibexa\Core\Persistence\Doctrine\DatabasePlatformResolver; use Symfony\Component\Filesystem\Filesystem; class DbBasedInstaller @@ -108,6 +108,15 @@ final protected function getKernelSQLFileForDBMS($relativeFilePath) protected function getDBMSDataDirectoryName(): string { - return DatabasePlatformResolver::resolveName($this->db->getDatabasePlatform())->value; + $platform = $this->db->getDatabasePlatform(); + $name = DatabasePlatformResolver::resolveName($platform); + if ($name === null) { + throw new InvalidArgumentException( + 'platform', + sprintf('Unsupported database platform: %s', $platform::class) + ); + } + + return $name->value; } } diff --git a/src/contracts/Test/Repository/SetupFactory/Legacy.php b/src/contracts/Test/Repository/SetupFactory/Legacy.php index 7854fd61af..ef75875a63 100644 --- a/src/contracts/Test/Repository/SetupFactory/Legacy.php +++ b/src/contracts/Test/Repository/SetupFactory/Legacy.php @@ -17,6 +17,7 @@ use Ibexa\Contracts\Core\Test\Persistence\Fixture\FixtureImporter; use Ibexa\Contracts\Core\Test\Persistence\Fixture\YamlFixture; use Ibexa\Contracts\Core\Test\Repository\SetupFactory; +use Ibexa\Contracts\DoctrineSchema\Database\DefaultTableOptions; use Ibexa\Core\Base\Container\Compiler; use Ibexa\Core\Base\ServiceContainer; use Ibexa\Core\Persistence\Legacy\Content\Language\CachingHandler as CachingLanguageHandler; @@ -223,7 +224,11 @@ protected function getInitialDataFixture(): Fixture protected function initializeSchema(): void { if (!self::$schemaInitialized) { - $schemaImporter = new LegacySchemaImporter($this->getDatabaseConnection(), new SchemaAssetsFilterBypass()); + $schemaImporter = new LegacySchemaImporter( + $this->getDatabaseConnection(), + new SchemaAssetsFilterBypass(), + DefaultTableOptions::AS_ARRAY + ); $schemaImporter->importSchema( dirname(__DIR__, 5) . '/src/bundle/Core/Resources/config/storage/legacy/schema.yaml' diff --git a/src/lib/FieldType/BinaryBase/BinaryBaseStorage/Gateway/DoctrineStorage.php b/src/lib/FieldType/BinaryBase/BinaryBaseStorage/Gateway/DoctrineStorage.php index 0a3a9d5d31..21b470b330 100644 --- a/src/lib/FieldType/BinaryBase/BinaryBaseStorage/Gateway/DoctrineStorage.php +++ b/src/lib/FieldType/BinaryBase/BinaryBaseStorage/Gateway/DoctrineStorage.php @@ -14,7 +14,6 @@ use Ibexa\Contracts\Core\Persistence\Content\Field; use Ibexa\Contracts\Core\Persistence\Content\VersionInfo; use Ibexa\Core\FieldType\BinaryBase\BinaryBaseStorage\Gateway; -use PDO; /** * Base class for binary files external storage DoctrineStorage gateways. @@ -98,11 +97,11 @@ protected function setInsertColumns(QueryBuilder $queryBuilder, VersionInfo $ver ->setValue('mime_type', ':mimeType') ->setValue('original_filename', ':originalFilename') ->setValue('version', ':versionNo') - ->setParameter('fieldId', $field->id, PDO::PARAM_INT) + ->setParameter('fieldId', $field->id, ParameterType::INTEGER) ->setParameter('filename', $this->removeMimeFromPath($field->value->externalData['id'])) ->setParameter('mimeType', $field->value->externalData['mimeType']) ->setParameter('originalFilename', $field->value->externalData['fileName']) - ->setParameter('versionNo', $versionInfo->versionNo, PDO::PARAM_INT) + ->setParameter('versionNo', $versionInfo->versionNo, ParameterType::INTEGER) ; } @@ -238,8 +237,8 @@ public function getFileReferenceData($fieldId, $versionNo) ) ) ) - ->setParameter('fieldId', $fieldId, PDO::PARAM_INT) - ->setParameter('versionNo', $versionNo, PDO::PARAM_INT) + ->setParameter('fieldId', $fieldId, ParameterType::INTEGER) + ->setParameter('versionNo', $versionNo, ParameterType::INTEGER) ; $statement = $selectQuery->executeQuery(); @@ -335,7 +334,7 @@ public function removeFileReferences(array $fieldIds, $versionNo) ) ) ->setParameter('fieldIds', $fieldIds, ArrayParameterType::INTEGER) - ->setParameter('versionNo', $versionNo, PDO::PARAM_INT) + ->setParameter('versionNo', $versionNo, ParameterType::INTEGER) ; $deleteQuery->executeStatement(); @@ -364,8 +363,8 @@ public function removeFileReference($fieldId, $versionNo) ) ) ) - ->setParameter('fieldId', $fieldId, PDO::PARAM_INT) - ->setParameter('versionNo', $versionNo, PDO::PARAM_INT) + ->setParameter('fieldId', $fieldId, ParameterType::INTEGER) + ->setParameter('versionNo', $versionNo, ParameterType::INTEGER) ; $deleteQuery->executeStatement(); @@ -404,7 +403,7 @@ public function getReferencedFiles(array $fieldIds, $versionNo) ) ) ->setParameter('fieldIds', $fieldIds, ArrayParameterType::INTEGER) - ->setParameter('versionNo', $versionNo, PDO::PARAM_INT) + ->setParameter('versionNo', $versionNo, ParameterType::INTEGER) ; $statement = $selectQuery->executeQuery(); diff --git a/src/lib/FieldType/BinaryFile/BinaryFileStorage/Gateway/DoctrineStorage.php b/src/lib/FieldType/BinaryFile/BinaryFileStorage/Gateway/DoctrineStorage.php index f24bec5246..94c30558d4 100644 --- a/src/lib/FieldType/BinaryFile/BinaryFileStorage/Gateway/DoctrineStorage.php +++ b/src/lib/FieldType/BinaryFile/BinaryFileStorage/Gateway/DoctrineStorage.php @@ -7,11 +7,11 @@ namespace Ibexa\Core\FieldType\BinaryFile\BinaryFileStorage\Gateway; +use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Query\QueryBuilder; use Ibexa\Contracts\Core\Persistence\Content\Field; use Ibexa\Contracts\Core\Persistence\Content\VersionInfo; use Ibexa\Core\FieldType\BinaryBase\BinaryBaseStorage\Gateway\DoctrineStorage as BaseDoctrineStorage; -use PDO; /** * Binary File Field Type external storage DoctrineStorage gateway. @@ -64,7 +64,7 @@ protected function setInsertColumns(QueryBuilder $queryBuilder, VersionInfo $ver ->setParameter( 'downloadCount', $field->value->externalData['downloadCount'], - PDO::PARAM_INT + ParameterType::INTEGER ) ; } diff --git a/src/lib/FieldType/Image/ImageStorage/Gateway/DoctrineStorage.php b/src/lib/FieldType/Image/ImageStorage/Gateway/DoctrineStorage.php index 490ede7232..9e09656e3c 100644 --- a/src/lib/FieldType/Image/ImageStorage/Gateway/DoctrineStorage.php +++ b/src/lib/FieldType/Image/ImageStorage/Gateway/DoctrineStorage.php @@ -16,7 +16,6 @@ use Ibexa\Core\IO\UrlRedecoratorInterface; use Ibexa\Core\Persistence\Legacy\Content\Gateway as ContentGateway; use Ibexa\Core\Persistence\Legacy\Content\Location\Gateway as LocationGateway; -use PDO; /** * Image Field Type external storage DoctrineStorage gateway. @@ -64,8 +63,8 @@ public function getNodePathString(VersionInfo $versionInfo): string ) ) ) - ->setParameter('contentObjectId', $versionInfo->contentInfo->id, PDO::PARAM_INT) - ->setParameter('versionNo', $versionInfo->versionNo, PDO::PARAM_INT) + ->setParameter('contentObjectId', $versionInfo->contentInfo->id, ParameterType::INTEGER) + ->setParameter('versionNo', $versionInfo->versionNo, ParameterType::INTEGER) ; return $selectQuery->executeQuery()->fetchOne(); @@ -88,7 +87,7 @@ public function storeImageReference(string $uri, mixed $fieldId): void $this->connection->quoteIdentifier('filepath') => ':path', ] ) - ->setParameter('fieldId', $fieldId, PDO::PARAM_INT) + ->setParameter('fieldId', $fieldId, ParameterType::INTEGER) ->setParameter('path', $path) ; @@ -119,7 +118,7 @@ public function getXmlForImages(int $versionNo, array $fieldIds): array ) ) ) - ->setParameter('versionNo', $versionNo, PDO::PARAM_INT) + ->setParameter('versionNo', $versionNo, ParameterType::INTEGER) ->setParameter('fieldIds', $fieldIds, ArrayParameterType::INTEGER) ; @@ -149,7 +148,7 @@ public function getAllVersionsImageXmlForFieldId(int $fieldId): array ':field_id' ) ) - ->setParameter('field_id', $fieldId, PDO::PARAM_INT) + ->setParameter('field_id', $fieldId, ParameterType::INTEGER) ; $statement = $selectQuery->executeQuery(); @@ -193,7 +192,7 @@ public function removeImageReferences(string $uri, int $versionNo, mixed $fieldI ) ) ) - ->setParameter('fieldId', $fieldId, PDO::PARAM_INT) + ->setParameter('fieldId', $fieldId, ParameterType::INTEGER) ->setParameter('likePath', $path . '%') ; @@ -231,7 +230,7 @@ public function isImageReferenced(string $uri): bool $selectQuery = $this->connection->createQueryBuilder(); $selectQuery - ->select(1) + ->select('1') ->from($this->connection->quoteIdentifier(self::IMAGE_FILE_TABLE)) ->where( $selectQuery->expr()->eq( @@ -288,8 +287,8 @@ protected function canRemoveImageReference(string $path, int $versionNo, int $fi ':versionNo' ) ) - ->setParameter('fieldId', $fieldId, PDO::PARAM_INT) - ->setParameter('versionNo', $versionNo, PDO::PARAM_INT) + ->setParameter('fieldId', $fieldId, ParameterType::INTEGER) + ->setParameter('versionNo', $versionNo, ParameterType::INTEGER) ; $imageXMLs = $selectQuery->executeQuery()->fetchFirstColumn(); @@ -432,7 +431,7 @@ public function hasImageReference(string $uri, int $fieldId): bool $selectQuery = $this->connection->createQueryBuilder(); $selectQuery - ->select(1) + ->select('1') ->from($this->connection->quoteIdentifier(self::IMAGE_FILE_TABLE)) ->andWhere( $selectQuery->expr()->eq( diff --git a/src/lib/FieldType/Keyword/KeywordStorage/Gateway/DoctrineStorage.php b/src/lib/FieldType/Keyword/KeywordStorage/Gateway/DoctrineStorage.php index b02967d4e7..37ec464eaa 100644 --- a/src/lib/FieldType/Keyword/KeywordStorage/Gateway/DoctrineStorage.php +++ b/src/lib/FieldType/Keyword/KeywordStorage/Gateway/DoctrineStorage.php @@ -256,7 +256,7 @@ protected function insertKeywords(array $keywordsToInsert, $contentTypeId) $this->connection->quoteIdentifier('keyword') => ':keyword', ] ) - ->setParameter('contentTypeId', $contentTypeId, \PDO::PARAM_INT); + ->setParameter('contentTypeId', $contentTypeId, ParameterType::INTEGER); foreach (array_keys($keywordsToInsert) as $keyword) { $insertQuery->setParameter('keyword', $keyword); diff --git a/src/lib/FieldType/MapLocation/MapLocationStorage/Gateway/DoctrineStorage.php b/src/lib/FieldType/MapLocation/MapLocationStorage/Gateway/DoctrineStorage.php index 2e6288fba2..8439766058 100644 --- a/src/lib/FieldType/MapLocation/MapLocationStorage/Gateway/DoctrineStorage.php +++ b/src/lib/FieldType/MapLocation/MapLocationStorage/Gateway/DoctrineStorage.php @@ -9,10 +9,10 @@ use Doctrine\DBAL\ArrayParameterType; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\ParameterType; use Ibexa\Contracts\Core\Persistence\Content\Field; use Ibexa\Contracts\Core\Persistence\Content\VersionInfo; use Ibexa\Core\FieldType\MapLocation\MapLocationStorage\Gateway; -use PDO; class DoctrineStorage extends Gateway { @@ -92,8 +92,8 @@ protected function updateFieldData(VersionInfo $versionInfo, Field $field) ->setParameter('latitude', $field->value->externalData['latitude']) ->setParameter('longitude', $field->value->externalData['longitude']) ->setParameter('address', $field->value->externalData['address']) - ->setParameter('fieldId', $field->id, PDO::PARAM_INT) - ->setParameter('versionNo', $versionInfo->versionNo, PDO::PARAM_INT) + ->setParameter('fieldId', $field->id, ParameterType::INTEGER) + ->setParameter('versionNo', $versionInfo->versionNo, ParameterType::INTEGER) ; $updateQuery->executeStatement(); @@ -172,8 +172,8 @@ protected function loadFieldData($fieldId, $versionNo) ) ) ) - ->setParameter('fieldId', $fieldId, PDO::PARAM_INT) - ->setParameter('versionNo', $versionNo, PDO::PARAM_INT) + ->setParameter('fieldId', $fieldId, ParameterType::INTEGER) + ->setParameter('versionNo', $versionNo, ParameterType::INTEGER) ; $statement = $selectQuery->executeQuery(); @@ -232,7 +232,7 @@ public function deleteFieldData(VersionInfo $versionInfo, array $fieldIds) ) ) ->setParameter('fieldIds', $fieldIds, ArrayParameterType::INTEGER) - ->setParameter('versionNo', $versionInfo->versionNo, PDO::PARAM_INT) + ->setParameter('versionNo', $versionInfo->versionNo, ParameterType::INTEGER) ; $deleteQuery->executeStatement(); diff --git a/src/lib/FieldType/Media/MediaStorage/Gateway/DoctrineStorage.php b/src/lib/FieldType/Media/MediaStorage/Gateway/DoctrineStorage.php index 0d494a9c59..1cebdaa870 100644 --- a/src/lib/FieldType/Media/MediaStorage/Gateway/DoctrineStorage.php +++ b/src/lib/FieldType/Media/MediaStorage/Gateway/DoctrineStorage.php @@ -12,7 +12,6 @@ use Ibexa\Contracts\Core\Persistence\Content\Field; use Ibexa\Contracts\Core\Persistence\Content\VersionInfo; use Ibexa\Core\FieldType\BinaryBase\BinaryBaseStorage\Gateway\DoctrineStorage as BaseDoctrineStorage; -use PDO; /** * Media Field Type external storage DoctrineStorage gateway. @@ -99,14 +98,14 @@ protected function setInsertColumns(QueryBuilder $queryBuilder, VersionInfo $ver ->setParameter( 'hasController', $field->value->externalData['hasController'], - PDO::PARAM_INT + ParameterType::INTEGER ) - ->setParameter('height', $field->value->externalData['height'], PDO::PARAM_INT) - ->setParameter('isAutoplay', $field->value->externalData['autoplay'], PDO::PARAM_INT) - ->setParameter('isLoop', $field->value->externalData['loop'], PDO::PARAM_INT) + ->setParameter('height', $field->value->externalData['height'], ParameterType::INTEGER) + ->setParameter('isAutoplay', $field->value->externalData['autoplay'], ParameterType::INTEGER) + ->setParameter('isLoop', $field->value->externalData['loop'], ParameterType::INTEGER) ->setParameter('pluginsPage', '') ->setParameter('quality', 'high') - ->setParameter('width', $field->value->externalData['width'], PDO::PARAM_INT) + ->setParameter('width', $field->value->externalData['width'], ParameterType::INTEGER) ; } diff --git a/src/lib/FieldType/Url/UrlStorage/Gateway/DoctrineStorage.php b/src/lib/FieldType/Url/UrlStorage/Gateway/DoctrineStorage.php index 958992e43b..210a96edaf 100644 --- a/src/lib/FieldType/Url/UrlStorage/Gateway/DoctrineStorage.php +++ b/src/lib/FieldType/Url/UrlStorage/Gateway/DoctrineStorage.php @@ -12,7 +12,6 @@ use Doctrine\DBAL\ParameterType; use Ibexa\Core\FieldType\Url\UrlStorage\Gateway; use Ibexa\Core\Persistence\Legacy\URL\Gateway\DoctrineDatabase; -use PDO; class DoctrineStorage extends Gateway { @@ -118,8 +117,8 @@ public function insertUrl($url): int 'url' => ':url', ] ) - ->setParameter('created', $time, PDO::PARAM_INT) - ->setParameter('modified', $time, PDO::PARAM_INT) + ->setParameter('created', $time, ParameterType::INTEGER) + ->setParameter('modified', $time, ParameterType::INTEGER) ->setParameter('original_url_md5', md5($url)) ->setParameter('url', $url) ; @@ -149,9 +148,9 @@ public function linkUrl($urlId, $fieldId, $versionNo) 'url_id' => ':url_id', ] ) - ->setParameter('contentobject_attribute_id', $fieldId, PDO::PARAM_INT) - ->setParameter('contentobject_attribute_version', $versionNo, PDO::PARAM_INT) - ->setParameter('url_id', $urlId, PDO::PARAM_INT) + ->setParameter('contentobject_attribute_id', $fieldId, ParameterType::INTEGER) + ->setParameter('contentobject_attribute_version', $versionNo, ParameterType::INTEGER) + ->setParameter('url_id', $urlId, ParameterType::INTEGER) ; $query->executeStatement(); diff --git a/src/lib/FieldType/User/UserStorage/Gateway/DoctrineStorage.php b/src/lib/FieldType/User/UserStorage/Gateway/DoctrineStorage.php index 29d576670f..14b72cdf78 100644 --- a/src/lib/FieldType/User/UserStorage/Gateway/DoctrineStorage.php +++ b/src/lib/FieldType/User/UserStorage/Gateway/DoctrineStorage.php @@ -17,7 +17,6 @@ use Ibexa\Core\FieldType\User\UserStorage\Gateway; use Ibexa\Core\Persistence\Legacy\Content\Gateway as ContentGateway; use Ibexa\Core\Persistence\Legacy\User\Gateway as UserGateway; -use PDO; /** * User DoctrineStorage gateway. @@ -141,7 +140,7 @@ protected function fetchUserId(int $fieldId): int ':fieldId' ) ) - ->setParameter('fieldId', $fieldId, PDO::PARAM_INT) + ->setParameter('fieldId', $fieldId, ParameterType::INTEGER) ; $statement = $query->executeQuery(); @@ -168,7 +167,7 @@ protected function fetchUserData(int $userId): array ':userId' ) ) - ->setParameter('userId', $userId, PDO::PARAM_INT) + ->setParameter('userId', $userId, ParameterType::INTEGER) ; $statement = $query->executeQuery(); @@ -193,7 +192,7 @@ protected function fetchUserSettings(int $userId): array ':userId' ) ) - ->setParameter('userId', $userId, PDO::PARAM_INT) + ->setParameter('userId', $userId, ParameterType::INTEGER) ; $statement = $query->executeQuery(); diff --git a/src/lib/Persistence/Doctrine/DatabasePlatformName.php b/src/lib/Persistence/Doctrine/DatabasePlatformName.php deleted file mode 100644 index de7dd41f02..0000000000 --- a/src/lib/Persistence/Doctrine/DatabasePlatformName.php +++ /dev/null @@ -1,16 +0,0 @@ - ':user_id', self::COLUMN_LOCATION_ID => ':location_id', ]) - ->setParameter('user_id', $bookmark->userId, PDO::PARAM_INT) - ->setParameter('location_id', $bookmark->locationId, PDO::PARAM_INT); + ->setParameter('user_id', $bookmark->userId, ParameterType::INTEGER) + ->setParameter('location_id', $bookmark->locationId, ParameterType::INTEGER); $query->executeStatement(); @@ -62,7 +61,7 @@ public function deleteBookmark(int $id): void $query ->delete(self::TABLE_BOOKMARKS) ->where($query->expr()->eq(self::COLUMN_ID, ':id')) - ->setParameter('id', $id, PDO::PARAM_INT); + ->setParameter('id', $id, ParameterType::INTEGER); $query->executeStatement(); } @@ -77,7 +76,7 @@ public function loadBookmarkDataById(int $id): array ->select(...$this->getColumns()) ->from(self::TABLE_BOOKMARKS) ->where($query->expr()->eq(self::COLUMN_ID, ':id')) - ->setParameter('id', $id, PDO::PARAM_INT); + ->setParameter('id', $id, ParameterType::INTEGER); return $query->executeQuery()->fetchAllAssociative(); } @@ -95,7 +94,7 @@ public function loadBookmarkDataByUserIdAndLocationId(int $userId, array $locati $query->expr()->eq(self::COLUMN_USER_ID, ':user_id'), $query->expr()->in(self::COLUMN_LOCATION_ID, ':location_id') )) - ->setParameter('user_id', $userId, PDO::PARAM_INT) + ->setParameter('user_id', $userId, ParameterType::INTEGER) ->setParameter('location_id', $locationIds, ArrayParameterType::INTEGER); return $query->executeQuery()->fetchAllAssociative(); @@ -139,7 +138,7 @@ public function loadUserBookmarks(int $userId, int $offset = 0, int $limit = -1) } $query->orderBy(self::COLUMN_ID, 'DESC'); - $query->setParameter('user_id', $userId, PDO::PARAM_INT); + $query->setParameter('user_id', $userId, ParameterType::INTEGER); return $query->executeQuery()->fetchAllAssociative(); } @@ -154,7 +153,7 @@ public function countUserBookmarks(int $userId): int ->select('COUNT(' . self::COLUMN_ID . ')') ->from(self::TABLE_BOOKMARKS) ->where($query->expr()->eq(self::COLUMN_USER_ID, ':user_id')) - ->setParameter('user_id', $userId, PDO::PARAM_INT); + ->setParameter('user_id', $userId, ParameterType::INTEGER); return (int) $query->executeQuery()->fetchOne(); } @@ -174,9 +173,9 @@ public function locationSwapped(int $location1Id, int $location2Id): void )); $stmt = $this->connection->prepare($query->getSQL()); - $stmt->bindValue('source_id', $location1Id, PDO::PARAM_INT); - $stmt->bindValue('target_id', $location2Id, PDO::PARAM_INT); - $stmt->execute(); + $stmt->bindValue('source_id', $location1Id, ParameterType::INTEGER); + $stmt->bindValue('target_id', $location2Id, ParameterType::INTEGER); + $stmt->executeStatement(); } private function getColumns(): array diff --git a/src/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabase.php b/src/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabase.php index 825b6f63ed..5062264a36 100644 --- a/src/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabase.php +++ b/src/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabase.php @@ -751,16 +751,16 @@ private function internalLoadContent( 'c', Gateway::CONTENT_VERSION_TABLE, 'v', - $expr->and( + (string) $expr->and( $expr->eq('c.id', 'v.contentobject_id'), - $expr->eq('v.version', $version ?? 'c.current_version') + $expr->eq('v.version', (string) ($version ?? 'c.current_version')) ) ) ->innerJoin( 'v', Gateway::CONTENT_FIELD_TABLE, 'a', - $expr->and( + (string) $expr->and( $expr->eq('v.contentobject_id', 'a.contentobject_id'), $expr->eq('v.version', 'a.version') ) @@ -769,7 +769,7 @@ private function internalLoadContent( 'c', LocationGateway::CONTENT_TREE_TABLE, 't', - $expr->and( + (string) $expr->and( $expr->eq('c.id', 't.contentobject_id'), $expr->eq('t.node_id', 't.main_node_id') ) @@ -941,9 +941,9 @@ public function countVersionsForUser(int $userId, int $status = VersionInfo::STA 'v', Gateway::CONTENT_ITEM_TABLE, 'c', - $expr->and( + (string) $expr->and( $expr->eq('c.id', 'v.contentobject_id'), - $expr->neq('c.status', ContentInfo::STATUS_TRASHED) + $expr->neq('c.status', (string) ContentInfo::STATUS_TRASHED) ) ) ->where( @@ -988,7 +988,7 @@ public function loadVersionsForUser( $expr->and( $expr->eq('v.status', ':status'), $expr->eq('v.creator_id', ':user_id'), - $expr->neq('c.status', ContentInfo::STATUS_TRASHED) + $expr->neq('c.status', (string) ContentInfo::STATUS_TRASHED) ) ) ->setFirstResult($offset) @@ -1142,7 +1142,7 @@ public function removeReverseFieldRelations(int $contentId): void 'a', Gateway::CONTENT_RELATION_TABLE, 'l', - $expr->and( + (string) $expr->and( 'l.from_contentobject_id = a.contentobject_id', 'l.from_contentobject_version = a.version', 'l.content_type_field_definition_id = a.content_type_field_definition_id' @@ -1155,7 +1155,7 @@ public function removeReverseFieldRelations(int $contentId): void 'l.relation_type', ':relation_type' ), - 0 + '0' ) ) ->setParameter('content_id', $contentId, ParameterType::INTEGER) @@ -1478,7 +1478,7 @@ private function prepareRelationQuery( 'l', self::CONTENT_ITEM_TABLE, 'c_to', - $expr->and( + (string) $expr->and( 'l.to_contentobject_id = c_to.id', 'c_to.status = :status' ) @@ -1505,7 +1505,7 @@ private function prepareRelationQuery( 'c_to', self::CONTENT_ITEM_TABLE, 'c', - $expr->and( + (string) $expr->and( 'c.id = l.from_contentobject_id', 'c.current_version = l.from_contentobject_version' ) @@ -1521,7 +1521,7 @@ private function prepareRelationQuery( 'l.relation_type', ':relation_type' ), - 0 + '0' ) ) ->setParameter('relation_type', $relationType, ParameterType::INTEGER); @@ -1541,7 +1541,7 @@ public function countReverseRelations(int $toContentId, ?int $relationType = nul 'l', Gateway::CONTENT_ITEM_TABLE, 'c', - $expr->and( + (string) $expr->and( $expr->eq('l.from_contentobject_id', 'c.id'), $expr->eq('l.from_contentobject_version', 'c.current_version'), $expr->eq('c.status', ':status') @@ -1560,9 +1560,9 @@ public function countReverseRelations(int $toContentId, ?int $relationType = nul $expr->gt( $this->getDatabasePlatform()->getBitAndComparisonExpression( 'l.relation_type', - $relationType + (string)$relationType ), - 0 + '0' ) ); } @@ -1579,7 +1579,7 @@ public function loadReverseRelations(int $toContentId, ?int $relationType = null 'l', Gateway::CONTENT_ITEM_TABLE, 'c', - $expr->and( + (string) $expr->and( 'c.id = l.from_contentobject_id', 'c.current_version = l.from_contentobject_version', 'c.status = :status' @@ -1601,7 +1601,7 @@ public function loadReverseRelations(int $toContentId, ?int $relationType = null 'l.relation_type', ':relation_type' ), - 0 + '0' ) ) ->setParameter('relation_type', $relationType, ParameterType::INTEGER); @@ -1623,10 +1623,10 @@ public function listReverseRelations( 'l', Gateway::CONTENT_ITEM_TABLE, 'c', - $expr->and( + (string) $expr->and( $expr->eq('l.from_contentobject_id', 'c.id'), $expr->eq('l.from_contentobject_version', 'c.current_version'), - $expr->eq('c.status', ContentInfo::STATUS_PUBLISHED) + $expr->eq('c.status', (string) ContentInfo::STATUS_PUBLISHED) ) ) ->where( @@ -1640,9 +1640,9 @@ public function listReverseRelations( $expr->gt( $this->getDatabasePlatform()->getBitAndComparisonExpression( 'l.relation_type', - $relationType + (string)$relationType ), - 0 + '0' ) ); } @@ -1999,7 +1999,7 @@ private function deleteTranslationFromContentObject($contentId, $languageId) ->setParameter('contentId', $contentId) ; - $rowCount = $query->executeQuery(); + $rowCount = $query->executeStatement(); // no rows updated means that most likely somehow it was the last remaining translation if ($rowCount === 0) { diff --git a/src/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabase/QueryBuilder.php b/src/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabase/QueryBuilder.php index 79f048af82..6e4a9955b1 100644 --- a/src/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabase/QueryBuilder.php +++ b/src/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabase/QueryBuilder.php @@ -177,7 +177,7 @@ public function createVersionInfoFindQueryBuilder(): DoctrineQueryBuilder 'v', LocationGateway::CONTENT_TREE_TABLE, 't', - $expr->and( + (string) $expr->and( $expr->eq('t.contentobject_id', 'v.contentobject_id'), $expr->eq('t.main_node_id', 't.node_id') ) diff --git a/src/lib/Persistence/Legacy/Content/Language/Gateway/DoctrineDatabase.php b/src/lib/Persistence/Legacy/Content/Language/Gateway/DoctrineDatabase.php index a325d53c5f..4b1a407c99 100644 --- a/src/lib/Persistence/Legacy/Content/Language/Gateway/DoctrineDatabase.php +++ b/src/lib/Persistence/Legacy/Content/Language/Gateway/DoctrineDatabase.php @@ -195,7 +195,7 @@ private function countTableData( $languageMaskColumn, $query->createPositionalParameter($languageId, ParameterType::INTEGER) ), - 0 + '0' ) ); if (null !== $languageIdColumn) { diff --git a/src/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php b/src/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php index 81e52d6d06..7dab41c200 100644 --- a/src/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php +++ b/src/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php @@ -152,7 +152,7 @@ public function loadParentLocationsDataForDraftContent(int $contentId): array 't', self::NODE_ASSIGNMENT_TABLE, 'a', - $expr->and( + (string) $expr->and( $expr->eq( 't.node_id', 'a.parent_node' @@ -174,7 +174,7 @@ public function loadParentLocationsDataForDraftContent(int $contentId): array 'a', ContentGateway::CONTENT_ITEM_TABLE, 'c', - $expr->and( + (string) $expr->and( $expr->eq( 'a.contentobject_id', 'c.id' @@ -982,7 +982,7 @@ public function updateLocationsContentVersionNo(int $contentId, int $versionNo): )->where( $query->expr()->eq( 'contentobject_id', - $contentId + (string) $contentId ) ); $query->executeStatement(); @@ -1046,7 +1046,7 @@ public function update(UpdateStruct $location, int $locationId): void ->where( $query->expr()->eq( 'node_id', - $locationId + (string) $locationId ) ); $query->executeStatement(); @@ -1420,7 +1420,7 @@ private function createNodeQueryBuilder( ): QueryBuilder { $queryBuilder = $this->connection->createQueryBuilder(); $queryBuilder - ->select($columns) + ->select(...$columns) ->from(self::CONTENT_TREE_TABLE, 't') ; @@ -1456,8 +1456,8 @@ private function appendContentItemTranslationsConstraint( $queryBuilder->andWhere( $expr->or( $expr->gt( - $this->getDatabasePlatform()->getBitAndComparisonExpression('c.language_mask', $mask), - 0 + $this->getDatabasePlatform()->getBitAndComparisonExpression('c.language_mask', (string)$mask), + '0' ), // Root location doesn't have language mask $expr->eq( diff --git a/src/lib/Persistence/Legacy/Content/Type/Gateway/DoctrineDatabase.php b/src/lib/Persistence/Legacy/Content/Type/Gateway/DoctrineDatabase.php index 91c695d00a..c723d3a72e 100644 --- a/src/lib/Persistence/Legacy/Content/Type/Gateway/DoctrineDatabase.php +++ b/src/lib/Persistence/Legacy/Content/Type/Gateway/DoctrineDatabase.php @@ -12,6 +12,7 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Query\QueryBuilder; +use Doctrine\DBAL\Types\Types; use Ibexa\Contracts\Core\Persistence\Content\Type; use Ibexa\Contracts\Core\Persistence\Content\Type\FieldDefinition; use Ibexa\Contracts\Core\Persistence\Content\Type\Group; @@ -675,10 +676,10 @@ private function mapCommonFieldDefinitionColumnsToQueryValuesAndTypes( ParameterType::INTEGER, ], 'is_searchable' => [(int)$fieldDefinition->isSearchable, ParameterType::INTEGER], - 'data_float1' => [$storageFieldDef->dataFloat1, null], - 'data_float2' => [$storageFieldDef->dataFloat2, null], - 'data_float3' => [$storageFieldDef->dataFloat3, null], - 'data_float4' => [$storageFieldDef->dataFloat4, null], + 'data_float1' => [$storageFieldDef->dataFloat1, Types::FLOAT], + 'data_float2' => [$storageFieldDef->dataFloat2, Types::FLOAT], + 'data_float3' => [$storageFieldDef->dataFloat3, Types::FLOAT], + 'data_float4' => [$storageFieldDef->dataFloat4, Types::FLOAT], 'data_int1' => [$storageFieldDef->dataInt1, ParameterType::INTEGER], 'data_int2' => [$storageFieldDef->dataInt2, ParameterType::INTEGER], 'data_int3' => [$storageFieldDef->dataInt3, ParameterType::INTEGER], @@ -710,7 +711,7 @@ public function loadFieldDefinition(int $id, int $status): array 'f_def', self::CONTENT_TYPE_TABLE, 'ct', - $expr->and( + (string) $expr->and( $expr->eq('f_def.content_type_id', 'ct.id'), $expr->eq('f_def.status', 'ct.status') ) @@ -719,7 +720,7 @@ public function loadFieldDefinition(int $id, int $status): array 'f_def', self::MULTILINGUAL_FIELD_DEFINITION_TABLE, 'transl_f_def', - $expr->and( + (string) $expr->and( $expr->eq( 'f_def.id', 'transl_f_def.content_type_field_definition_id' @@ -948,7 +949,7 @@ public function loadTypesListData(array $typeIds): array $query ->where($query->expr()->in('c.id', ':ids')) - ->andWhere($query->expr()->eq('c.status', Type::STATUS_DEFINED)) + ->andWhere($query->expr()->eq('c.status', (string) Type::STATUS_DEFINED)) ->setParameter('ids', $typeIds, ArrayParameterType::INTEGER); return $query->executeQuery()->fetchAllAssociative(); @@ -1071,7 +1072,7 @@ private function getLoadTypeQueryBuilder(): QueryBuilder 'c', self::FIELD_DEFINITION_TABLE, 'a', - $expr->and( + (string) $expr->and( $expr->eq('c.id', 'a.content_type_id'), $expr->eq('c.status', 'a.status') ) @@ -1080,7 +1081,7 @@ private function getLoadTypeQueryBuilder(): QueryBuilder 'c', self::CONTENT_TYPE_TO_GROUP_ASSIGNMENT_TABLE, 'g', - $expr->and( + (string) $expr->and( $expr->eq('c.id', 'g.content_type_id'), $expr->eq('c.status', 'g.content_type_status') ) @@ -1089,7 +1090,7 @@ private function getLoadTypeQueryBuilder(): QueryBuilder 'a', self::MULTILINGUAL_FIELD_DEFINITION_TABLE, 'ml', - $expr->and( + (string) $expr->and( $expr->eq('a.id', 'ml.content_type_field_definition_id'), $expr->eq('a.status', 'ml.status') ) @@ -1223,7 +1224,7 @@ private function selectColumns( } $queryBuilder ->addSelect( - array_map( + ...array_map( function (string $columnName) use ($tableName, $tableAlias): string { return sprintf( '%s.%s as %s_%s', diff --git a/src/lib/Persistence/Legacy/Content/UrlAlias/Gateway/DoctrineDatabase.php b/src/lib/Persistence/Legacy/Content/UrlAlias/Gateway/DoctrineDatabase.php index c22f98dd4e..df8413f384 100644 --- a/src/lib/Persistence/Legacy/Content/UrlAlias/Gateway/DoctrineDatabase.php +++ b/src/lib/Persistence/Legacy/Content/UrlAlias/Gateway/DoctrineDatabase.php @@ -73,7 +73,7 @@ public function loadAllLocationEntries(int $locationId): array { $query = $this->connection->createQueryBuilder(); $query - ->select(array_keys(self::URL_ALIAS_DATA_COLUMN_TYPE_MAP)) + ->select(...array_keys(self::URL_ALIAS_DATA_COLUMN_TYPE_MAP)) ->from($this->connection->quoteIdentifier($this->table)) ->where('action = :action') ->andWhere('is_original = :is_original') @@ -134,7 +134,7 @@ public function loadLocationEntries( 'lang_mask', $query->createPositionalParameter($languageId, ParameterType::INTEGER) ), - 0 + '0' ) ); } @@ -205,7 +205,7 @@ public function listGlobalEntries( ParameterType::INTEGER ) ), - 0 + '0' ) ); } @@ -281,7 +281,7 @@ public function cleanupAfterPublish( 'lang_mask', $query->createPositionalParameter($languageId, ParameterType::INTEGER) ), - 0 + '0' ) ) // 2) ...but not newly published entry @@ -373,7 +373,7 @@ public function historizeBeforeSwap(string $action, int $languageMask): void ParameterType::INTEGER ) ), - 0 + '0' ) ) ); @@ -670,7 +670,7 @@ public function loadUrlAliasData(array $urlHashes): array $tableAlias = $level !== $count - 1 ? $this->table . $level : 'u'; $query ->addSelect( - array_map( + ...array_map( static function (string $columnName) use ($tableAlias): string { // do not alias data for top level url part $columnAlias = 'u' === $tableAlias @@ -1113,7 +1113,7 @@ public function deleteUrlAliasesWithoutLocation(): int 'CAST(%s as %s)', $this->getDatabasePlatform()->getSubstringExpression( $this->connection->quoteIdentifier($this->table) . '.action', - 8 + '8' ), $this->getIntegerType() ) @@ -1133,7 +1133,7 @@ public function deleteUrlAliasesWithoutLocation(): int sprintf('NOT EXISTS (%s)', $subQuery->getSQL()) ); - return $deleteQuery->executeStatement(); + return (int)$deleteQuery->executeStatement(); } public function deleteUrlAliasesWithoutParent(): int @@ -1156,7 +1156,7 @@ public function deleteUrlAliasesWithoutParent(): int ) ); - return $query->executeStatement(); + return (int)$query->executeStatement(); } public function deleteUrlAliasesWithBrokenLink(): int @@ -1275,7 +1275,7 @@ public function deleteUrlNopAliasesWithoutChildren(): int ) ->groupBy('u_parent.id') ->having( - $expressionBuilder->eq('COUNT(u.id)', 0) + $expressionBuilder->eq('COUNT(u.id)', '0') ); $wrapperQueryBuilder @@ -1293,7 +1293,7 @@ public function deleteUrlNopAliasesWithoutChildren(): int ) ->setParameter('actionType', self::NOP); - return $queryBuilder->executeStatement(); + return (int)$queryBuilder->executeStatement(); } /** @@ -1434,7 +1434,7 @@ private function deleteRow(int $parentId, string $textMD5): int ) ; - return $queryBuilder->executeStatement(); + return (int)$queryBuilder->executeStatement(); } private function getDatabasePlatform(): AbstractPlatform diff --git a/src/lib/Persistence/Legacy/Filter/Gateway/Content/Doctrine/DoctrineGateway.php b/src/lib/Persistence/Legacy/Filter/Gateway/Content/Doctrine/DoctrineGateway.php index e6f5c17017..a068abf82f 100644 --- a/src/lib/Persistence/Legacy/Filter/Gateway/Content/Doctrine/DoctrineGateway.php +++ b/src/lib/Persistence/Legacy/Filter/Gateway/Content/Doctrine/DoctrineGateway.php @@ -126,7 +126,7 @@ private function buildQuery( $expressionBuilder = $queryBuilder->expr(); $queryBuilder - ->select($columns) + ->select(...$columns) ->distinct() ->from(ContentGateway::CONTENT_ITEM_TABLE, 'content') ->joinPublishedVersion() @@ -134,7 +134,7 @@ private function buildQuery( 'content', LocationGateway::CONTENT_TREE_TABLE, 'main_location', - $expressionBuilder->and( + (string) $expressionBuilder->and( 'content.id = main_location.contentobject_id', 'main_location.main_node_id = main_location.node_id' ) diff --git a/src/lib/Persistence/Legacy/Notification/Gateway/DoctrineDatabase.php b/src/lib/Persistence/Legacy/Notification/Gateway/DoctrineDatabase.php index 7dcfe17960..3dd9ed8487 100644 --- a/src/lib/Persistence/Legacy/Notification/Gateway/DoctrineDatabase.php +++ b/src/lib/Persistence/Legacy/Notification/Gateway/DoctrineDatabase.php @@ -19,7 +19,6 @@ use Ibexa\Contracts\Core\Repository\Values\Notification\Query\NotificationQuery; use Ibexa\Core\Base\Exceptions\InvalidArgumentException; use Ibexa\Core\Persistence\Legacy\Notification\Gateway; -use PDO; class DoctrineDatabase extends Gateway { @@ -58,11 +57,11 @@ public function insert(CreateStruct $createStruct): int self::COLUMN_TYPE => ':type', self::COLUMN_DATA => ':data', ]) - ->setParameter('is_pending', $createStruct->isPending, PDO::PARAM_BOOL) - ->setParameter('user_id', $createStruct->ownerId, PDO::PARAM_INT) - ->setParameter('created', $createStruct->created, PDO::PARAM_INT) - ->setParameter('type', $createStruct->type, PDO::PARAM_STR) - ->setParameter('data', json_encode($createStruct->data), PDO::PARAM_STR); + ->setParameter('is_pending', $createStruct->isPending, ParameterType::BOOLEAN) + ->setParameter('user_id', $createStruct->ownerId, ParameterType::INTEGER) + ->setParameter('created', $createStruct->created, ParameterType::INTEGER) + ->setParameter('type', $createStruct->type, ParameterType::STRING) + ->setParameter('data', json_encode($createStruct->data), ParameterType::STRING); $query->executeStatement(); @@ -77,7 +76,7 @@ public function getNotificationById(int $notificationId): array ->from(self::TABLE_NOTIFICATION) ->where($query->expr()->eq(self::COLUMN_ID, ':id')); - $query->setParameter('id', $notificationId, PDO::PARAM_INT); + $query->setParameter('id', $notificationId, ParameterType::INTEGER); return $query->executeQuery()->fetchAllAssociative(); } @@ -166,8 +165,8 @@ public function updateNotification(Notification $notification): void ->update(self::TABLE_NOTIFICATION) ->set(self::COLUMN_IS_PENDING, ':is_pending') ->where($query->expr()->eq(self::COLUMN_ID, ':id')) - ->setParameter('is_pending', $notification->isPending, PDO::PARAM_BOOL) - ->setParameter('id', $notification->id, PDO::PARAM_INT); + ->setParameter('is_pending', $notification->isPending, ParameterType::BOOLEAN) + ->setParameter('id', $notification->id, ParameterType::INTEGER); $query->executeStatement(); } @@ -179,7 +178,7 @@ public function countUserNotifications(int $userId, ?NotificationQuery $query = ->select('COUNT(' . self::COLUMN_ID . ')') ->from(self::TABLE_NOTIFICATION) ->where($queryBuilder->expr()->eq(self::COLUMN_OWNER_ID, ':user_id')) - ->setParameter('user_id', $userId, PDO::PARAM_INT); + ->setParameter('user_id', $userId, ParameterType::INTEGER); if ($query !== null && !empty($query->getCriteria())) { $this->applyFilters($queryBuilder, $query->getCriteria()); @@ -198,8 +197,8 @@ public function countUserPendingNotifications(int $userId): int ->from(self::TABLE_NOTIFICATION) ->where($expr->eq(self::COLUMN_OWNER_ID, ':user_id')) ->andWhere($expr->eq(self::COLUMN_IS_PENDING, ':is_pending')) - ->setParameter('is_pending', true, PDO::PARAM_BOOL) - ->setParameter('user_id', $userId, PDO::PARAM_INT); + ->setParameter('is_pending', true, ParameterType::BOOLEAN) + ->setParameter('user_id', $userId, ParameterType::INTEGER); return (int)$query->executeQuery()->fetchOne(); } @@ -218,7 +217,7 @@ public function loadUserNotifications(int $userId, int $offset = 0, int $limit = } $query->orderBy(self::COLUMN_ID, 'DESC'); - $query->setParameter('user_id', $userId, PDO::PARAM_INT); + $query->setParameter('user_id', $userId, ParameterType::INTEGER); return $query->executeQuery()->fetchAllAssociative(); } @@ -230,7 +229,7 @@ public function findUserNotifications(int $userId, ?NotificationQuery $query = n ->select(...$this->getColumns()) ->from(self::TABLE_NOTIFICATION) ->andWhere($queryBuilder->expr()->eq(self::COLUMN_OWNER_ID, ':user_id')) - ->setParameter('user_id', $userId, PDO::PARAM_INT) + ->setParameter('user_id', $userId, ParameterType::INTEGER) ->orderBy(self::COLUMN_ID, 'DESC'); if ($query === null) { @@ -284,7 +283,7 @@ public function delete(int $notificationId): void $query ->delete(self::TABLE_NOTIFICATION) ->where($query->expr()->eq(self::COLUMN_ID, ':id')) - ->setParameter('id', $notificationId, PDO::PARAM_INT); + ->setParameter('id', $notificationId, ParameterType::INTEGER); $query->executeStatement(); } diff --git a/src/lib/Persistence/Legacy/URL/Gateway/DoctrineDatabase.php b/src/lib/Persistence/Legacy/URL/Gateway/DoctrineDatabase.php index a89a78c7d8..3e823ef189 100644 --- a/src/lib/Persistence/Legacy/URL/Gateway/DoctrineDatabase.php +++ b/src/lib/Persistence/Legacy/URL/Gateway/DoctrineDatabase.php @@ -107,7 +107,7 @@ public function findUsages($id): array 'c', ContentGateway::CONTENT_FIELD_TABLE, 'f_def', - $expr->and( + (string) $expr->and( 'c.id = f_def.contentobject_id', 'c.current_version = f_def.version' ) @@ -116,7 +116,7 @@ public function findUsages($id): array 'f_def', self::URL_LINK_TABLE, 'u_lnk', - $expr->and( + (string) $expr->and( 'f_def.id = u_lnk.contentobject_attribute_id', 'f_def.version = u_lnk.contentobject_attribute_version' ) @@ -223,7 +223,7 @@ protected function createSelectQuery(): QueryBuilder { return $this->connection ->createQueryBuilder() - ->select($this->getSelectColumns()) + ->select(...$this->getSelectColumns()) ->from(self::URL_TABLE, 'url'); } diff --git a/src/lib/Persistence/Legacy/URL/Query/CriterionHandler/Base.php b/src/lib/Persistence/Legacy/URL/Query/CriterionHandler/Base.php index 4af5d5c243..5040f0ee66 100644 --- a/src/lib/Persistence/Legacy/URL/Query/CriterionHandler/Base.php +++ b/src/lib/Persistence/Legacy/URL/Query/CriterionHandler/Base.php @@ -73,7 +73,7 @@ protected function joinContentObjectAttribute(QueryBuilder $query): void 'u_lnk', ContentGateway::CONTENT_FIELD_TABLE, 'f_def', - $query->expr()->and( + (string) $query->expr()->and( 'u_lnk.contentobject_attribute_id = f_def.id', 'u_lnk.contentobject_attribute_version = f_def.version' ) diff --git a/src/lib/Persistence/Legacy/User/Role/Gateway/DoctrineDatabase.php b/src/lib/Persistence/Legacy/User/Role/Gateway/DoctrineDatabase.php index 9ec40d9282..430e544618 100644 --- a/src/lib/Persistence/Legacy/User/Role/Gateway/DoctrineDatabase.php +++ b/src/lib/Persistence/Legacy/User/Role/Gateway/DoctrineDatabase.php @@ -382,7 +382,7 @@ private function buildLoadRoleAssignmentsQuery(array $columns, int $roleId): Que 'content_object', (string) $expr->and( $expr->eq('user_role.contentobject_id', 'content_object.id'), - $expr->eq('content_object.status', ContentInfo::STATUS_PUBLISHED) + $expr->eq('content_object.status', (string) ContentInfo::STATUS_PUBLISHED) ) )->where( $expr->eq( diff --git a/src/lib/Search/Common/Indexer.php b/src/lib/Search/Common/Indexer.php index 600041d310..84c29af0f5 100644 --- a/src/lib/Search/Common/Indexer.php +++ b/src/lib/Search/Common/Indexer.php @@ -50,9 +50,9 @@ protected function getContentDbFieldsStmt(array $fields): Result { $query = $this->connection->createQueryBuilder(); $query - ->select($fields) + ->select(...$fields) ->from(ContentGateway::CONTENT_ITEM_TABLE) - ->where($query->expr()->eq('status', ContentInfo::STATUS_PUBLISHED)); + ->where($query->expr()->eq('status', (string) ContentInfo::STATUS_PUBLISHED)); return $query->executeQuery(); } diff --git a/src/lib/Search/Legacy/Content/Common/Gateway/CriterionHandler/FieldValue/Handler.php b/src/lib/Search/Legacy/Content/Common/Gateway/CriterionHandler/FieldValue/Handler.php index 2fd844b3b2..9706f5ccd6 100644 --- a/src/lib/Search/Legacy/Content/Common/Gateway/CriterionHandler/FieldValue/Handler.php +++ b/src/lib/Search/Legacy/Content/Common/Gateway/CriterionHandler/FieldValue/Handler.php @@ -194,7 +194,7 @@ private function createNamedParameter(QueryBuilder $outerQuery, string $column, break; default: $parameterValue = $value; - $parameterType = null; + $parameterType = ParameterType::STRING; } return $outerQuery->createNamedParameter( @@ -206,7 +206,7 @@ private function createNamedParameter(QueryBuilder $outerQuery, string $column, /** * @param array $values */ - private function getParamArrayType(array $values): int + private function getParamArrayType(array $values): ArrayParameterType { if (empty($values)) { throw new InvalidArgumentException('$values', 'Array cannot be empty'); @@ -223,7 +223,7 @@ private function getParamArrayType(array $values): int } } - $arrayValueTypes = array_unique($types); + $arrayValueTypes = array_values(array_unique($types, SORT_REGULAR)); // Fallback to ArrayParameterType::STRING return $arrayValueTypes[0] ?? ArrayParameterType::STRING; diff --git a/src/lib/Search/Legacy/Content/Common/Gateway/CriterionHandler/LanguageCode.php b/src/lib/Search/Legacy/Content/Common/Gateway/CriterionHandler/LanguageCode.php index 2f4717c8cc..f42ecac4c6 100644 --- a/src/lib/Search/Legacy/Content/Common/Gateway/CriterionHandler/LanguageCode.php +++ b/src/lib/Search/Legacy/Content/Common/Gateway/CriterionHandler/LanguageCode.php @@ -54,7 +54,7 @@ public function handle( $criterion->matchAlwaysAvailable ) ), - 0 + '0' ); } } diff --git a/src/lib/Search/Legacy/Content/Common/Gateway/CriterionHandler/MapLocationDistance.php b/src/lib/Search/Legacy/Content/Common/Gateway/CriterionHandler/MapLocationDistance.php index 6c9fed9f90..135f43bef9 100644 --- a/src/lib/Search/Legacy/Content/Common/Gateway/CriterionHandler/MapLocationDistance.php +++ b/src/lib/Search/Legacy/Content/Common/Gateway/CriterionHandler/MapLocationDistance.php @@ -176,7 +176,7 @@ public function handle( 'f_def', DoctrineStorage::MAP_LOCATION_TABLE, 'map', - $expr->and( + (string) $expr->and( 'map.contentobject_version = f_def.version', 'map.contentobject_attribute_id = f_def.id', ...$boundingConstraints diff --git a/src/lib/Search/Legacy/Content/Common/Gateway/SortClauseHandler/Random/MySqlRandom.php b/src/lib/Search/Legacy/Content/Common/Gateway/SortClauseHandler/Random/MySqlRandom.php index a20b543fc0..c18841af5c 100644 --- a/src/lib/Search/Legacy/Content/Common/Gateway/SortClauseHandler/Random/MySqlRandom.php +++ b/src/lib/Search/Legacy/Content/Common/Gateway/SortClauseHandler/Random/MySqlRandom.php @@ -8,15 +8,15 @@ namespace Ibexa\Core\Search\Legacy\Content\Common\Gateway\SortClauseHandler\Random; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform; -use Doctrine\DBAL\Platforms\MySQLPlatform; use Ibexa\Core\Search\Legacy\Content\Common\Gateway\SortClauseHandler\AbstractRandom; class MySqlRandom extends AbstractRandom { public function supportsPlatform(AbstractPlatform $platform): bool { - return $platform instanceof MySQLPlatform; + return $platform instanceof AbstractMySQLPlatform; } public function getRandomFunctionName(?int $seed): string diff --git a/src/lib/Search/Legacy/Content/Common/Gateway/SortClauseHandler/Random/SqlLiteRandom.php b/src/lib/Search/Legacy/Content/Common/Gateway/SortClauseHandler/Random/SqlLiteRandom.php index 6a4f02503b..b0020ea141 100644 --- a/src/lib/Search/Legacy/Content/Common/Gateway/SortClauseHandler/Random/SqlLiteRandom.php +++ b/src/lib/Search/Legacy/Content/Common/Gateway/SortClauseHandler/Random/SqlLiteRandom.php @@ -9,14 +9,14 @@ namespace Ibexa\Core\Search\Legacy\Content\Common\Gateway\SortClauseHandler\Random; use Doctrine\DBAL\Platforms\AbstractPlatform; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; use Ibexa\Core\Search\Legacy\Content\Common\Gateway\SortClauseHandler\AbstractRandom; class SqlLiteRandom extends AbstractRandom { public function supportsPlatform(AbstractPlatform $platform): bool { - return $platform instanceof SqlitePlatform; + return $platform instanceof SQLitePlatform; } public function getRandomFunctionName(?int $seed): string diff --git a/src/lib/Search/Legacy/Content/Gateway/CriterionHandler/Visibility.php b/src/lib/Search/Legacy/Content/Gateway/CriterionHandler/Visibility.php index 0a54382515..da9c9eb24c 100644 --- a/src/lib/Search/Legacy/Content/Gateway/CriterionHandler/Visibility.php +++ b/src/lib/Search/Legacy/Content/Gateway/CriterionHandler/Visibility.php @@ -39,22 +39,22 @@ public function handle( $expression = $queryBuilder->expr()->and( $queryBuilder->expr()->eq( 'subquery_location.is_hidden', - 0 + '0' ), $queryBuilder->expr()->eq( 'subquery_location.is_invisible', - 0 + '0' ) ); } else { $expression = $queryBuilder->expr()->or( $queryBuilder->expr()->eq( 'subquery_location.is_hidden', - 1 + '1' ), $queryBuilder->expr()->eq( 'subquery_location.is_invisible', - 1 + '1' ) ); } diff --git a/src/lib/Search/Legacy/Content/Gateway/DoctrineDatabase.php b/src/lib/Search/Legacy/Content/Gateway/DoctrineDatabase.php index 4d4e14554e..abd9c2b122 100644 --- a/src/lib/Search/Legacy/Content/Gateway/DoctrineDatabase.php +++ b/src/lib/Search/Legacy/Content/Gateway/DoctrineDatabase.php @@ -135,11 +135,11 @@ private function getQueryCondition( $this->criteriaConverter->convertCriteria($query, $filter, $languageFilter), $expr->eq( 'c.status', - ContentInfo::STATUS_PUBLISHED + (string) ContentInfo::STATUS_PUBLISHED ), $expr->eq( 'v.status', - VersionInfo::STATUS_PUBLISHED + (string) VersionInfo::STATUS_PUBLISHED ) ); @@ -252,7 +252,7 @@ private function getContentInfoList( } $query->setMaxResults($limit); - $query->setFirstResult($offset); + $query->setFirstResult($offset ?? 0); $statement = $query->executeQuery(); diff --git a/tests/bundle/Core/Resources/config/doctrine.php b/tests/bundle/Core/Resources/config/doctrine.php index ebbf226763..49dee328c8 100644 --- a/tests/bundle/Core/Resources/config/doctrine.php +++ b/tests/bundle/Core/Resources/config/doctrine.php @@ -8,37 +8,15 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; -use Ibexa\DoctrineSchema\Database\DbPlatform\PostgreSqlDbPlatform; -use Ibexa\DoctrineSchema\Database\DbPlatform\SqliteDbPlatform; -use RuntimeException; - return static function (ContainerConfigurator $container): void { if (!isset($_ENV['DATABASE_URL'])) { $_ENV['DATABASE_URL'] = 'sqlite://:memory:'; } - $platformsMap = [ - 'sqlite' => SqliteDbPlatform::class, - 'postgres' => PostgreSqlDbPlatform::class, - 'postgresql' => PostgreSqlDbPlatform::class, - 'pgsql' => PostgreSqlDbPlatform::class, - ]; - - $scheme = parse_url($_ENV['DATABASE_URL'], PHP_URL_SCHEME); - if (!is_string($scheme)) { - throw new RuntimeException(sprintf( - 'Failed parsing "%s". Unable to determine scheme.', - $_ENV['DATABASE_URL'], - )); - } - - $platform = $platformsMap[$scheme] ?? null; - $container->extension('doctrine', [ 'dbal' => [ 'url' => '%env(DATABASE_URL)%', 'logging' => false, - 'platform_service' => $platform, 'use_savepoints' => true, ], ]); diff --git a/tests/bundle/Core/Resources/services/fixture-services.yaml b/tests/bundle/Core/Resources/services/fixture-services.yaml index 28c7437394..68007ed453 100644 --- a/tests/bundle/Core/Resources/services/fixture-services.yaml +++ b/tests/bundle/Core/Resources/services/fixture-services.yaml @@ -8,6 +8,7 @@ services: arguments: - '@doctrine.dbal.default_connection' - '@Ibexa\Contracts\DoctrineSchema\SchemaAssetsFilterBypassInterface' + - !php/const Ibexa\Contracts\DoctrineSchema\Database\DefaultTableOptions::AS_ARRAY # repeat part of DIC setup to avoid loading DoctrineSchemaBundle, which is where this # alias normally comes from (see its Resources/config/api.yaml) diff --git a/tests/integration/Core/Persistence/Filter/Doctrine/FilteringQueryBuilderTest.php b/tests/integration/Core/Persistence/Filter/Doctrine/FilteringQueryBuilderTest.php index deafd9946f..3933a08000 100644 --- a/tests/integration/Core/Persistence/Filter/Doctrine/FilteringQueryBuilderTest.php +++ b/tests/integration/Core/Persistence/Filter/Doctrine/FilteringQueryBuilderTest.php @@ -29,7 +29,7 @@ protected function setUp(): void $connectionMock = $this->createMock(Connection::class); $connectionMock->method('getDatabasePlatform')->willReturn($platform); - $connectionMock->method('getExpressionBuilder')->willReturn( + $connectionMock->method('createExpressionBuilder')->willReturn( new ExpressionBuilder($connectionMock) ); $this->queryBuilder = new FilteringQueryBuilder($connectionMock); diff --git a/tests/integration/Core/Repository/Parallel/BaseParallelTestCase.php b/tests/integration/Core/Repository/Parallel/BaseParallelTestCase.php index 44072903ef..85ff1fe6a0 100644 --- a/tests/integration/Core/Repository/Parallel/BaseParallelTestCase.php +++ b/tests/integration/Core/Repository/Parallel/BaseParallelTestCase.php @@ -8,6 +8,8 @@ namespace Ibexa\Tests\Integration\Core\Repository\Parallel; +use Ibexa\Contracts\DoctrineSchema\Database\DatabasePlatformName; +use Ibexa\Contracts\DoctrineSchema\Database\DatabasePlatformResolver; use Ibexa\Tests\Core\Repository\Parallel\ParallelProcessList; use Ibexa\Tests\Integration\Core\Repository\BaseTestCase; use Jenner\SimpleFork\Process; @@ -19,9 +21,9 @@ protected function setUp(): void parent::setUp(); $connection = $this->getRawDatabaseConnection(); - $dbms = $connection->getDatabasePlatform()->getName(); + $dbms = DatabasePlatformResolver::resolveName($connection->getDatabasePlatform()); - if ($dbms == 'sqlite') { + if ($dbms === DatabasePlatformName::SQLite) { self::markTestSkipped('Can not run parallel test on sqlite'); } } @@ -31,7 +33,7 @@ protected function addParallelProcess(ParallelProcessList $list, callable $callb $connection = $this->getRawDatabaseConnection(); $process = new Process(static function () use ($callback, $connection) { - $connection->connect(); + $connection->executeQuery('SELECT 1'); $callback(); $connection->close(); }); @@ -53,6 +55,6 @@ protected function runParallelProcesses(ParallelProcessList $list): void $process->wait(); } - $connection->connect(); + $connection->executeQuery('SELECT 1'); } } diff --git a/tests/integration/Core/Repository/URLAliasServiceTest.php b/tests/integration/Core/Repository/URLAliasServiceTest.php index 5ef2d1806a..e684ffb24d 100644 --- a/tests/integration/Core/Repository/URLAliasServiceTest.php +++ b/tests/integration/Core/Repository/URLAliasServiceTest.php @@ -8,6 +8,7 @@ namespace Ibexa\Tests\Integration\Core\Repository; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\ParameterType; use Exception; use Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException; use Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException; @@ -1361,7 +1362,7 @@ static function (Connection $connection) use ($folderLocation) { ) ); - return $queryBuilder->execute(); + return $queryBuilder->executeStatement(); } ); @@ -1428,7 +1429,7 @@ static function (Connection $connection) use ($nestedFolderLocation) { $expr = $queryBuilder->expr(); $queryBuilder ->update(Gateway::TABLE) - ->set('link', $queryBuilder->createPositionalParameter(666, \PDO::PARAM_INT)) + ->set('link', $queryBuilder->createPositionalParameter(666, ParameterType::INTEGER)) ->where( $expr->eq( 'action', @@ -1440,7 +1441,7 @@ static function (Connection $connection) use ($nestedFolderLocation) { ->andWhere( $expr->eq( 'is_original', - $queryBuilder->createPositionalParameter(0, \PDO::PARAM_INT) + $queryBuilder->createPositionalParameter(0, ParameterType::INTEGER) ) ) ->andWhere( @@ -1448,7 +1449,7 @@ static function (Connection $connection) use ($nestedFolderLocation) { ) ; - return $queryBuilder->execute(); + return $queryBuilder->executeStatement(); } ); diff --git a/tests/lib/FieldType/Url/Gateway/DoctrineStorageTest.php b/tests/lib/FieldType/Url/Gateway/DoctrineStorageTest.php index e0c168a5ba..f6848c42b6 100644 --- a/tests/lib/FieldType/Url/Gateway/DoctrineStorageTest.php +++ b/tests/lib/FieldType/Url/Gateway/DoctrineStorageTest.php @@ -7,6 +7,7 @@ namespace Ibexa\Tests\Core\FieldType\Url\Gateway; +use Doctrine\DBAL\ParameterType; use Ibexa\Core\FieldType\Url\UrlStorage\Gateway; use Ibexa\Core\FieldType\Url\UrlStorage\Gateway\DoctrineStorage; use Ibexa\Core\Persistence\Legacy\URL\Gateway\DoctrineDatabase; @@ -84,7 +85,7 @@ public function testInsertUrl() ':id' ) ) - ->setParameter('id', $id, \PDO::PARAM_INT) + ->setParameter('id', $id, ParameterType::INTEGER) ; $statement = $query->executeQuery(); @@ -128,7 +129,7 @@ public function testLinkUrl() ->where( $query->expr()->eq($this->connection->quoteIdentifier('url_id'), ':urlId') ) - ->setParameter('urlId', $urlId, \PDO::PARAM_INT) + ->setParameter('urlId', $urlId, ParameterType::INTEGER) ; $statement = $query->executeQuery(); diff --git a/tests/lib/Persistence/DatabaseConnectionFactory.php b/tests/lib/Persistence/DatabaseConnectionFactory.php index a739a64b2c..af990bb957 100644 --- a/tests/lib/Persistence/DatabaseConnectionFactory.php +++ b/tests/lib/Persistence/DatabaseConnectionFactory.php @@ -8,10 +8,10 @@ namespace Ibexa\Tests\Core\Persistence; -use Doctrine\Common\EventManager; use Doctrine\DBAL\Configuration; use Doctrine\DBAL\Connection; use Doctrine\DBAL\DriverManager; +use Doctrine\DBAL\Tools\DsnParser; /** * Database connection factory for integration tests. @@ -20,6 +20,16 @@ */ class DatabaseConnectionFactory { + private const array DSN_SCHEME_MAP = [ + 'sqlite' => 'pdo_sqlite', + 'sqlite3' => 'sqlite3', + 'mysql' => 'pdo_mysql', + 'mysql2' => 'pdo_mysql', + 'postgres' => 'pdo_pgsql', + 'postgresql' => 'pdo_pgsql', + 'pgsql' => 'pdo_pgsql', + ]; + /** * Associative array of [driver => AbstractPlatform]. * @@ -27,8 +37,6 @@ class DatabaseConnectionFactory */ private array $databasePlatforms; - private EventManager $eventManager; - /** * Connection Pool for re-using an already created connection. * @@ -38,17 +46,24 @@ class DatabaseConnectionFactory */ private static ?array $connectionPool = null; + private static function normalizeDsn(string $databaseURL): string + { + if (str_starts_with($databaseURL, 'sqlite://:memory:')) { + return 'sqlite:///:memory:'; + } + + return $databaseURL; + } + /** * @phpstan-param array $databasePlatforms */ - public function __construct(iterable $databasePlatforms, EventManager $eventManager) + public function __construct(iterable $databasePlatforms) { $this->databasePlatforms = []; foreach ($databasePlatforms as $databasePlatform) { $this->databasePlatforms[$databasePlatform->getDriverName()] = $databasePlatform; } - - $this->eventManager = $eventManager; } /** @@ -62,24 +77,17 @@ public function createConnection(string $databaseURL): Connection return self::$connectionPool[$databaseURL]; } - $params = ['url' => $databaseURL]; + $params = (new DsnParser(self::DSN_SCHEME_MAP))->parse(self::normalizeDsn($databaseURL)); // set DbPlatform based on a database url scheme $scheme = parse_url($databaseURL, PHP_URL_SCHEME); $driverName = 'pdo_' . $scheme; $config = new Configuration(); if (isset($this->databasePlatforms[$driverName])) { - $params['platform'] = $this->databasePlatforms[$driverName]; - // add predefined event subscribers only for the relevant connection - $params['platform']->addEventSubscribers($this->eventManager); - $params['platform']->configure($config); + $this->databasePlatforms[$driverName]->configure($config); } - self::$connectionPool[$databaseURL] = DriverManager::getConnection( - $params, - $config, - $this->eventManager - ); + self::$connectionPool[$databaseURL] = DriverManager::getConnection($params, $config); self::$connectionPool[$databaseURL]->setNestTransactionsWithSavepoints(true); return self::$connectionPool[$databaseURL]; diff --git a/tests/lib/Persistence/Doctrine/DatabasePlatformResolverTest.php b/tests/lib/Persistence/Doctrine/DatabasePlatformResolverTest.php deleted file mode 100644 index bbaa2f0b03..0000000000 --- a/tests/lib/Persistence/Doctrine/DatabasePlatformResolverTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - */ - public function provideDataForTestResolveName(): iterable - { - yield 'mysql' => [new MySQLPlatform(), DatabasePlatformName::Mysql]; - yield 'mariadb' => [new MariaDBPlatform(), DatabasePlatformName::Mysql]; - yield 'postgresql' => [new PostgreSQLPlatform(), DatabasePlatformName::Postgresql]; - yield 'sqlite' => [new SqlitePlatform(), DatabasePlatformName::Sqlite]; - } - - /** - * @dataProvider provideDataForTestResolveName - */ - public function testResolveName(AbstractPlatform $platform, DatabasePlatformName $expected): void - { - self::assertSame($expected, DatabasePlatformResolver::resolveName($platform)); - } - - public function testResolveNameThrowsForUnsupportedPlatform(): void - { - $this->expectException(InvalidArgumentException::class); - - DatabasePlatformResolver::resolveName(new OraclePlatform()); - } -} diff --git a/tests/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabaseTest.php b/tests/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabaseTest.php index dbf60215c9..922405be3f 100644 --- a/tests/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabaseTest.php +++ b/tests/lib/Persistence/Legacy/Content/Gateway/DoctrineDatabaseTest.php @@ -379,8 +379,8 @@ public function testUpdateVersion() ->from(Gateway::CONTENT_VERSION_TABLE) ->where( $expr->and( - $expr->eq('contentobject_id', 10), - $expr->eq('version', 2) + $expr->eq('contentobject_id', '10'), + $expr->eq('version', '2') ) ) ); @@ -1473,8 +1473,8 @@ public function testUpdateAlwaysAvailableFlagRemove(): void ->from(Gateway::CONTENT_FIELD_TABLE) ->where( $query->expr()->and( - $query->expr()->eq('contentobject_id', 103), - $query->expr()->eq('version', 1) + $query->expr()->eq('contentobject_id', '103'), + $query->expr()->eq('version', '1') ) ) ); diff --git a/tests/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabaseTest.php b/tests/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabaseTest.php index 7864b1a976..39acae924b 100644 --- a/tests/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabaseTest.php +++ b/tests/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabaseTest.php @@ -7,7 +7,6 @@ namespace Ibexa\Tests\Core\Persistence\Legacy\Content\Location\Gateway; -use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Query\QueryBuilder; use Ibexa\Contracts\Core\Persistence\Content\Location; @@ -363,7 +362,7 @@ public function testMoveSubtreeAssignmentUpdate() 'is_hidden' ) ->from(DoctrineDatabase::NODE_ASSIGNMENT_TABLE) - ->where($query->expr()->eq('contentobject_id', 67)) + ->where($query->expr()->eq('contentobject_id', '67')) ); } @@ -628,7 +627,7 @@ public function testCreateLocationValues($field, $value) $query ->select($field) ->from(Gateway::CONTENT_TREE_TABLE) - ->where($query->expr()->eq('node_id', 228)) + ->where($query->expr()->eq('node_id', '228')) ); } @@ -753,7 +752,7 @@ private function buildGenericNodeSelectContentWithParentQuery( $query = $this->getDatabaseConnection()->createQueryBuilder(); $expr = $query->expr(); $query - ->select($fields) + ->select(...$fields) ->from($nodeTable) ->where( $expr->eq( @@ -897,7 +896,7 @@ public function testUpdateLocationsContentVersionNo() )->where( $query->expr()->eq( 'contentobject_id', - 4096 + '4096' ) ) ); @@ -917,7 +916,7 @@ public function testDeleteNodeAssignment() ->select('count(*)') ->from(DoctrineDatabase::NODE_ASSIGNMENT_TABLE) ->where( - $query->expr()->eq('contentobject_id', 11) + $query->expr()->eq('contentobject_id', '11') ) ); } @@ -932,7 +931,7 @@ public function testDeleteNodeAssignmentWithSecondArgument() ->select('count(*)') ->from(DoctrineDatabase::NODE_ASSIGNMENT_TABLE) ->where( - $query->expr()->eq('contentobject_id', 11) + $query->expr()->eq('contentobject_id', '11') ); $statement = $query->executeQuery(); $nodeAssignmentsCount = (int)$statement->fetchOne(); @@ -946,7 +945,7 @@ public function testDeleteNodeAssignmentWithSecondArgument() ->select('count(*)') ->from(DoctrineDatabase::NODE_ASSIGNMENT_TABLE) ->where( - $query->expr()->eq('contentobject_id', 11) + $query->expr()->eq('contentobject_id', '11') ) ); } @@ -1024,7 +1023,7 @@ public function testConvertNodeAssignments($field, $value) if ($field === 'modified_subnode') { $statement = $query->executeQuery(); - $result = $statement->fetch(FetchMode::ASSOCIATIVE); + $result = $statement->fetchAssociative(); self::assertGreaterThanOrEqual($value, $result); } else { $this->assertQueryResult( @@ -1198,7 +1197,7 @@ public function testSetSectionForSubtree() $query ->select('id') ->from(ContentGateway::CONTENT_ITEM_TABLE) - ->where($query->expr()->eq('section_id', 23)) + ->where($query->expr()->eq('section_id', '23')) ); } diff --git a/tests/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabaseTrashTest.php b/tests/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabaseTrashTest.php index e73158b309..0172836e21 100644 --- a/tests/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabaseTrashTest.php +++ b/tests/lib/Persistence/Legacy/Content/Location/Gateway/DoctrineDatabaseTrashTest.php @@ -397,7 +397,7 @@ public function testRemoveElementFromTrash() $query ->select('*') ->from(Gateway::TRASH_TABLE) - ->where($query->expr()->eq('node_id', 71)) + ->where($query->expr()->eq('node_id', '71')) ); } diff --git a/tests/lib/Persistence/Legacy/Content/Type/Gateway/DoctrineDatabaseTest.php b/tests/lib/Persistence/Legacy/Content/Type/Gateway/DoctrineDatabaseTest.php index af898a6bcd..800f5a982b 100644 --- a/tests/lib/Persistence/Legacy/Content/Type/Gateway/DoctrineDatabaseTest.php +++ b/tests/lib/Persistence/Legacy/Content/Type/Gateway/DoctrineDatabaseTest.php @@ -983,7 +983,7 @@ public function testDeleteFieldDefinitionsForTypeExisting() ->where( $countAffectedAttr->expr()->eq( 'content_type_id', - 1 + '1' ) ); // 1 left with version 1 diff --git a/tests/lib/Persistence/Legacy/Filter/BaseCriterionVisitorQueryBuilderTestCase.php b/tests/lib/Persistence/Legacy/Filter/BaseCriterionVisitorQueryBuilderTestCase.php index 0372364174..c6585e001f 100644 --- a/tests/lib/Persistence/Legacy/Filter/BaseCriterionVisitorQueryBuilderTestCase.php +++ b/tests/lib/Persistence/Legacy/Filter/BaseCriterionVisitorQueryBuilderTestCase.php @@ -81,7 +81,7 @@ private function getQueryBuilder(): FilteringQueryBuilder { $connectionMock = $this->createMock(Connection::class); $connectionMock - ->method('getExpressionBuilder') + ->method('createExpressionBuilder') ->willReturn( new ExpressionBuilder($connectionMock) ); diff --git a/tests/lib/Persistence/Legacy/Filter/SortClauseQueryBuilder/Location/BaseLocationSortClauseQueryBuilderTest.php b/tests/lib/Persistence/Legacy/Filter/SortClauseQueryBuilder/Location/BaseLocationSortClauseQueryBuilderTest.php index 1ab851fee3..e12ff79dd7 100644 --- a/tests/lib/Persistence/Legacy/Filter/SortClauseQueryBuilder/Location/BaseLocationSortClauseQueryBuilderTest.php +++ b/tests/lib/Persistence/Legacy/Filter/SortClauseQueryBuilder/Location/BaseLocationSortClauseQueryBuilderTest.php @@ -20,7 +20,7 @@ final class BaseLocationSortClauseQueryBuilderTest extends TestCase { public function testLegacyImplementationIsSupported(): void { - $connection = DriverManager::getConnection(['url' => 'sqlite:///:memory:']); + $connection = DriverManager::getConnection(['driver' => 'pdo_sqlite', 'memory' => true]); $queryBuilder = new FilteringQueryBuilder($connection); $sortClause = new class() implements FilteringSortClause { @@ -39,24 +39,18 @@ public function accepts(FilteringSortClause $sortClause): bool } }; - $builder->buildQuery($queryBuilder, $sortClause); + $queryBuilder->select('content.id')->from('ibexa_content', 'content'); - self::assertSame( - ['ibexa_sort_location.depth AS ibexa_filter_sort_ibexa_sort_location_depth'], - $queryBuilder->getQueryPart('select') - ); + $builder->buildQuery($queryBuilder, $sortClause); - $joins = $queryBuilder->getQueryPart('join'); - self::assertArrayHasKey('content', $joins); - self::assertCount(1, $joins['content']); - self::assertSame(LocationGateway::CONTENT_TREE_TABLE, $joins['content'][0]['joinTable']); - self::assertSame('ibexa_sort_location', $joins['content'][0]['joinAlias']); self::assertSame( - '(content.id = ibexa_sort_location.contentobject_id) AND (ibexa_sort_location.node_id = ibexa_sort_location.main_node_id)', - (string)$joins['content'][0]['joinCondition'] + 'SELECT content.id, ibexa_sort_location.depth AS ibexa_filter_sort_ibexa_sort_location_depth' + . ' FROM ibexa_content content' + . ' INNER JOIN ' . LocationGateway::CONTENT_TREE_TABLE . ' ibexa_sort_location' + . ' ON (content.id = ibexa_sort_location.contentobject_id)' + . ' AND (ibexa_sort_location.node_id = ibexa_sort_location.main_node_id)' + . ' ORDER BY ibexa_filter_sort_ibexa_sort_location_depth ASC', + $queryBuilder->getSQL() ); - - $orderBy = $queryBuilder->getQueryPart('orderBy'); - self::assertSame(['ibexa_filter_sort_ibexa_sort_location_depth ASC'], $orderBy); } } diff --git a/tests/lib/Persistence/Legacy/SharedGateway/GatewayFactoryTest.php b/tests/lib/Persistence/Legacy/SharedGateway/GatewayFactoryTest.php index a3e5d4e8e5..be52286391 100644 --- a/tests/lib/Persistence/Legacy/SharedGateway/GatewayFactoryTest.php +++ b/tests/lib/Persistence/Legacy/SharedGateway/GatewayFactoryTest.php @@ -30,7 +30,7 @@ final class GatewayFactoryTest extends TestCase public function setUp(): void { $gateways = [ - Platforms\SqlitePlatform::class => new SqliteGateway($this->createMock(Connection::class)), + Platforms\SQLitePlatform::class => new SqliteGateway($this->createMock(Connection::class)), ]; $this->factory = new GatewayFactory( @@ -63,7 +63,7 @@ public function testBuildSharedGateway( public function getTestBuildSharedGatewayData(): Traversable { $databasePlatformGatewayPairs = [ - [new Platforms\SqlitePlatform(), SqliteGateway::class], + [new Platforms\SQLitePlatform(), SqliteGateway::class], [new Platforms\MySQL80Platform(), FallbackGateway::class], [new Platforms\MySQLPlatform(), FallbackGateway::class], [new Platforms\PostgreSQLPlatform(), FallbackGateway::class], @@ -71,7 +71,6 @@ public function getTestBuildSharedGatewayData(): Traversable foreach ($databasePlatformGatewayPairs as $databasePlatformGatewayPair) { [$databasePlatform, $sharedGateway] = $databasePlatformGatewayPair; - /** @var \Doctrine\DBAL\Platforms\AbstractPlatform $databasePlatform */ $connectionMock = $this ->createMock(Connection::class); $connectionMock diff --git a/tests/lib/Persistence/Legacy/TestCase.php b/tests/lib/Persistence/Legacy/TestCase.php index 39a5592456..9725e43894 100644 --- a/tests/lib/Persistence/Legacy/TestCase.php +++ b/tests/lib/Persistence/Legacy/TestCase.php @@ -7,16 +7,16 @@ namespace Ibexa\Tests\Core\Persistence\Legacy; -use Doctrine\Common\EventManager as DoctrineEventManager; use Doctrine\DBAL\Connection; use Doctrine\DBAL\ConnectionException; use Doctrine\DBAL\Exception as DBALException; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; use Doctrine\DBAL\Query\QueryBuilder; use Ibexa\Contracts\Core\Test\Persistence\Fixture\FileFixtureFactory; use Ibexa\Contracts\Core\Test\Persistence\Fixture\FixtureImporter; use Ibexa\Contracts\Core\Test\Persistence\Fixture\YamlFixture; use Ibexa\Contracts\Core\Test\Repository\SetupFactory\Legacy; +use Ibexa\Contracts\DoctrineSchema\Database\DefaultTableOptions; use Ibexa\Core\Persistence\Doctrine\JoinedTablesTracker; use Ibexa\Core\Persistence\Legacy\Filter\Query\LimitedCountQueryBuilder; use Ibexa\Core\Persistence\Legacy\SharedGateway; @@ -92,10 +92,8 @@ protected function getDsn() final public function getDatabaseConnection(): Connection { if (!$this->connection) { - $eventManager = new DoctrineEventManager(); $connectionFactory = new DatabaseConnectionFactory( - [new SqliteDbPlatform()], - $eventManager + [new SqliteDbPlatform()] ); try { @@ -118,7 +116,7 @@ final public function getSharedGateway(): SharedGateway\Gateway $factory = new SharedGateway\GatewayFactory( new SharedGateway\DatabasePlatform\FallbackGateway($connection), [ - SqlitePlatform::class => new SharedGateway\DatabasePlatform\SqliteGateway($connection), + SQLitePlatform::class => new SharedGateway\DatabasePlatform\SqliteGateway($connection), ] ); @@ -135,7 +133,11 @@ final public function getSharedGateway(): SharedGateway\Gateway protected function setUp(): void { try { - $schemaImporter = new LegacySchemaImporter($this->getDatabaseConnection(), new SchemaAssetsFilterBypass()); + $schemaImporter = new LegacySchemaImporter( + $this->getDatabaseConnection(), + new SchemaAssetsFilterBypass(), + DefaultTableOptions::AS_ARRAY + ); $schemaImporter->importSchema( dirname(__DIR__, 4) . '/src/bundle/Core/Resources/config/storage/legacy/schema.yaml' diff --git a/tests/lib/Persistence/Legacy/URL/Query/CriterionHandler/CriterionHandlerTestCase.php b/tests/lib/Persistence/Legacy/URL/Query/CriterionHandler/CriterionHandlerTestCase.php index a5f0408987..00525ff4bd 100644 --- a/tests/lib/Persistence/Legacy/URL/Query/CriterionHandler/CriterionHandlerTestCase.php +++ b/tests/lib/Persistence/Legacy/URL/Query/CriterionHandler/CriterionHandlerTestCase.php @@ -57,10 +57,8 @@ protected function mockConverterForLogicalOperator( ): CriteriaConverter { $compositeExpression = new CompositeExpression( $expressionType, - [ - $fooExpr, - $barExpr, - ] + $fooExpr, + $barExpr ); $expressionBuilder = $this->createMock(ExpressionBuilder::class); $expressionBuilder diff --git a/tests/lib/Persistence/Legacy/URL/Query/CriterionHandler/VisibleOnlyTest.php b/tests/lib/Persistence/Legacy/URL/Query/CriterionHandler/VisibleOnlyTest.php index a0d4629f37..8dfa4a546f 100644 --- a/tests/lib/Persistence/Legacy/URL/Query/CriterionHandler/VisibleOnlyTest.php +++ b/tests/lib/Persistence/Legacy/URL/Query/CriterionHandler/VisibleOnlyTest.php @@ -64,7 +64,7 @@ private function createDoctrineQueryBuilder(): QueryBuilder $expressionBuilder = new ExpressionBuilder($connection); $connection ->expects(self::any()) - ->method('getExpressionBuilder') + ->method('createExpressionBuilder') ->willReturn($expressionBuilder); return new QueryBuilder($connection); diff --git a/tests/lib/Repository/LegacySchemaImporter.php b/tests/lib/Repository/LegacySchemaImporter.php index 4278b1e05b..cc2d4fde47 100644 --- a/tests/lib/Repository/LegacySchemaImporter.php +++ b/tests/lib/Repository/LegacySchemaImporter.php @@ -11,8 +11,12 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Schema\Schema as DoctrineSchema; +use Doctrine\DBAL\Schema\SchemaConfig; use Ibexa\Contracts\DoctrineSchema\Exception\InvalidConfigurationException; use Ibexa\Contracts\DoctrineSchema\SchemaAssetsFilterBypassInterface; +use Ibexa\DoctrineSchema\Database\DbPlatform\PostgreSqlDbPlatform; +use Ibexa\DoctrineSchema\Database\DbPlatform\SqliteDbPlatform; +use Ibexa\DoctrineSchema\Database\DbPlatformFactory; use Ibexa\DoctrineSchema\Importer\SchemaImporter; use RuntimeException; @@ -30,10 +34,20 @@ final class LegacySchemaImporter private SchemaAssetsFilterBypassInterface $schemaAssetsFilterBypass; - public function __construct(Connection $connection, SchemaAssetsFilterBypassInterface $schemaAssetsFilterBypass) - { + /** @var array */ + private array $defaultTableOptions; + + /** + * @param array $defaultTableOptions + */ + public function __construct( + Connection $connection, + SchemaAssetsFilterBypassInterface $schemaAssetsFilterBypass, + array $defaultTableOptions + ) { $this->connection = $connection; $this->schemaAssetsFilterBypass = $schemaAssetsFilterBypass; + $this->defaultTableOptions = $defaultTableOptions; } /** @@ -49,8 +63,15 @@ public function importSchema(string $schemaFilePath): void $importer = new SchemaImporter(); try { - $databasePlatform = $this->connection->getDatabasePlatform(); - $schema = $importer->importFromFile($schemaFilePath); + $databasePlatform = $this->getIbexaDatabasePlatform(); + // Tests have to generate the same DDL an installation does, so the schema carries + // the same default table options SchemaBuilder applies in production. + $schemaConfig = new SchemaConfig(); + $schemaConfig->setDefaultTableOptions($this->defaultTableOptions); + $schema = $importer->importFromFile( + $schemaFilePath, + new DoctrineSchema([], [], $schemaConfig) + ); $statements = array_merge( $this->getDropSqlStatementsForExistingSchema( $schema, @@ -96,10 +117,19 @@ private function getDropSqlStatementsForExistingSchema( // cleanup pre-existing database foreach ($tables as $table) { if ($existingSchema->hasTable($table->getName())) { - $statements[] = $databasePlatform->getDropTableSQL($table); + $statements[] = $databasePlatform->getDropTableSQL($table->getName()); } } return $statements; } + + private function getIbexaDatabasePlatform(): AbstractPlatform + { + $driverName = $this->connection->getParams()['driver'] ?? ''; + + return (new DbPlatformFactory([new SqliteDbPlatform(), new PostgreSqlDbPlatform()])) + ->createDatabasePlatformFromDriverName($driverName) + ?? $this->connection->getDatabasePlatform(); + } } diff --git a/tests/lib/Search/Legacy/Content/Common/Gateway/SortClauseHandler/Random/RandomSortClauseHandlerPlatformSupportTest.php b/tests/lib/Search/Legacy/Content/Common/Gateway/SortClauseHandler/Random/RandomSortClauseHandlerPlatformSupportTest.php new file mode 100644 index 0000000000..31102256ca --- /dev/null +++ b/tests/lib/Search/Legacy/Content/Common/Gateway/SortClauseHandler/Random/RandomSortClauseHandlerPlatformSupportTest.php @@ -0,0 +1,81 @@ + $handlerClass + */ + public function testSupportsPlatform( + string $handlerClass, + AbstractPlatform $platform, + bool $expectedSupport + ): void { + self::assertSame( + $expectedSupport, + $this->createHandler($handlerClass, $platform)->supportsPlatform($platform) + ); + } + + /** + * @return iterable, AbstractPlatform, bool}> + */ + public function providePlatformSupport(): iterable + { + yield 'MySQL' => [MySqlRandom::class, new MySQLPlatform(), true]; + yield 'MySQL 8.0' => [MySqlRandom::class, new MySQL80Platform(), true]; + yield 'MySQL 8.4' => [MySqlRandom::class, new MySQL84Platform(), true]; + yield 'MariaDB' => [MySqlRandom::class, new MariaDBPlatform(), true]; + yield 'MariaDB 10.10' => [MySqlRandom::class, new MariaDB1010Platform(), true]; + yield 'MySQL handler rejects PostgreSQL' => [MySqlRandom::class, new PostgreSQLPlatform(), false]; + yield 'MySQL handler rejects SQLite' => [MySqlRandom::class, new SQLitePlatform(), false]; + + yield 'PostgreSQL' => [PgSqlRandom::class, new PostgreSQLPlatform(), true]; + yield 'PostgreSQL handler rejects MariaDB' => [PgSqlRandom::class, new MariaDBPlatform(), false]; + + yield 'SQLite' => [SqlLiteRandom::class, new SQLitePlatform(), true]; + yield 'SQLite handler rejects MySQL' => [SqlLiteRandom::class, new MySQLPlatform(), false]; + } + + /** + * @phpstan-param class-string<\Ibexa\Core\Search\Legacy\Content\Common\Gateway\SortClauseHandler\AbstractRandom> $handlerClass + */ + private function createHandler(string $handlerClass, AbstractPlatform $platform): AbstractRandom + { + $connection = $this->createStub(Connection::class); + $connection + ->method('getDatabasePlatform') + ->willReturn($platform); + + return new $handlerClass($connection); + } +}