diff --git a/.github/workflows/composer-require-checker.yml b/.github/workflows/composer-require-checker.yml index 7817057..64d6d2d 100644 --- a/.github/workflows/composer-require-checker.yml +++ b/.github/workflows/composer-require-checker.yml @@ -11,6 +11,8 @@ on: - 'psalm.xml' push: + branches: + - master paths-ignore: - 'docs/**' - 'README.md' @@ -34,4 +36,4 @@ jobs: os: >- ['ubuntu-latest'] php: >- - ['8.1', '8.2', '8.3'] + ['8.1', '8.2', '8.3', '8.4', '8.5'] diff --git a/.github/workflows/mariadb.yml b/.github/workflows/mariadb.yml index d7e473d..ba2c8f7 100644 --- a/.github/workflows/mariadb.yml +++ b/.github/workflows/mariadb.yml @@ -10,6 +10,8 @@ on: - 'psalm.xml' push: + branches: + - master paths-ignore: - 'docs/**' - 'README.md' @@ -32,34 +34,40 @@ jobs: env: extensions: pdo, pdo_mysql - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest strategy: matrix: - os: - - ubuntu-latest - php: - 8.1 - 8.2 - 8.3 - + - 8.4 + - 8.5 mariadb: - - mariadb:10.4 - - mariadb:10.5 - - mariadb:10.6 - - mariadb:10.7 - - mariadb:10.8 - - mariadb:10.9 - mariadb:latest + include: + - php: 8.5 + mariadb: mariadb:10.4 + - php: 8.5 + mariadb: mariadb:10.5 + - php: 8.5 + mariadb: mariadb:10.6 + - php: 8.5 + mariadb: mariadb:10.7 + - php: 8.5 + mariadb: mariadb:10.8 + - php: 8.5 + mariadb: mariadb:10.9 services: mysql: image: ${{ matrix.mariadb }} env: MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: true - MARIADB_ROOT_PASSWORD: '' - MARIADB_DATABASE: yiitest + MARIADB_DATABASE: translator-message-db-test + MARIADB_USER: yii + MARIADB_PASSWORD: 'q1w2e3r4' ports: - 3306:3306 options: --health-cmd="mariadb-admin ping" --health-interval=10s --health-timeout=5s --health-retries=3 @@ -80,11 +88,21 @@ jobs: - name: Update composer. run: composer self-update - - name: Install db-mysql. - run: composer require yiisoft/db-mysql --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + - name: Remove unused dependencies of DB drivers + run: composer remove --dev yiisoft/db-sqlite yiisoft/db-pgsql yiisoft/db-mssql yiisoft/db-oracle + + - name: Install dependencies with composer + run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - name: Run tests with phpunit. run: vendor/bin/phpunit --testsuite=Mysql --coverage-clover=coverage.xml --colors=always + env: + ENVIRONMENT: ci + YII_MYSQL_DATABASE: translator-message-db-test + YII_MYSQL_HOST: 127.0.0.1 + YII_MYSQL_PORT: 3306 + YII_MYSQL_USER: yii + YII_MYSQL_PASSWORD: q1w2e3r4 - name: Upload coverage to Codecov. if: matrix.php == '8.1' diff --git a/.github/workflows/mssql.yml b/.github/workflows/mssql.yml index d0e80fa..f9431a0 100644 --- a/.github/workflows/mssql.yml +++ b/.github/workflows/mssql.yml @@ -42,6 +42,8 @@ jobs: - 8.1 - 8.2 - 8.3 + - 8.4 + - 8.5 mssql: - server: 2025-latest @@ -49,12 +51,12 @@ jobs: flag: "-C" include: - - php: 8.3 + - php: 8.5 mssql: server: 2019-latest odbc-version: 18 flag: "-C" - - php: 8.3 + - php: 8.5 mssql: server: 2022-latest odbc-version: 18 @@ -81,7 +83,7 @@ jobs: sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18 - name: Create MS SQL Database. - run: docker exec -i mssql /opt/mssql-tools${{ matrix.mssql.odbc-version }}/bin/sqlcmd ${{ matrix.mssql.flag }} -S localhost -U SA -P 'YourStrong!Passw0rd' -Q 'CREATE DATABASE yiitest' + run: docker exec -i mssql /opt/mssql-tools${{ matrix.mssql.odbc-version }}/bin/sqlcmd ${{ matrix.mssql.flag }} -S localhost -U SA -P 'YourStrong!Passw0rd' -Q 'CREATE DATABASE [translator-message-db-test]' - name: Install PHP with extensions. uses: shivammathur/setup-php@v2 @@ -95,11 +97,21 @@ jobs: - name: Update composer. run: composer self-update - - name: Install db-mssql. - run: composer require yiisoft/db-mssql --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + - name: Remove unused dependencies of DB drivers + run: composer remove --dev yiisoft/db-sqlite yiisoft/db-mysql yiisoft/db-pgsql yiisoft/db-oracle + + - name: Install dependencies with composer + run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - name: Run tests with phpunit. run: vendor/bin/phpunit --testsuite=Mssql --coverage-clover=coverage.xml --colors=always + env: + ENVIRONMENT: ci + YII_MSSQL_DATABASE: translator-message-db-test + YII_MSSQL_HOST: 127.0.0.1 + YII_MSSQL_PORT: 1433 + YII_MSSQL_USER: SA + YII_MSSQL_PASSWORD: YourStrong!Passw0rd - name: Upload coverage to Codecov. if: matrix.php == '8.3' diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index 50b3af0..0c73d38 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -9,6 +9,8 @@ on: - 'psalm.xml' push: + branches: + - master paths-ignore: - 'docs/**' - 'README.md' @@ -38,16 +40,15 @@ jobs: - ubuntu-latest php: - - 8.1 - - 8.2 + - 8.5 services: postgres: image: postgres:15 env: - POSTGRES_USER: root - POSTGRES_PASSWORD: root - POSTGRES_DB: yiitest + POSTGRES_DB: translator-message-db-test + POSTGRES_USER: yii + POSTGRES_PASSWORD: q1w2e3r4 ports: - 5432:5432 options: --name=postgres --health-cmd="pg_isready" --health-interval=10s --health-timeout=5s --health-retries=3 @@ -68,11 +69,20 @@ jobs: - name: Update composer. run: composer self-update - - name: Install db-pgsql. - run: composer require yiisoft/db-pgsql --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + - name: Remove unused dependencies of DB drivers + run: composer remove --dev yiisoft/db-sqlite yiisoft/db-mysql yiisoft/db-mssql yiisoft/db-oracle + + - name: Install dependencies with composer + run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - name: Run infection. run: | vendor/bin/roave-infection-static-analysis-plugin --threads=2 --ignore-msi-with-no-mutations --test-framework-options="--testsuite=Pgsql" env: STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} + ENVIRONMENT: ci + YII_PGSQL_DATABASE: translator-message-db-test + YII_PGSQL_HOST: 127.0.0.1 + YII_PGSQL_PORT: 5432 + YII_PGSQL_USER: yii + YII_PGSQL_PASSWORD: q1w2e3r4 diff --git a/.github/workflows/mysql.yml b/.github/workflows/mysql.yml index b539f9f..471f587 100644 --- a/.github/workflows/mysql.yml +++ b/.github/workflows/mysql.yml @@ -10,6 +10,8 @@ on: - 'psalm.xml' push: + branches: + - master paths-ignore: - 'docs/**' - 'README.md' @@ -32,29 +34,30 @@ jobs: env: extensions: pdo, pdo_mysql - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest strategy: matrix: - os: - - ubuntu-latest - php: - 8.1 - 8.2 - 8.3 - + - 8.4 + - 8.5 mysql: - - mysql:5.7 - mysql:latest + include: + - php: 8.5 + mysql: mysql:5.7 services: mysql: image: ${{ matrix.mysql }} env: MYSQL_ALLOW_EMPTY_PASSWORD: true - MYSQL_PASSWORD: '' - MYSQL_DATABASE: yiitest + MYSQL_DATABASE: translator-message-db-test + MYSQL_USER: yii + MYSQL_PASSWORD: 'q1w2e3r4' ports: - 3306:3306 options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 @@ -75,11 +78,21 @@ jobs: - name: Update composer. run: composer self-update - - name: Install db-mysql. - run: composer require yiisoft/db-mysql --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + - name: Remove unused dependencies of DB drivers + run: composer remove --dev yiisoft/db-sqlite yiisoft/db-pgsql yiisoft/db-mssql yiisoft/db-oracle + + - name: Install dependencies with composer + run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - name: Run tests with phpunit. run: vendor/bin/phpunit --testsuite=Mysql --coverage-clover=coverage.xml --colors=always + env: + ENVIRONMENT: ci + YII_MYSQL_DATABASE: translator-message-db-test + YII_MYSQL_HOST: 127.0.0.1 + YII_MYSQL_PORT: 3306 + YII_MYSQL_USER: yii + YII_MYSQL_PASSWORD: q1w2e3r4 - name: Upload coverage to Codecov. if: matrix.php == '8.1' diff --git a/.github/workflows/oracle.yml b/.github/workflows/oracle.yml index 34fa7a9..92ee053 100644 --- a/.github/workflows/oracle.yml +++ b/.github/workflows/oracle.yml @@ -10,6 +10,8 @@ on: - 'psalm.xml' push: + branches: + - master paths-ignore: - 'docs/**' - 'README.md' @@ -32,21 +34,21 @@ jobs: env: extensions: pdo, pdo_oci, oci8 - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest strategy: matrix: - os: - - ubuntu-latest - php: - 8.1 - 8.2 - 8.3 - + - 8.4 + - 8.5 oracle: - - 18 - 21 + include: + - php: 8.5 + oracle: 18 services: oci: @@ -54,8 +56,10 @@ jobs: ports: - 1521:1521 env: - ORACLE_DATABASE : yiitest - ORACLE_PASSWORD : root + ORACLE_RANDOM_PASSWORD: yes + ORACLE_DATABASE: translator_message_db_test + APP_USER: yii + APP_USER_PASSWORD: q1w2e3r4 options: >- --name=oci --health-cmd healthcheck.sh @@ -79,11 +83,21 @@ jobs: - name: Update composer. run: composer self-update - - name: Install db-oracle. - run: composer require yiisoft/db-oracle --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + - name: Remove unused dependencies of DB drivers + run: composer remove --dev yiisoft/db-sqlite yiisoft/db-mysql yiisoft/db-pgsql yiisoft/db-mssql + + - name: Install dependencies with composer + run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - name: Run tests with phpunit. run: vendor/bin/phpunit --testsuite=Oracle --coverage-clover=coverage.xml --colors=always + env: + ENVIRONMENT: ci + YII_ORACLE_DATABASE: translator_message_db_test + YII_ORACLE_HOST: localhost + YII_ORACLE_PORT: 1521 + YII_ORACLE_USER: yii + YII_ORACLE_PASSWORD: q1w2e3r4 - name: Upload coverage to Codecov. if: matrix.php == '8.1' diff --git a/.github/workflows/pgsql.yml b/.github/workflows/pgsql.yml index f0e2841..ffea18b 100644 --- a/.github/workflows/pgsql.yml +++ b/.github/workflows/pgsql.yml @@ -10,6 +10,8 @@ on: - 'psalm.xml' push: + branches: + - master paths-ignore: - 'docs/**' - 'README.md' @@ -32,34 +34,45 @@ jobs: env: extensions: pdo, pdo_pgsql - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest strategy: matrix: - os: - - ubuntu-latest - php: - 8.1 - 8.2 - 8.3 - + - 8.4 + - 8.5 pgsql: - - 9 - - 10 - - 11 - - 12 - - 13 - - 14 - - 15 + - 18 + include: + - php: 8.5 + pgsql: 9 + - php: 8.5 + pgsql: 10 + - php: 8.5 + pgsql: 11 + - php: 8.5 + pgsql: 12 + - php: 8.5 + pgsql: 13 + - php: 8.5 + pgsql: 14 + - php: 8.5 + pgsql: 15 + - php: 8.5 + pgsql: 16 + - php: 8.5 + pgsql: 17 services: postgres: image: postgres:${{ matrix.pgsql }} env: - POSTGRES_USER: root - POSTGRES_PASSWORD: root - POSTGRES_DB: yiitest + POSTGRES_DB: translator-message-db-test + POSTGRES_USER: yii + POSTGRES_PASSWORD: q1w2e3r4 ports: - 5432:5432 options: --name=postgres --health-cmd="pg_isready" --health-interval=10s --health-timeout=5s --health-retries=3 @@ -80,11 +93,21 @@ jobs: - name: Update composer. run: composer self-update - - name: Install db-pgsql. - run: composer require yiisoft/db-pgsql --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + - name: Remove unused dependencies of DB drivers + run: composer remove --dev yiisoft/db-sqlite yiisoft/db-mysql yiisoft/db-mssql yiisoft/db-oracle + + - name: Install dependencies with composer + run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - name: Run tests with phpunit. run: vendor/bin/phpunit --testsuite=Pgsql --coverage-clover=coverage.xml --colors=always + env: + ENVIRONMENT: ci + YII_PGSQL_DATABASE: translator-message-db-test + YII_PGSQL_HOST: 127.0.0.1 + YII_PGSQL_PORT: 5432 + YII_PGSQL_USER: yii + YII_PGSQL_PASSWORD: q1w2e3r4 - name: Upload coverage to Codecov. if: matrix.php == '8.1' diff --git a/.github/workflows/sqlite.yml b/.github/workflows/sqlite.yml index f8213ac..6aa85d5 100644 --- a/.github/workflows/sqlite.yml +++ b/.github/workflows/sqlite.yml @@ -10,6 +10,8 @@ on: - 'psalm.xml' push: + branches: + - master paths-ignore: - 'docs/**' - 'README.md' @@ -44,6 +46,8 @@ jobs: - 8.1 - 8.2 - 8.3 + - 8.4 + - 8.5 steps: - name: Checkout. @@ -61,8 +65,11 @@ jobs: - name: Update composer. run: composer self-update - - name: Install db-sqlite. - run: composer require yiisoft/db-sqlite --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + - name: Remove unused dependencies of DB drivers + run: composer remove --dev yiisoft/db-mysql yiisoft/db-pgsql yiisoft/db-mssql yiisoft/db-oracle + + - name: Install dependencies with composer. + run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - name: Run tests with phpunit. run: vendor/bin/phpunit --testsuite=Sqlite --coverage-clover=coverage.xml --colors=always diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index fc92879..6db7365 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -10,6 +10,8 @@ on: - 'phpunit.xml.dist' push: + branches: + - master paths-ignore: - 'docs/**' - 'README.md' @@ -32,4 +34,4 @@ jobs: os: >- ['ubuntu-latest'] php: >- - ['8.1', '8.2', '8.3'] + ['8.1', '8.2', '8.3', '8.4', '8.5'] diff --git a/CHANGELOG.md b/CHANGELOG.md index 8260b8c..78effd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## 1.0.1 under development - Chg #81: Raise the minimum PHP version to 8.1 (@vjik) +- Chg #82: Change PHP constraint in composer.json to `8.1 - 8.5` (@vjik) +- Chg #82: Bump required `yiisoft/db` version to `^2.0` (@vjik) - Enh #69: Add support of `yiisoft/cache` version `^3.0` (@thenotsoft) - Enh #66: Add support of `yiisoft/translator` version `^3.0` (@thenotsoft) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dcc0cf6 --- /dev/null +++ b/Makefile @@ -0,0 +1,74 @@ +help: ## Show the list of available commands with description. + @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) +.DEFAULT_GOAL := help + +build: ## Build services + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml --profile all build +up: ## Start services + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml --profile all up -d +ps: ## List running services + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml ps +stop: ## Stop running services + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml --profile all stop +down: ## Stop running services and remove containers, networks and volumes + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml --profile all down \ + --remove-orphans \ + --volumes +clear: ## Remove all containers, networks, volumes and images + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml --profile all down \ + --remove-orphans \ + --volumes \ + --rmi all + +run: ## Run arbitrary command + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml --profile php run \ + --rm \ + --entrypoint $(CMD) \ + php + +test-all: test-sqlite \ + test-mysql \ + test-pgsql \ + test-mssql \ + test-oracle +test-sqlite: ## Run SQLite tests + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml --profile php up -d + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml exec php \ + vendor/bin/phpunit --testsuite Sqlite $(RUN_ARGS) +test-mysql: ## Run MySQL tests + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml --profile mysql up -d + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml exec php-mysql \ + vendor/bin/phpunit --testsuite Mysql $(RUN_ARGS) +test-pgsql: ## Run PostgreSQL tests + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml --profile pgsql up -d + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml exec php-pgsql \ + vendor/bin/phpunit --testsuite Pgsql $(RUN_ARGS) +test-mssql: ## Run MSSQL tests + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml --profile mssql up -d + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml exec php-mssql \ + vendor/bin/phpunit --testsuite Mssql $(RUN_ARGS) +test-oracle: ## Run Oracle tests + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml --profile oracle up -d + docker compose -f docker/docker-compose.yml -f docker/docker-compose.override.yml exec php-oracle \ + bash -c -l 'vendor/bin/phpunit --testsuite Oracle $(RUN_ARGS)' + +psalm: CMD="vendor/bin/psalm --no-cache" ## Run static analysis using Psalm +psalm: run + +mutation: CMD="\ +vendor/bin/roave-infection-static-analysis-plugin \ +--threads=$(shell nproc) \ +--min-msi=0 \ +--min-covered-msi=100 \ +--ignore-msi-with-no-mutations \ +--only-covered" ## Run mutation tests using Infection +mutation: run + +composer-require-checker: CMD="vendor/bin/composer-require-checker" ## Check dependencies using Composer Require Checker +composer-require-checker: run + +rector: CMD="vendor/bin/rector" ## Check code style using Rector +rector: run + +shell: CMD="bash" ## Open interactive shell +shell: run diff --git a/README.md b/README.md index 7b15f65..1796d78 100644 --- a/README.md +++ b/README.md @@ -18,17 +18,17 @@ with [`yiisoft/translator`](https://github.com/yiisoft/translator) package. ## Supported databases -| Packages | PHP | Versions | CI-Actions | -|----------|---------------|----------|------------| -| [[db-mssql]](https://github.com/yiisoft/db-mssql) | **8.1 - 8.2** | **2017 - 2022** | [![mssql](https://github.com/yiisoft/translator-message-db/actions/workflows/mssql.yml/badge.svg)](https://github.com/yiisoft/translator-message-db/actions/workflows/mssql.yml) | | -| [[db-mysql/mariadb]](https://github.com/yiisoft/db-mysql) | **8.1 - 8.2** | **5.7-8.0**/**10.4-10.10** | [![mysql](https://github.com/yiisoft/translator-message-db/actions/workflows/mysql.yml/badge.svg)](https://github.com/yiisoft/translator-message-db/actions/workflows/mysql.yml) | -| [[db-oracle]](https://github.com/yiisoft/db-oracle) | **8.1 - 8.2** | **11C - 21C** | [![oracle](https://github.com/yiisoft/translator-message-db/actions/workflows/oracle.yml/badge.svg)](https://github.com/yiisoft/translator-message-db/actions/workflows/oracle.yml) | -| [[db-pgsql]](https://github.com/yiisoft/db-pgsql) | **8.1 - 8.2** | **9.0 - 15.0** | [![pgsql](https://github.com/yiisoft/translator-message-db/actions/workflows/pgsql.yml/badge.svg)](https://github.com/yiisoft/translator-message-db/actions/workflows/pgsql.yml) | -| [[db-sqlite]](https://github.com/yiisoft/db-sqlite) | **8.1 - 8.2** | **3:latest** | [![sqlite](https://github.com/yiisoft/translator-message-db/actions/workflows/sqlite.yml/badge.svg)](https://github.com/yiisoft/translator-message-db/actions/workflows/sqlite.yml) | +| Packages | CI-Actions | +|-----------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [[db-mssql]](https://github.com/yiisoft/db-mssql) | [![mssql](https://github.com/yiisoft/translator-message-db/actions/workflows/mssql.yml/badge.svg)](https://github.com/yiisoft/translator-message-db/actions/workflows/mssql.yml) | | +| [[db-mysql/mariadb]](https://github.com/yiisoft/db-mysql) | [![mysql](https://github.com/yiisoft/translator-message-db/actions/workflows/mysql.yml/badge.svg)](https://github.com/yiisoft/translator-message-db/actions/workflows/mysql.yml) | +| [[db-oracle]](https://github.com/yiisoft/db-oracle) | [![oracle](https://github.com/yiisoft/translator-message-db/actions/workflows/oracle.yml/badge.svg)](https://github.com/yiisoft/translator-message-db/actions/workflows/oracle.yml) | +| [[db-pgsql]](https://github.com/yiisoft/db-pgsql) | [![pgsql](https://github.com/yiisoft/translator-message-db/actions/workflows/pgsql.yml/badge.svg)](https://github.com/yiisoft/translator-message-db/actions/workflows/pgsql.yml) | +| [[db-sqlite]](https://github.com/yiisoft/db-sqlite) | [![sqlite](https://github.com/yiisoft/translator-message-db/actions/workflows/sqlite.yml/badge.svg)](https://github.com/yiisoft/translator-message-db/actions/workflows/sqlite.yml) | ## Requirements -- PHP 8.1 or higher. +- PHP 8.1 - 8.5. - `json` PHP extension. ## Installation diff --git a/composer.json b/composer.json index 5b95e6b..4f1d5c6 100644 --- a/composer.json +++ b/composer.json @@ -29,11 +29,11 @@ } ], "require": { - "php": "^8.1", + "php": "8.1 - 8.5", "ext-json": "*", "yiisoft/cache": "^2.0|^3.0", "yiisoft/arrays": "^2.0|^3.0", - "yiisoft/db": "^1.0", + "yiisoft/db": "^2.0", "yiisoft/translator": "^2.2|^3.0" }, "require-dev": { @@ -41,7 +41,13 @@ "phpunit/phpunit": "^10.5.60", "rector/rector": "^2.3.1", "roave/infection-static-analysis-plugin": "^1.35", - "vimeo/psalm": "^5.26.1 || ^6" + "vimeo/psalm": "^5.26.1 || ^6.14.3", + "vlucas/phpdotenv": "^5.6.2", + "yiisoft/db-mssql": "^2.0", + "yiisoft/db-mysql": "^2.0", + "yiisoft/db-oracle": "^2.0", + "yiisoft/db-pgsql": "^2.0", + "yiisoft/db-sqlite": "^2.0" }, "autoload": { "psr-4": { diff --git a/docker/.gitignore b/docker/.gitignore new file mode 100644 index 0000000..f2bec73 --- /dev/null +++ b/docker/.gitignore @@ -0,0 +1 @@ +/docker-compose.override.yml diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..c49f0c8 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,97 @@ +FROM composer/composer:latest-bin AS composer + +FROM php:8.3-cli-bookworm + +# System packages + +RUN apt-get update && apt-get install -y \ + unzip \ + # PostgreSQL + libpq-dev \ + # MSSQL + apt-transport-https \ + gnupg2 \ + libpng-dev \ + # Oracle + libaio1 && \ + rm -rf /var/lib/apt/lists/* + +# MSSQL dependencies + +ENV ACCEPT_EULA=Y + +# Install prerequisites for the sqlsrv and pdo_sqlsrv PHP extensions. +# Some packages are pinned with lower priority to prevent build issues due to package conflicts. +# Link: https://github.com/microsoft/linux-package-repositories/issues/39 +RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - \ + && curl https://packages.microsoft.com/config/debian/11/prod.list > /etc/apt/sources.list.d/mssql-release.list \ + && echo "Package: unixodbc\nPin: origin \"packages.microsoft.com\"\nPin-Priority: 100\n" >> /etc/apt/preferences.d/microsoft \ + && echo "Package: unixodbc-dev\nPin: origin \"packages.microsoft.com\"\nPin-Priority: 100\n" >> /etc/apt/preferences.d/microsoft \ + && echo "Package: libodbc1:amd64\nPin: origin \"packages.microsoft.com\"\nPin-Priority: 100\n" >> /etc/apt/preferences.d/microsoft \ + && echo "Package: odbcinst\nPin: origin \"packages.microsoft.com\"\nPin-Priority: 100\n" >> /etc/apt/preferences.d/microsoft \ + && echo "Package: odbcinst1debian2:amd64\nPin: origin \"packages.microsoft.com\"\nPin-Priority: 100\n" >> /etc/apt/preferences.d/microsoft \ + && apt-get update \ + && apt-get install -y msodbcsql18 mssql-tools18 unixodbc-dev \ + && rm -rf /var/lib/apt/lists/* + +# Oracle dependencies +ARG TARGETARCH +RUN if [ "$TARGETARCH" = "arm64" ] ; then \ + cd /tmp && curl -L https://download.oracle.com/otn_software/linux/instantclient/2370000/instantclient-basic-linux.arm64-23.7.0.25.01.zip -O \ + && curl -L https://download.oracle.com/otn_software/linux/instantclient/2370000/instantclient-sdk-linux.arm64-23.7.0.25.01.zip -O \ + && curl -L https://download.oracle.com/otn_software/linux/instantclient/2370000/instantclient-sqlplus-linux.arm64-23.7.0.25.01.zip -O \ + && unzip -o /tmp/instantclient-basic-linux.arm64-23.7.0.25.01.zip -d /usr/local/ \ + && unzip -o /tmp/instantclient-sdk-linux.arm64-23.7.0.25.01.zip -d /usr/local/ \ + && unzip -o /tmp/instantclient-sqlplus-linux.arm64-23.7.0.25.01.zip -d /usr/local/ \ + && ln -s /usr/local/instantclient_23_7 /usr/local/instantclient; \ + elif [ "$TARGETARCH" = "amd64" ]; then \ + cd /tmp && curl -L https://download.oracle.com/otn_software/linux/instantclient/2350000/instantclient-basic-linux.x64-23.5.0.24.07.zip -O \ + && curl -L https://download.oracle.com/otn_software/linux/instantclient/2350000/instantclient-sdk-linux.x64-23.5.0.24.07.zip -O \ + && curl -L https://download.oracle.com/otn_software/linux/instantclient/2350000/instantclient-sqlplus-linux.x64-23.5.0.24.07.zip -O \ + && unzip /tmp/instantclient-basic-linux.x64-23.5.0.24.07.zip -d /usr/local/ \ + && unzip -o /tmp/instantclient-sdk-linux.x64-23.5.0.24.07.zip -d /usr/local/ \ + && unzip -o /tmp/instantclient-sqlplus-linux.x64-23.5.0.24.07.zip -d /usr/local/ \ + && ln -s /usr/local/instantclient_23_5 /usr/local/instantclient; \ + fi +RUN ln -s /usr/local/instantclient/lib* /usr/lib +RUN ln -s /usr/local/instantclient/sqlplus /usr/bin/sqlplus + +RUN echo 'export LD_LIBRARY_PATH="/usr/local/instantclient"' >> /root/.bashrc +RUN echo 'umask 002' >> /root/.bashrc + +# PHP extensions + +RUN docker-php-ext-install \ + pdo_mysql \ + pdo_pgsql \ + # For Psalm, to make use of JIT for a 20%+ performance boost. + opcache + +RUN pecl install sqlsrv +RUN printf "; priority=20\nextension=sqlsrv.so\n" > /usr/local/etc/php/conf.d/php-sqlsrv.ini + +RUN pecl install pdo_sqlsrv +RUN printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /usr/local/etc/php/conf.d/php-pdo-sqlsrv.ini + +RUN echo 'instantclient,/usr/local/instantclient' | pecl install oci8 +RUN echo "extension=oci8.so" > /usr/local/etc/php/conf.d/php-oci8.ini + +RUN echo 'instantclient,/usr/local/instantclient' | pecl install pdo_oci +RUN echo "extension=pdo_oci.so" > /usr/local/etc/php/conf.d/php-pdo-oci.ini + +# For code coverage (mutation testing) +RUN pecl install pcov && docker-php-ext-enable pcov + +# Composer + +COPY --from=composer /composer /usr/bin/composer + +# Code + +COPY . /code +RUN rm -f /code/composer.lock +WORKDIR /code + +# PHP packages + +RUN COMPOSER_ALLOW_SUPERUSER=1 composer install --no-cache diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..6b321f0 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,140 @@ +name: yiisoft-translator-message-db + +x-php-base: &php-base + build: + context: ./.. + dockerfile: ./docker/Dockerfile + image: yiisoft-translator-message-php-test + volumes: + - ./../src:/code/src + - ./../tests:/code/tests + - ./../composer.json:/code/composer.json + - ./../phpunit.xml.dist:/code/phpunit.xml.dist + command: tail -F anything + +services: + php: + <<: *php-base + profiles: + - php + - all + php-mysql: + <<: *php-base + profiles: + - mysql + - all + depends_on: + mysql: + condition: service_healthy + mysql: + image: mysql:9 + ports: + - "3306:3306" + volumes: + - type: tmpfs + target: /var/lib/mysql + environment: + MYSQL_ALLOW_EMPTY_PASSWORD: true + MYSQL_DATABASE: translator-message-db-test + MYSQL_USER: yii + MYSQL_PASSWORD: 'q1w2e3r4' + healthcheck: + test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost", "-uyii" ] + interval: 5s + timeout: 5s + retries: 20 + profiles: + - mysql + - all + php-pgsql: + <<: *php-base + profiles: + - pgsql + - all + depends_on: + postgres: + condition: service_healthy + postgres: + image: postgres:17 + ports: + - "5432:5432" + volumes: + - type: tmpfs + target: /var/lib/postgresql/data + environment: + POSTGRES_DB: translator-message-db-test + POSTGRES_USER: yii + POSTGRES_PASSWORD: q1w2e3r4 + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U postgres" ] + interval: 5s + timeout: 5s + retries: 5 + profiles: + - pgsql + - all + php-mssql: + <<: *php-base + profiles: + - mssql + - all + depends_on: + mssql: + condition: service_healthy + mssql: + image: mcr.microsoft.com/mssql/server:2022-latest + ports: + - "1433:1433" + user: root + volumes: + - mssql-data:/var/opt/mssql/data + - mssql-log:/var/opt/mssql/log + - mssql-secrets:/var/opt/mssql/secrets + - ./mssql/init.sh:/tmp/init.sh + environment: + SA_PASSWORD: YourStrong!Passw0rd + ACCEPT_EULA: Y + healthcheck: + test: /opt/mssql-tools18/bin/sqlcmd -S localhost -U yii -P "q1w2e3r4!" -Q "SELECT 1" -b -C -o /dev/null + interval: 10s + timeout: 3s + retries: 100 + start_period: 10s + command: /tmp/init.sh + profiles: + - mssql + - all + php-oracle: + <<: *php-base + profiles: + - oracle + - all + depends_on: + oracle: + condition: service_healthy + oracle: + image: gvenzl/oracle-free:23 + ports: + - "1521:1521" + volumes: + - oracle-data:/opt/oracle/oradata + environment: + ORACLE_RANDOM_PASSWORD: yes + ORACLE_DATABASE: translator_message_db_test + APP_USER: yii + APP_USER_PASSWORD: q1w2e3r4 + healthcheck: + test: ["CMD", "healthcheck.sh"] + interval: 10s + timeout: 5s + retries: 100 + start_period: 5s + start_interval: 5s + profiles: + - oracle + - all +volumes: + mssql-data: + mssql-log: + mssql-secrets: + oracle-data: diff --git a/docker/mssql/init.sh b/docker/mssql/init.sh new file mode 100755 index 0000000..578f8a0 --- /dev/null +++ b/docker/mssql/init.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -e + +/opt/mssql/bin/sqlservr & +SQLSERVER_PID=$! + +until /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'YourStrong!Passw0rd' -C -Q "SELECT 1 FROM tempdb.sys.tables" -h -1 >/dev/null 2>&1 +do + sleep 1 +done + +/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'YourStrong!Passw0rd' -C -Q " +IF NOT EXISTS (SELECT * FROM sys.sql_logins WHERE name = N'yii') + CREATE LOGIN yii WITH PASSWORD = 'q1w2e3r4!'; +" + +/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'YourStrong!Passw0rd' -C -Q " +IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = N'translator-message-db-test') + CREATE DATABASE [translator-message-db-test]; +" + +/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'YourStrong!Passw0rd' -C -d translator-message-db-test -Q " +IF NOT EXISTS (SELECT * FROM sys.database_principals WHERE name = N'yii') + CREATE USER yii FOR LOGIN yii; +ALTER ROLE db_owner ADD MEMBER yii; +" + +wait $SQLSERVER_PID diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 8c487d1..d823251 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,7 +1,7 @@ db->getDriverName(); $schema = $this->db->getSchema(); - $tableRawNameSourceMessage = $schema->getRawTableName($tableSourceMessage); - $tableRawNameMessage = $schema->getRawTableName($tableMessage); + $quoter = $this->db->getQuoter(); + $tableRawNameSourceMessage = $quoter->getRawTableName($tableSourceMessage); + $tableRawNameMessage = $quoter->getRawTableName($tableMessage); if ($this->hasTable($tableSourceMessage) && $this->hasTable($tableMessage)) { return; @@ -82,8 +82,9 @@ public function ensureNoTables( ): void { $driverName = $this->db->getDriverName(); $schema = $this->db->getSchema(); - $tableRawNameSourceMessage = $schema->getRawTableName($tableSourceMessage); - $tableRawNameMessage = $schema->getRawTableName($tableMessage); + $quoter = $this->db->getQuoter(); + $tableRawNameSourceMessage = $quoter->getRawTableName($tableSourceMessage); + $tableRawNameMessage = $quoter->getRawTableName($tableMessage); if ($this->hasTable($tableMessage)) { if ($driverName !== 'sqlite' && $schema->getTableForeignKeys($tableMessage, true) !== []) { @@ -193,7 +194,6 @@ private function addSequenceAndTrigger(string $tableRawNameSourceMessage, string /** * Create index for tables '{{%yii_source_message}}' and '{{%yii_message}}'. * - * @throws InvalidArgumentException * @throws Exception * @throws Throwable */ @@ -217,7 +217,6 @@ private function createIndex( * Create schema for tables in the database. * * @throws Exception - * @throws InvalidArgumentException * @throws InvalidConfigException * @throws NotSupportedException * @throws Throwable @@ -230,6 +229,7 @@ private function createSchema( string $tableMessage, string $tableRawNameMessage ): void { + $columnBuilder = $this->db->getColumnBuilderClass(); $updateAction = 'RESTRICT'; if ($driverName === 'sqlsrv') { @@ -248,10 +248,10 @@ private function createSchema( ->createTable( $tableSourceMessage, [ - 'id' => $schema->createColumn(SchemaInterface::TYPE_PK), - 'category' => $schema->createColumn(SchemaInterface::TYPE_STRING), - 'message_id' => $schema->createColumn(SchemaInterface::TYPE_TEXT), - 'comment' => $schema->createColumn(SchemaInterface::TYPE_TEXT), + 'id' => $columnBuilder::primaryKey(), + 'category' => $columnBuilder::string(), + 'message_id' => $columnBuilder::text(), + 'comment' => $columnBuilder::text(), ], ) ->execute(); @@ -262,9 +262,9 @@ private function createSchema( ->createTable( $tableMessage, [ - 'id' => $schema->createColumn(SchemaInterface::TYPE_INTEGER)->notNull(), - 'locale' => $schema->createColumn(SchemaInterface::TYPE_STRING, 16)->notNull(), - 'translation' => $schema->createColumn(SchemaInterface::TYPE_TEXT), + 'id' => $columnBuilder::integer()->notNull(), + 'locale' => $columnBuilder::string(16)->notNull(), + 'translation' => $columnBuilder::text(), ], ) ->execute(); @@ -300,7 +300,6 @@ private function createSchema( * Create schema for tables in SQLite database. * * @throws Exception - * @throws InvalidArgumentException * @throws InvalidConfigException * @throws NotSupportedException * @throws Throwable @@ -312,16 +311,18 @@ private function createSchemaSqlite( string $tableMessage, string $tableRawNameMessage ): void { + $columnBuilder = $this->db->getColumnBuilderClass(); + // create table `yii_source_message`. $this->db ->createCommand() ->createTable( $tableSourceMessage, [ - 'id' => $schema->createColumn(SchemaInterface::TYPE_INTEGER)->notNull(), - 'category' => $schema->createColumn(SchemaInterface::TYPE_STRING), - 'message_id' => $schema->createColumn(SchemaInterface::TYPE_TEXT), - 'comment' => $schema->createColumn(SchemaInterface::TYPE_TEXT), + 'id' => $columnBuilder::integer()->notNull(), + 'category' => $columnBuilder::string(), + 'message_id' => $columnBuilder::text(), + 'comment' => $columnBuilder::text(), "CONSTRAINT [[PK_{$tableRawNameSourceMessage}]] PRIMARY KEY ([[id]])", ], ) @@ -333,9 +334,9 @@ private function createSchemaSqlite( ->createTable( $tableMessage, [ - 'id' => $schema->createColumn(SchemaInterface::TYPE_INTEGER)->notNull(), - 'locale' => $schema->createColumn(SchemaInterface::TYPE_STRING, 16)->notNull(), - 'translation' => $schema->createColumn(SchemaInterface::TYPE_TEXT), + 'id' => $columnBuilder::integer()->notNull(), + 'locale' => $columnBuilder::string(16)->notNull(), + 'translation' => $columnBuilder::text(), 'PRIMARY KEY (`id`, `locale`)', "CONSTRAINT `FK_{$tableRawNameMessage}_{$tableRawNameSourceMessage}` FOREIGN KEY (`id`) REFERENCES `$tableRawNameSourceMessage` (`id`) ON DELETE CASCADE", ], diff --git a/src/MessageSource.php b/src/MessageSource.php index a0acf5f..0b5a696 100644 --- a/src/MessageSource.php +++ b/src/MessageSource.php @@ -4,17 +4,17 @@ namespace Yiisoft\Translator\Message\Db; +use InvalidArgumentException; use JsonException; -use RuntimeException; use Throwable; use Yiisoft\Arrays\ArrayHelper; use Yiisoft\Cache\CacheInterface; use Yiisoft\Db\Connection\ConnectionInterface; use Yiisoft\Db\Exception\Exception; -use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Exception\InvalidCallException; use Yiisoft\Db\Exception\InvalidConfigException; -use Yiisoft\Db\Expression\Expression; +use Yiisoft\Db\Expression\Value\ColumnName; +use Yiisoft\Db\Expression\Value\Value; use Yiisoft\Db\Query\Query; use Yiisoft\Translator\MessageReaderInterface; use Yiisoft\Translator\MessageWriterInterface; @@ -115,10 +115,9 @@ public function write(string $category, string $locale, array $messages): void $comment = $messageData['comment']; } - /** @psalm-var array|false $result */ $result = $this->db ->createCommand() - ->insertWithReturningPks( + ->insertReturningPks( $this->sourceMessageTable, [ 'category' => $category, @@ -127,10 +126,6 @@ public function write(string $category, string $locale, array $messages): void ], ); - if ($result === false) { - throw new RuntimeException("Failed to write source message with \"$messageId\" ID."); - } - $sourceMessages[$messageId] = $result['id']; } @@ -144,9 +139,9 @@ public function write(string $category, string $locale, array $messages): void } if ($needUpdate || !isset($translatedMessages[$messageId])) { - $result = $this->db + $this->db ->createCommand() - ->insertWithReturningPks( + ->insertReturningPks( $this->messageTable, [ 'id' => $sourceMessages[$messageId], @@ -154,10 +149,6 @@ public function write(string $category, string $locale, array $messages): void 'translation' => $messageData['message'], ] ); - - if ($result === false) { - throw new RuntimeException("Failed to write message with \"$messageId\" ID."); - } } } } @@ -199,8 +190,8 @@ private function readFromDb(string $category, string $locale): array ->innerJoin( ['td' => $this->messageTable], [ - 'td.id' => new Expression('[[ts.id]]'), - 'ts.category' => $category, + 'td.id' => new ColumnName('ts.id'), + 'ts.category' => new Value($category), ] ) ->where(['locale' => $locale]); diff --git a/tests/.env b/tests/.env new file mode 100644 index 0000000..0a85342 --- /dev/null +++ b/tests/.env @@ -0,0 +1,23 @@ +YII_MYSQL_DATABASE=translator-message-db-test +YII_MYSQL_HOST=mysql +YII_MYSQL_PORT=3306 +YII_MYSQL_USER=yii +YII_MYSQL_PASSWORD=q1w2e3r4 + +YII_PGSQL_DATABASE=translator-message-db-test +YII_PGSQL_HOST=postgres +YII_PGSQL_PORT=5432 +YII_PGSQL_USER=yii +YII_PGSQL_PASSWORD=q1w2e3r4 + +YII_MSSQL_DATABASE=translator-message-db-test +YII_MSSQL_HOST=mssql +YII_MSSQL_PORT=1433 +YII_MSSQL_USER=yii +YII_MSSQL_PASSWORD=q1w2e3r4! + +YII_ORACLE_DATABASE=translator_message_db_test +YII_ORACLE_HOST=oracle +YII_ORACLE_PORT=1521 +YII_ORACLE_USER=yii +YII_ORACLE_PASSWORD=q1w2e3r4 diff --git a/tests/Common/AbstractDbSchemaManagerTest.php b/tests/Common/AbstractDbSchemaManagerTest.php index 52b35ad..199e85d 100644 --- a/tests/Common/AbstractDbSchemaManagerTest.php +++ b/tests/Common/AbstractDbSchemaManagerTest.php @@ -7,16 +7,17 @@ use PHPUnit\Framework\TestCase; use Throwable; use Yiisoft\Db\Connection\ConnectionInterface; +use Yiisoft\Db\Constant\ColumnType; +use Yiisoft\Db\Constraint\ForeignKey; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidConfigException; -use Yiisoft\Db\Schema\SchemaInterface; use Yiisoft\Translator\Message\Db\DbSchemaManager; abstract class AbstractDbSchemaManagerTest extends TestCase { - protected string $commentType = SchemaInterface::TYPE_TEXT; - protected string $messageIdType = SchemaInterface::TYPE_TEXT; - protected string $translationType = SchemaInterface::TYPE_TEXT; + protected string $commentType = ColumnType::TEXT; + protected string $messageIdType = ColumnType::TEXT; + protected string $translationType = ColumnType::TEXT; protected ConnectionInterface $db; private DbSchemaManager $dbSchemaManager; @@ -56,10 +57,6 @@ public function testEnsureTableAndEnsureNoTable(string $tableSourceMessage, stri /** * @dataProvider tableNameProvider - * - * @throws Exception - * @throws InvalidConfigException - * @throws Throwable */ public function testEnsureTableExist(string $tableSourceMessage, string $tableMessage): void { @@ -81,27 +78,23 @@ public function testEnsureTableExist(string $tableSourceMessage, string $tableMe /** * @dataProvider tableNameProvider - * - * @throws Exception - * @throws InvalidConfigException - * @throws Throwable */ public function testVerifyTableStructure(string $tableSourceMessage, string $tableMessage): void { $this->dbSchemaManager->ensureTables($tableSourceMessage, $tableMessage); $driverName = $this->db->getDriverName(); - $schema = $this->db->getSchema(); - $tableRawNameSourceMessage = $schema->getRawTableName($tableSourceMessage); - $tableRawNameMessage = $schema->getRawTableName($tableMessage); + $quoter = $this->db->getQuoter(); + $tableRawNameSourceMessage = $quoter->getRawTableName($tableSourceMessage); + $tableRawNameMessage = $quoter->getRawTableName($tableMessage); $tableSchema = $this->db->getTableSchema($tableSourceMessage); $this->assertSame($tableRawNameSourceMessage, $tableSchema?->getName()); $this->assertSame(['id'], $tableSchema?->getPrimaryKey()); $this->assertSame(['id', 'category', 'message_id', 'comment'], $tableSchema?->getColumnNames()); - $this->assertSame(SchemaInterface::TYPE_INTEGER, $tableSchema?->getColumn('id')->getType()); - $this->assertSame(SchemaInterface::TYPE_STRING, $tableSchema?->getColumn('category')->getType()); + $this->assertSame(ColumnType::INTEGER, $tableSchema?->getColumn('id')->getType()); + $this->assertSame(ColumnType::STRING, $tableSchema?->getColumn('category')->getType()); $this->assertSame($this->messageIdType, $tableSchema?->getColumn('message_id')->getType()); $this->assertSame($this->commentType, $tableSchema?->getColumn('comment')->getType()); @@ -110,28 +103,43 @@ public function testVerifyTableStructure(string $tableSourceMessage, string $tab $this->assertSame($tableRawNameMessage, $tableSchema?->getName()); $this->assertSame(['id', 'locale'], $tableSchema?->getPrimaryKey()); $this->assertSame(['id', 'locale', 'translation'], $tableSchema?->getColumnNames()); - $this->assertSame(SchemaInterface::TYPE_INTEGER, $tableSchema?->getColumn('id')->getType()); - $this->assertSame(SchemaInterface::TYPE_STRING, $tableSchema?->getColumn('locale')->getType()); + $this->assertSame(ColumnType::INTEGER, $tableSchema?->getColumn('id')->getType()); + $this->assertSame(ColumnType::STRING, $tableSchema?->getColumn('locale')->getType()); $this->assertSame(16, $tableSchema?->getColumn('locale')->getSize()); $this->assertSame($this->translationType, $tableSchema?->getColumn('translation')->getType()); + $foreignKey = new ForeignKey( + match ($driverName) { + 'sqlsrv', 'oci', 'mysql', 'pgsql' => "FK_{$tableRawNameSourceMessage}_{$tableRawNameMessage}", + default => '0', + }, + ['id'], + match ($driverName) { + 'sqlsrv' => 'dbo', + 'pgsql' => 'public', + 'oci' => 'YII', + default => '', + }, + $tableRawNameSourceMessage, + ['id'], + 'CASCADE', + match ($driverName) { + 'mysql', 'pgsql' => 'RESTRICT', + 'oci' => null, + default => 'NO ACTION', + }, + ); $foreignKeysExpected = [ - "FK_{$tableRawNameSourceMessage}_{$tableRawNameMessage}" => [ - 0 => $tableRawNameSourceMessage, - 'id' => 'id', - ], + "FK_{$tableRawNameSourceMessage}_{$tableRawNameMessage}" => $foreignKey, ]; - if ($driverName === 'oci' || $driverName === 'sqlite') { + if ($driverName === 'sqlite') { $foreignKeysExpected = [ - 0 => [ - 0 => $tableRawNameSourceMessage, - 'id' => 'id', - ], + 0 => $foreignKey, ]; } - $this->assertSame($foreignKeysExpected, $tableSchema?->getForeignKeys()); + $this->assertEquals($foreignKeysExpected, $tableSchema?->getForeignKeys()); $this->dbSchemaManager->ensureNoTables($tableSourceMessage, $tableMessage); diff --git a/tests/Common/AbstractMessageSourceTest.php b/tests/Common/AbstractMessageSourceTest.php index 84d5936..eb11627 100644 --- a/tests/Common/AbstractMessageSourceTest.php +++ b/tests/Common/AbstractMessageSourceTest.php @@ -4,20 +4,12 @@ namespace Yiisoft\Translator\Message\Db\Tests\Common; -use JsonException; +use InvalidArgumentException; use PHPUnit\Framework\TestCase; -use RuntimeException; -use Throwable; use Yiisoft\Cache\ArrayCache; use Yiisoft\Cache\Cache; use Yiisoft\Cache\CacheInterface; -use Yiisoft\Db\Command\CommandInterface; use Yiisoft\Db\Connection\ConnectionInterface; -use Yiisoft\Db\Exception\Exception; -use Yiisoft\Db\Exception\InvalidArgumentException; -use Yiisoft\Db\Exception\InvalidCallException; -use Yiisoft\Db\Exception\InvalidConfigException; -use Yiisoft\Db\QueryBuilder\QueryBuilderInterface; use Yiisoft\Translator\Message\Db\DbSchemaManager; use Yiisoft\Translator\Message\Db\MessageSource; @@ -41,11 +33,6 @@ protected function setup(): void parent::setup(); } - /** - * @throws Exception - * @throws InvalidConfigException - * @throws Throwable - */ protected function tearDown(): void { // drop table @@ -62,13 +49,6 @@ protected function tearDown(): void * @dataProvider generateTranslationsData * * @psalm-param array> $data - * - * @throws Exception - * @throws JsonException - * @throws InvalidArgumentException - * @throws InvalidCallException - * @throws InvalidConfigException - * @throws Throwable */ public function testWrite(string $category, string $locale, array $data): void { @@ -84,11 +64,6 @@ public function testWrite(string $category, string $locale, array $data): void * @dataProvider generateFailTranslationsData * * @psalm-param array> $data - * - * @throws Exception - * @throws InvalidCallException - * @throws InvalidConfigException - * @throws Throwable */ public function testWriteWithFailData(string $category, string $locale, array $data): void { @@ -98,14 +73,6 @@ public function testWriteWithFailData(string $category, string $locale, array $d $messageSource->write($category, $locale, $data); } - /** - * @throws Exception - * @throws JsonException - * @throws InvalidArgumentException - * @throws InvalidCallException - * @throws InvalidConfigException - * @throws Throwable - */ public function testMultiWrite(): void { $allData = self::generateTranslationsData(); @@ -129,14 +96,6 @@ public function testMultiWrite(): void } } - /** - * @throws Exception - * @throws JsonException - * @throws InvalidArgumentException - * @throws InvalidCallException - * @throws InvalidConfigException - * @throws Throwable - */ public function testUpdate(): void { $updatedData = [ @@ -186,14 +145,6 @@ public function testUpdate(): void } } - /** - * @throws Exception - * @throws JsonException - * @throws InvalidArgumentException - * @throws InvalidCallException - * @throws InvalidConfigException - * @throws Throwable - */ public function testMultiWriteWithCache(): void { $allData = self::generateTranslationsData(); @@ -220,13 +171,6 @@ public function testMultiWriteWithCache(): void * @dataProvider generateTranslationsData * * @psalm-param array> $data - * - * @throws Exception - * @throws JsonException - * @throws InvalidArgumentException - * @throws InvalidCallException - * @throws InvalidConfigException - * @throws Throwable */ public function testReadMessages(string $category, string $locale, array $data): void { @@ -238,40 +182,6 @@ public function testReadMessages(string $category, string $locale, array $data): $this->assertEquals($messages, $data); } - public function testReadMessageError(): void - { - $qbMock = $this->createMock(QueryBuilderInterface::class); - $qbMock->expects(self::atLeastOnce()) - ->method('build') - ->willReturn(['', []]); - - $commandMock = $this->createMock(CommandInterface::class); - $commandMock->expects(self::once()) - ->method('insertWithReturningPks') - ->willReturn(false); - $commandMock->expects(self::atLeastOnce()) - ->method('queryAll') - ->willReturn([]); - - $dbMock = $this->createMock(ConnectionInterface::class); - $dbMock->expects(self::atLeastOnce()) - ->method('createCommand') - ->willReturn($commandMock); - $dbMock->expects(self::atLeastOnce()) - ->method('getQueryBuilder') - ->willReturn($qbMock); - - $messageSource = new MessageSource($dbMock); - - $this->expectException(RuntimeException::class); - $messageSource->write('app', 'de', [ - 'test.id1' => [ - 'comment' => 'Translate wisely!', - 'message' => 'app: Test 1 on the (de)', - ], - ]); - } - /** * @psalm-return array>}> */ diff --git a/tests/Common/AbstractSQLDumpFileTest.php b/tests/Common/AbstractSQLDumpFileTest.php index 1adefea..e73fed2 100644 --- a/tests/Common/AbstractSQLDumpFileTest.php +++ b/tests/Common/AbstractSQLDumpFileTest.php @@ -7,21 +7,20 @@ use PHPUnit\Framework\TestCase; use Throwable; use Yiisoft\Db\Connection\ConnectionInterface; +use Yiisoft\Db\Constant\ColumnType; +use Yiisoft\Db\Constraint\ForeignKey; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidConfigException; -use Yiisoft\Db\Schema\SchemaInterface; /** * @group Mssql - * - * @psalm-suppress PropertyNotSetInConstructor */ abstract class AbstractSQLDumpFileTest extends TestCase { protected ConnectionInterface $db; - protected string $commentType = SchemaInterface::TYPE_TEXT; - protected string $messageIdType = SchemaInterface::TYPE_TEXT; - protected string $translationType = SchemaInterface::TYPE_TEXT; + protected string $commentType = ColumnType::TEXT; + protected string $messageIdType = ColumnType::TEXT; + protected string $translationType = ColumnType::TEXT; private string $driverName = ''; private string $tableSourceMessage = '{{%yii_source_message}}'; private string $tableMessage = '{{%yii_message}}'; @@ -40,11 +39,6 @@ protected function tearDown(): void unset($this->db, $this->driverName); } - /** - * @throws Exception - * @throws InvalidConfigException - * @throws Throwable - */ public function testEnsureTableAndEnsureNoTable(): void { $this->loadFromSQLDumpFile(dirname(__DIR__, 2) . "/sql/$this->driverName-up.sql"); @@ -58,22 +52,18 @@ public function testEnsureTableAndEnsureNoTable(): void $this->assertNull($this->db->getTableSchema($this->tableMessage, true)); } - /** - * @throws Exception - * @throws InvalidConfigException - * @throws Throwable - */ public function testVerifyTableStructure(): void { $this->loadFromSQLDumpFile(dirname(__DIR__, 2) . "/sql/$this->driverName-up.sql"); $tableSchema = $this->db->getTableSchema($this->tableSourceMessage); + $driverName = $this->db->getDriverName(); $this->assertSame('yii_source_message', $tableSchema?->getName()); $this->assertSame(['id'], $tableSchema?->getPrimaryKey()); $this->assertSame(['id', 'category', 'message_id', 'comment'], $tableSchema?->getColumnNames()); - $this->assertSame(SchemaInterface::TYPE_INTEGER, $tableSchema?->getColumn('id')->getType()); - $this->assertSame(SchemaInterface::TYPE_STRING, $tableSchema?->getColumn('category')->getType()); + $this->assertSame(ColumnType::INTEGER, $tableSchema?->getColumn('id')->getType()); + $this->assertSame(ColumnType::STRING, $tableSchema?->getColumn('category')->getType()); $this->assertSame($this->messageIdType, $tableSchema?->getColumn('message_id')->getType()); $this->assertSame($this->commentType, $tableSchema?->getColumn('comment')->getType()); @@ -82,28 +72,43 @@ public function testVerifyTableStructure(): void $this->assertSame('yii_message', $tableSchema?->getName()); $this->assertSame(['id', 'locale'], $tableSchema?->getPrimaryKey()); $this->assertSame(['id', 'locale', 'translation'], $tableSchema?->getColumnNames()); - $this->assertSame(SchemaInterface::TYPE_INTEGER, $tableSchema?->getColumn('id')->getType()); - $this->assertSame(SchemaInterface::TYPE_STRING, $tableSchema?->getColumn('locale')->getType()); + $this->assertSame(ColumnType::INTEGER, $tableSchema?->getColumn('id')->getType()); + $this->assertSame(ColumnType::STRING, $tableSchema?->getColumn('locale')->getType()); $this->assertSame(16, $tableSchema?->getColumn('locale')->getSize()); $this->assertSame($this->translationType, $tableSchema?->getColumn('translation')->getType()); + $foreignKey = new ForeignKey( + match ($driverName) { + 'sqlsrv', 'oci', 'mysql', 'pgsql' => 'FK_yii_source_message_yii_message', + default => '0', + }, + ['id'], + match ($driverName) { + 'sqlsrv' => 'dbo', + 'pgsql' => 'public', + 'oci' => 'YII', + default => '', + }, + 'yii_source_message', + ['id'], + 'CASCADE', + match ($driverName) { + 'mysql', 'pgsql' => 'RESTRICT', + 'oci' => null, + default => 'NO ACTION', + }, + ); $foreignKeysExpected = [ - 'FK_yii_source_message_yii_message' => [ - 0 => 'yii_source_message', - 'id' => 'id', - ], + 'FK_yii_source_message_yii_message' => $foreignKey, ]; - if ($this->driverName === 'oci' || $this->driverName === 'sqlite') { + if ($this->driverName === 'sqlite') { $foreignKeysExpected = [ - 0 => [ - 0 => 'yii_source_message', - 'id' => 'id', - ], + 0 => $foreignKey, ]; } - $this->assertSame($foreignKeysExpected, $tableSchema?->getForeignKeys()); + $this->assertEquals($foreignKeysExpected, $tableSchema?->getForeignKeys()); $this->loadFromSQLDumpFile(dirname(__DIR__, 2) . "/sql/$this->driverName-down.sql"); diff --git a/tests/Driver/Mssql/DbSchemaManagerTest.php b/tests/Driver/Mssql/DbSchemaManagerTest.php index ef36f22..5714b40 100644 --- a/tests/Driver/Mssql/DbSchemaManagerTest.php +++ b/tests/Driver/Mssql/DbSchemaManagerTest.php @@ -4,20 +4,18 @@ namespace Yiisoft\Translator\Message\Db\Tests\Driver\Mssql; -use Yiisoft\Db\Schema\SchemaInterface; +use Yiisoft\Db\Constant\ColumnType; use Yiisoft\Translator\Message\Db\Tests\Common\AbstractDbSchemaManagerTest; use Yiisoft\Translator\Message\Db\Tests\Support\MssqlFactory; /** * @group Mssql - * - * @psalm-suppress PropertyNotSetInConstructor */ final class DbSchemaManagerTest extends AbstractDbSchemaManagerTest { - protected string $commentType = SchemaInterface::TYPE_STRING; - protected string $messageIdType = SchemaInterface::TYPE_STRING; - protected string $translationType = SchemaInterface::TYPE_STRING; + protected string $commentType = ColumnType::STRING; + protected string $messageIdType = ColumnType::STRING; + protected string $translationType = ColumnType::STRING; protected function setUp(): void { diff --git a/tests/Driver/Mssql/SQLDumpFileTest.php b/tests/Driver/Mssql/SQLDumpFileTest.php index 7d88067..ef85d5f 100644 --- a/tests/Driver/Mssql/SQLDumpFileTest.php +++ b/tests/Driver/Mssql/SQLDumpFileTest.php @@ -4,20 +4,18 @@ namespace Yiisoft\Translator\Message\Db\Tests\Driver\Mssql; -use Yiisoft\Db\Schema\SchemaInterface; +use Yiisoft\Db\Constant\ColumnType; use Yiisoft\Translator\Message\Db\Tests\Common\AbstractSQLDumpFileTest; use Yiisoft\Translator\Message\Db\Tests\Support\MssqlFactory; /** * @group Mssql - * - * @psalm-suppress PropertyNotSetInConstructor */ final class SQLDumpFileTest extends AbstractSQLDumpFileTest { - protected string $commentType = SchemaInterface::TYPE_STRING; - protected string $messageIdType = SchemaInterface::TYPE_STRING; - protected string $translationType = SchemaInterface::TYPE_STRING; + protected string $commentType = ColumnType::STRING; + protected string $messageIdType = ColumnType::STRING; + protected string $translationType = ColumnType::STRING; protected function setUp(): void { diff --git a/tests/Driver/Sqlite/MessageSourceTest.php b/tests/Driver/Sqlite/MessageSourceTest.php index a42d3c1..64e013f 100644 --- a/tests/Driver/Sqlite/MessageSourceTest.php +++ b/tests/Driver/Sqlite/MessageSourceTest.php @@ -4,24 +4,14 @@ namespace Yiisoft\Translator\Message\Db\Tests\Driver\Sqlite; -use Throwable; -use Yiisoft\Db\Exception\Exception; -use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Translator\Message\Db\Tests\Common\AbstractMessageSourceTest; use Yiisoft\Translator\Message\Db\Tests\Support\SqliteFactory; /** * @group sqlite - * - * @psalm-suppress PropertyNotSetInConstructor */ final class MessageSourceTest extends AbstractMessageSourceTest { - /** - * @throws Exception - * @throws InvalidConfigException - * @throws Throwable - */ protected function setUp(): void { // create connection dbms-specific diff --git a/tests/Support/MssqlFactory.php b/tests/Support/MssqlFactory.php index f8af918..55e22c3 100644 --- a/tests/Support/MssqlFactory.php +++ b/tests/Support/MssqlFactory.php @@ -7,17 +7,23 @@ use Yiisoft\Db\Connection\ConnectionInterface; use Yiisoft\Db\Mssql\Connection; use Yiisoft\Db\Mssql\Driver; -use Yiisoft\Db\Mssql\Dsn; final class MssqlFactory extends ConnectionFactory { public function createConnection(): ConnectionInterface { + $database = getenv('YII_MSSQL_DATABASE'); + $host = getenv('YII_MSSQL_HOST'); + $port = getenv('YII_MSSQL_PORT'); + $user = getenv('YII_MSSQL_USER'); + $password = getenv('YII_MSSQL_PASSWORD'); + $pdoDriver = new Driver( - (new Dsn('sqlsrv', 'localhost', 'yiitest;TrustServerCertificate=1'))->asString(), - 'SA', - 'YourStrong!Passw0rd', + "sqlsrv:Server=$host,$port;Database=$database;TrustServerCertificate=true", + $user, + $password, ); + $pdoDriver->charset('UTF8MB4'); return new Connection($pdoDriver, $this->createSchemaCache()); } diff --git a/tests/Support/MysqlFactory.php b/tests/Support/MysqlFactory.php index 7fe7961..f7b3544 100644 --- a/tests/Support/MysqlFactory.php +++ b/tests/Support/MysqlFactory.php @@ -5,7 +5,6 @@ namespace Yiisoft\Translator\Message\Db\Tests\Support; use Yiisoft\Db\Connection\ConnectionInterface; -use Yiisoft\Db\Mysql\Dsn; use Yiisoft\Db\Mysql\Connection; use Yiisoft\Db\Mysql\Driver; @@ -13,11 +12,14 @@ final class MysqlFactory extends ConnectionFactory { public function createConnection(): ConnectionInterface { - $pdoDriver = new Driver( - (new Dsn('mysql', '127.0.0.1', 'yiitest', '3306', ['charset' => 'utf8mb4']))->asString(), - 'root', - '', - ); + $database = getenv('YII_MYSQL_DATABASE'); + $host = getenv('YII_MYSQL_HOST'); + $port = getenv('YII_MYSQL_PORT'); + $user = getenv('YII_MYSQL_USER'); + $password = getenv('YII_MYSQL_PASSWORD'); + + $pdoDriver = new Driver("mysql:host=$host;dbname=$database;port=$port", $user, $password); + $pdoDriver->charset('UTF8MB4'); return new Connection($pdoDriver, $this->createSchemaCache()); } diff --git a/tests/Support/OracleFactory.php b/tests/Support/OracleFactory.php index 7796805..c890fed 100644 --- a/tests/Support/OracleFactory.php +++ b/tests/Support/OracleFactory.php @@ -8,17 +8,19 @@ use Yiisoft\Db\Connection\ConnectionInterface; use Yiisoft\Db\Oracle\Connection; use Yiisoft\Db\Oracle\Driver; -use Yiisoft\Db\Oracle\Dsn; final class OracleFactory extends ConnectionFactory { public function createConnection(): ConnectionInterface { - $pdoDriver = new Driver( - (new Dsn('oci', 'localhost', 'XE', '1521', ['charset' => 'AL32UTF8']))->asString(), - 'system', - 'root' - ); + $database = getenv('YII_ORACLE_DATABASE'); + $host = getenv('YII_ORACLE_HOST'); + $port = getenv('YII_ORACLE_PORT'); + $user = getenv('YII_ORACLE_USER'); + $password = getenv('YII_ORACLE_PASSWORD'); + + $pdoDriver = new Driver("oci:dbname=//$host:$port/$database", $user, $password); + $pdoDriver->charset('AL32UTF8'); $pdoDriver->attributes([PDO::ATTR_STRINGIFY_FETCHES => true]); return new Connection($pdoDriver, $this->createSchemaCache()); diff --git a/tests/Support/PgsqlFactory.php b/tests/Support/PgsqlFactory.php index 077389f..f02a528 100644 --- a/tests/Support/PgsqlFactory.php +++ b/tests/Support/PgsqlFactory.php @@ -7,17 +7,19 @@ use Yiisoft\Db\Connection\ConnectionInterface; use Yiisoft\Db\Pgsql\Connection; use Yiisoft\Db\Pgsql\Driver; -use Yiisoft\Db\Pgsql\Dsn; final class PgsqlFactory extends ConnectionFactory { public function createConnection(): ConnectionInterface { - $pdoDriver = new Driver( - (new Dsn('pgsql', '127.0.0.1', 'yiitest', '5432'))->asString(), - 'root', - 'root', - ); + $database = getenv('YII_PGSQL_DATABASE'); + $host = getenv('YII_PGSQL_HOST'); + $port = getenv('YII_PGSQL_PORT'); + $user = getenv('YII_PGSQL_USER'); + $password = getenv('YII_PGSQL_PASSWORD'); + + $pdoDriver = new Driver("pgsql:host=$host;dbname=$database;port=$port", $user, $password); + $pdoDriver->charset('UTF8'); return new Connection($pdoDriver, $this->createSchemaCache()); } diff --git a/tests/Support/SqliteFactory.php b/tests/Support/SqliteFactory.php index 38fa4dd..3500a5f 100644 --- a/tests/Support/SqliteFactory.php +++ b/tests/Support/SqliteFactory.php @@ -13,7 +13,7 @@ final class SqliteFactory extends ConnectionFactory { public function createConnection(): ConnectionInterface { - $pdoDriver = new Driver((new Dsn('sqlite', __DIR__ . '/runtime/yiitest.sq3'))->asString()); + $pdoDriver = new Driver(new Dsn('sqlite', __DIR__ . '/runtime/yiitest.sq3')); return new Connection($pdoDriver, $this->createSchemaCache()); } diff --git a/tests/Support/runtime/.gitignore b/tests/Support/runtime/.gitignore index e69de29..d6b7ef3 100644 --- a/tests/Support/runtime/.gitignore +++ b/tests/Support/runtime/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..3e174c3 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,10 @@ +load(); +}