diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index bfa76d0..a1aa5e8 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -26,7 +26,7 @@ jobs: steps: - name: 'Check out the repo' - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: 'Print Docker version' run: 'docker -v' @@ -44,8 +44,8 @@ jobs: TAG="${GITHUB_REF##*/}" IS_SEMANTIC_TAG=$(echo "$TAG" | grep -q '^v\?[0-9]\+\.[0-9]\+\.[0-9]\+$' && echo true || echo false) echo "Tag = '$TAG', is semantic tag = '$IS_SEMANTIC_TAG'" - echo "::set-output name=app_image_tag::$TAG" - echo "::set-output name=is_semantic_tag::$IS_SEMANTIC_TAG" + echo "is_semantic_tag=$IS_SEMANTIC_TAG" >> $GITHUB_OUTPUT + echo "app_image_tag=$TAG" >> $GITHUB_OUTPUT - name: 'Push image to ECR' uses: keboola/action-push-to-ecr@master @@ -63,7 +63,7 @@ jobs: steps: - name: 'Check out the repo' - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: 'Pull image from ECR' uses: keboola/action-pull-from-ecr@master diff --git a/Dockerfile b/Dockerfile index 392b63c..82c523f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,73 @@ -FROM php:7.4-cli +FROM php:8.2-cli-buster ARG COMPOSER_FLAGS="--prefer-dist --no-interaction" ARG DEBIAN_FRONTEND=noninteractive +ARG SNOWFLAKE_ODBC_VERSION=2.25.12 +ARG SNOWFLAKE_GPG_KEY=630D9F3CAB551AF3 ENV COMPOSER_ALLOW_SUPERUSER 1 ENV COMPOSER_PROCESS_TIMEOUT 3600 +ENV LANGUAGE=en_US.UTF-8 +ENV LANG=en_US.UTF-8 +ENV LC_ALL=en_US.UTF-8 WORKDIR /code/ -COPY docker/php-prod.ini /usr/local/etc/php/php.ini +COPY docker/php/php-prod.ini /usr/local/etc/php/php.ini +COPY docker/php/xdebug.ini /usr/local/etc/php/conf.d/ COPY docker/composer-install.sh /tmp/composer-install.sh RUN apt-get update && apt-get install -y --no-install-recommends \ git \ locales \ unzip \ + unixodbc \ + unixodbc-dev \ + gnupg \ + debsig-verify \ + gpg-agent \ && rm -r /var/lib/apt/lists/* \ && sed -i 's/^# *\(en_US.UTF-8\)/\1/' /etc/locale.gen \ && locale-gen \ && chmod +x /tmp/composer-install.sh \ && /tmp/composer-install.sh -ENV LANGUAGE=en_US.UTF-8 -ENV LANG=en_US.UTF-8 -ENV LC_ALL=en_US.UTF-8 +# Install PHP odbc extension +# https://github.com/docker-library/php/issues/103 +RUN set -x \ + && docker-php-source extract \ + && cd /usr/src/php/ext/odbc \ + && phpize \ + && sed -ri 's@^ *test +"\$PHP_.*" *= *"no" *&& *PHP_.*=yes *$@#&@g' configure \ + && ./configure --with-unixODBC=shared,/usr \ + && docker-php-ext-install odbc \ + && docker-php-source delete + +#snoflake download + verify package +COPY docker/snowflake/snowflake-policy.pol /etc/debsig/policies/$SNOWFLAKE_GPG_KEY/generic.pol +COPY docker/snowflake/simba.snowflake.ini /usr/lib/snowflake/odbc/lib/simba.snowflake.ini +ADD https://sfc-repo.azure.snowflakecomputing.com/odbc/linux/$SNOWFLAKE_ODBC_VERSION/snowflake-odbc-$SNOWFLAKE_ODBC_VERSION.x86_64.deb /tmp/snowflake-odbc.deb + +RUN mkdir -p ~/.gnupg \ + && chmod 700 ~/.gnupg \ + && echo "disable-ipv6" >> ~/.gnupg/dirmngr.conf \ + && mkdir -p /usr/share/debsig/keyrings/$SNOWFLAKE_GPG_KEY \ + && if ! gpg --keyserver hkp://keys.gnupg.net --recv-keys $SNOWFLAKE_GPG_KEY; then \ + gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys $SNOWFLAKE_GPG_KEY; \ + fi \ + && gpg --export $SNOWFLAKE_GPG_KEY > /usr/share/debsig/keyrings/$SNOWFLAKE_GPG_KEY/debsig.gpg \ + && curl https://sfc-repo.snowflakecomputing.com/odbc/linux/$SNOWFLAKE_ODBC_VERSION/snowflake-odbc-$SNOWFLAKE_ODBC_VERSION.x86_64.deb --output /tmp/snowflake-odbc.deb \ + && debsig-verify /tmp/snowflake-odbc.deb \ + && gpg --batch --delete-key --yes $SNOWFLAKE_GPG_KEY \ + && dpkg -i /tmp/snowflake-odbc.deb \ + && rm /tmp/snowflake-odbc.deb + +RUN pecl install xdebug \ + && docker-php-ext-enable xdebug ## Composer - deps always cached unless changed # First copy only composer files COPY composer.* /code/ +COPY patches /code/patches # Download dependencies, but don't run scripts or init autoloaders as the app is missing RUN composer install $COMPOSER_FLAGS --no-scripts --no-autoloader diff --git a/composer.json b/composer.json index 7612645..597708d 100644 --- a/composer.json +++ b/composer.json @@ -3,30 +3,32 @@ "description": "MyComponent description", "license": "MIT", "require": { - "php": "^7.4", - "keboola/php-component": "^8.1", + "php": "^8.2", + "keboola/db-adapter-snowflake": "^1.4", + "keboola/php-component": "^9.4", "keboola/storage-api-client": "^14.16" }, "require-dev": { + "cweagans/composer-patches": "^1.7", "keboola/coding-standard": ">=7.0.2", "keboola/csv": "^1.1", "keboola/datadir-tests": "^5.2", "keboola/php-temp": "^2.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan": "^0.12.14", + "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^9.0", "symfony/finder": "^5.4", "symfony/process": "^5.0" }, "autoload": { "psr-4": { - "AppProjectMigrateLargeTables\\": "src/" + "Keboola\\AppProjectMigrateLargeTables\\": "src/" } }, "autoload-dev": { "psr-4": { - "AppProjectMigrateLargeTables\\Tests\\": "tests/phpunit/", - "AppProjectMigrateLargeTables\\FunctionalTests\\": "tests/functional/" + "Keboola\\AppProjectMigrateLargeTables\\Tests\\": "tests/phpunit/", + "Keboola\\AppProjectMigrateLargeTables\\FunctionalTests\\": "tests/functional/" } }, "scripts": { @@ -56,7 +58,15 @@ "sort-packages": true, "optimize-autoloader": true, "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": true + "dealerdirect/phpcodesniffer-composer-installer": true, + "cweagans/composer-patches": true + } + }, + "extra": { + "patches": { + "microsoft/azure-storage-common": [ + "patches/microsoft-azure-storage-common-src-common-internal-servicerestproxy-php.patch" + ] } } } diff --git a/composer.lock b/composer.lock index 0d0021c..64f5117 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "323ffa9530e680021e078a607dea56b8", + "content-hash": "7263ad8b18469f87c541fa7b58514984", "packages": [ { "name": "aws/aws-crt-php", @@ -62,16 +62,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.300.13", + "version": "3.301.1", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "b1eb7307d30ebcfa4e156971f658c2d177434db3" + "reference": "0a910d2b35e7087337cdf3569dc9b6ce232aafba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/b1eb7307d30ebcfa4e156971f658c2d177434db3", - "reference": "b1eb7307d30ebcfa4e156971f658c2d177434db3", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/0a910d2b35e7087337cdf3569dc9b6ce232aafba", + "reference": "0a910d2b35e7087337cdf3569dc9b6ce232aafba", "shasum": "" }, "require": { @@ -151,32 +151,31 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.300.13" + "source": "https://github.com/aws/aws-sdk-php/tree/3.301.1" }, - "time": "2024-03-07T19:14:04+00:00" + "time": "2024-03-15T18:14:42+00:00" }, { "name": "brick/math", - "version": "0.9.3", + "version": "0.11.0", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" + "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", - "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", + "url": "https://api.github.com/repos/brick/math/zipball/0ad82ce168c82ba30d1c01ec86116ab52f589478", + "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478", "shasum": "" }, "require": { - "ext-json": "*", - "php": "^7.1 || ^8.0" + "php": "^8.0" }, "require-dev": { "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", - "vimeo/psalm": "4.9.2" + "phpunit/phpunit": "^9.0", + "vimeo/psalm": "5.0.0" }, "type": "library", "autoload": { @@ -201,19 +200,15 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.9.3" + "source": "https://github.com/brick/math/tree/0.11.0" }, "funding": [ { "url": "https://github.com/BenMorel", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/brick/math", - "type": "tidelift" } ], - "time": "2021-08-15T20:50:18+00:00" + "time": "2023-01-15T23:15:59+00:00" }, { "name": "firebase/php-jwt", @@ -388,26 +383,26 @@ }, { "name": "google/cloud-core", - "version": "v1.56.0", + "version": "v1.56.2", "source": { "type": "git", "url": "https://github.com/googleapis/google-cloud-php-core.git", - "reference": "35ca0fd74685c635a4c027c871de9d716c504933" + "reference": "686ffd0bb1328cd2ee963c4444e2ab4b111ba3ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-cloud-php-core/zipball/35ca0fd74685c635a4c027c871de9d716c504933", - "reference": "35ca0fd74685c635a4c027c871de9d716c504933", + "url": "https://api.github.com/repos/googleapis/google-cloud-php-core/zipball/686ffd0bb1328cd2ee963c4444e2ab4b111ba3ba", + "reference": "686ffd0bb1328cd2ee963c4444e2ab4b111ba3ba", "shasum": "" }, "require": { "google/auth": "^1.34", - "google/gax": "^1.27.0", + "google/gax": "^1.30", "guzzlehttp/guzzle": "^6.5.8|^7.4.4", "guzzlehttp/promises": "^1.4||^2.0", "guzzlehttp/psr7": "^2.6", "monolog/monolog": "^2.9|^3.0", - "php": ">=7.4", + "php": "^8.0", "psr/http-message": "^1.0|^2.0", "rize/uri-template": "~0.3" }, @@ -448,27 +443,27 @@ ], "description": "Google Cloud PHP shared dependency, providing functionality useful to all components.", "support": { - "source": "https://github.com/googleapis/google-cloud-php-core/tree/v1.56.0" + "source": "https://github.com/googleapis/google-cloud-php-core/tree/v1.56.2" }, - "time": "2024-02-23T23:49:35+00:00" + "time": "2024-03-15T18:39:38+00:00" }, { "name": "google/cloud-storage", - "version": "v1.39.0", + "version": "v1.40.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-cloud-php-storage.git", - "reference": "2425a167578084af5c9b87fac6eb59b09b33b8f5" + "reference": "fb2cc48fbdda164d457df3107464b3d205a25529" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-cloud-php-storage/zipball/2425a167578084af5c9b87fac6eb59b09b33b8f5", - "reference": "2425a167578084af5c9b87fac6eb59b09b33b8f5", + "url": "https://api.github.com/repos/googleapis/google-cloud-php-storage/zipball/fb2cc48fbdda164d457df3107464b3d205a25529", + "reference": "fb2cc48fbdda164d457df3107464b3d205a25529", "shasum": "" }, "require": { "google/cloud-core": "^1.55", - "php": ">=7.4", + "php": "^8.0", "ramsey/uuid": "^4.2.3" }, "require-dev": { @@ -505,9 +500,9 @@ ], "description": "Cloud Storage Client for PHP", "support": { - "source": "https://github.com/googleapis/google-cloud-php-storage/tree/v1.39.0" + "source": "https://github.com/googleapis/google-cloud-php-storage/tree/v1.40.0" }, - "time": "2024-02-23T23:49:35+00:00" + "time": "2024-03-15T18:39:38+00:00" }, { "name": "google/common-protos", @@ -563,35 +558,36 @@ }, { "name": "google/gax", - "version": "v1.29.1", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/googleapis/gax-php.git", - "reference": "54a863e63ee318308637adb283f6157ccc3aabbb" + "reference": "25fb6fe93f8a871d7c626dc4599a481d9ebb6b02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/gax-php/zipball/54a863e63ee318308637adb283f6157ccc3aabbb", - "reference": "54a863e63ee318308637adb283f6157ccc3aabbb", + "url": "https://api.github.com/repos/googleapis/gax-php/zipball/25fb6fe93f8a871d7c626dc4599a481d9ebb6b02", + "reference": "25fb6fe93f8a871d7c626dc4599a481d9ebb6b02", "shasum": "" }, "require": { "google/auth": "^1.34.0", "google/common-protos": "^4.4", - "google/grpc-gcp": "^0.2||^0.3", + "google/grpc-gcp": "^0.3", "google/longrunning": "~0.2", "google/protobuf": "^3.22", "grpc/grpc": "^1.13", - "guzzlehttp/promises": "^1.4||^2.0", + "guzzlehttp/promises": "^2.0", "guzzlehttp/psr7": "^2.0", - "php": ">=7.4" + "php": "^8.0", + "ramsey/uuid": "^4.0" }, "conflict": { "ext-protobuf": "<3.7.0" }, "require-dev": { - "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9.0", + "phpspec/prophecy-phpunit": "^2.1", + "phpunit/phpunit": "^9.6", "squizlabs/php_codesniffer": "3.*" }, "type": "library", @@ -612,9 +608,9 @@ ], "support": { "issues": "https://github.com/googleapis/gax-php/issues", - "source": "https://github.com/googleapis/gax-php/tree/v1.29.1" + "source": "https://github.com/googleapis/gax-php/tree/v1.30.0" }, - "time": "2024-02-26T19:15:41+00:00" + "time": "2024-02-28T20:33:41+00:00" }, { "name": "google/grpc-gcp", @@ -1120,16 +1116,16 @@ }, { "name": "keboola/common-exceptions", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/keboola/common-exceptions.git", - "reference": "e406d05ec9307a88790692a33e84490c0eed38ce" + "reference": "35ac327808f0e4157c9de6cbe0bf8536145cb5ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/keboola/common-exceptions/zipball/e406d05ec9307a88790692a33e84490c0eed38ce", - "reference": "e406d05ec9307a88790692a33e84490c0eed38ce", + "url": "https://api.github.com/repos/keboola/common-exceptions/zipball/35ac327808f0e4157c9de6cbe0bf8536145cb5ac", + "reference": "35ac327808f0e4157c9de6cbe0bf8536145cb5ac", "shasum": "" }, "require": { @@ -1154,9 +1150,9 @@ ], "description": "Common exceptions shared between different applications", "support": { - "source": "https://github.com/keboola/common-exceptions/tree/1.2.0" + "source": "https://github.com/keboola/common-exceptions/tree/1.2.1" }, - "time": "2021-07-26T14:42:14+00:00" + "time": "2022-10-02T21:12:00+00:00" }, { "name": "keboola/csv", @@ -1207,37 +1203,78 @@ }, "time": "2023-02-02T10:54:07+00:00" }, + { + "name": "keboola/db-adapter-snowflake", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/keboola/db-adapter-snowflake.git", + "reference": "8d1548cc3724dc588b3fd38bb970072da6041158" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/keboola/db-adapter-snowflake/zipball/8d1548cc3724dc588b3fd38bb970072da6041158", + "reference": "8d1548cc3724dc588b3fd38bb970072da6041158", + "shasum": "" + }, + "require": { + "ext-odbc": "*", + "php": "^8.0" + }, + "require-dev": { + "keboola/coding-standard": ">=7.0.2", + "keboola/datadir-tests": "^5.3", + "keboola/php-temp": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpstan/phpstan": "^1.8", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Keboola\\SnowflakeDbAdapter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "support": { + "source": "https://github.com/keboola/db-adapter-snowflake/tree/1.4.0" + }, + "time": "2023-06-02T07:06:55+00:00" + }, { "name": "keboola/php-component", - "version": "8.3.0", + "version": "9.4.0", "source": { "type": "git", "url": "https://github.com/keboola/php-component.git", - "reference": "2791e6eb346dc25a3a82818fd8dbebddc8eeb79b" + "reference": "5ffea8afc13789fb0328acdbfca4e323c8232361" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/keboola/php-component/zipball/2791e6eb346dc25a3a82818fd8dbebddc8eeb79b", - "reference": "2791e6eb346dc25a3a82818fd8dbebddc8eeb79b", + "url": "https://api.github.com/repos/keboola/php-component/zipball/5ffea8afc13789fb0328acdbfca4e323c8232361", + "reference": "5ffea8afc13789fb0328acdbfca4e323c8232361", "shasum": "" }, "require": { "ext-json": "*", - "keboola/common-exceptions": "^1.0", - "monolog/monolog": "^2.0", - "php": "^7.3", - "symfony/config": "^5.0", - "symfony/filesystem": "^5.0", - "symfony/finder": "^5.0", - "symfony/serializer": "^5.0" + "keboola/common-exceptions": "^1.2", + "monolog/monolog": "^2.3", + "php": "^7.4|^8.0", + "symfony/config": "^5.4|^6.0", + "symfony/filesystem": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", + "symfony/serializer": "^5.4|^6.0" }, "require-dev": { "devedge/sami-github": "^1.0", - "jakub-onderka/php-parallel-lint": "^1.0", - "keboola/coding-standard": ">=7.0.2", + "keboola/coding-standard": "^14.0", "keboola/php-temp": "^2.0", - "phpstan/phpstan": "^0.12.14", - "phpunit/phpunit": "^9.0" + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^9.5" }, "type": "project", "autoload": { @@ -1263,9 +1300,9 @@ ], "support": { "issues": "https://github.com/keboola/php-component/issues", - "source": "https://github.com/keboola/php-component/tree/8.3.0" + "source": "https://github.com/keboola/php-component/tree/9.4.0" }, - "time": "2021-03-12T08:12:05+00:00" + "time": "2023-05-30T06:36:55+00:00" }, { "name": "keboola/php-datatypes", @@ -1647,20 +1684,20 @@ }, { "name": "psr/cache", - "version": "1.0.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/cache.git", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { @@ -1680,7 +1717,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for caching libraries", @@ -1690,9 +1727,9 @@ "psr-6" ], "support": { - "source": "https://github.com/php-fig/cache/tree/master" + "source": "https://github.com/php-fig/cache/tree/3.0.0" }, - "time": "2016-08-06T20:24:11+00:00" + "time": "2021-02-03T23:26:27+00:00" }, { "name": "psr/http-client", @@ -1856,30 +1893,30 @@ }, { "name": "psr/log", - "version": "1.1.4", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "3.x-dev" } }, "autoload": { "psr-4": { - "Psr\\Log\\": "Psr/Log/" + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1900,9 +1937,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/1.1.4" + "source": "https://github.com/php-fig/log/tree/3.0.0" }, - "time": "2021-05-03T11:20:27+00:00" + "time": "2021-07-14T16:46:02+00:00" }, { "name": "ralouphie/getallheaders", @@ -1950,21 +1987,20 @@ }, { "name": "ramsey/collection", - "version": "1.3.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/ramsey/collection.git", - "reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4" + "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/ad7475d1c9e70b190ecffc58f2d989416af339b4", - "reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4", + "url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", + "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", "shasum": "" }, "require": { - "php": "^7.4 || ^8.0", - "symfony/polyfill-php81": "^1.23" + "php": "^8.1" }, "require-dev": { "captainhook/plugin-composer": "^5.3", @@ -2024,7 +2060,7 @@ ], "support": { "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/1.3.0" + "source": "https://github.com/ramsey/collection/tree/2.0.0" }, "funding": [ { @@ -2036,29 +2072,27 @@ "type": "tidelift" } ], - "time": "2022-12-27T19:12:24+00:00" + "time": "2022-12-31T21:50:55+00:00" }, { "name": "ramsey/uuid", - "version": "4.2.3", + "version": "4.7.5", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df" + "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", - "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", + "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", "shasum": "" }, "require": { - "brick/math": "^0.8 || ^0.9", + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11", "ext-json": "*", - "php": "^7.2 || ^8.0", - "ramsey/collection": "^1.0", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-php80": "^1.14" + "php": "^8.0", + "ramsey/collection": "^1.2 || ^2.0" }, "replace": { "rhumsaa/uuid": "self.version" @@ -2070,24 +2104,23 @@ "doctrine/annotations": "^1.8", "ergebnis/composer-normalize": "^2.15", "mockery/mockery": "^1.3", - "moontoast/math": "^1.1", "paragonie/random-lib": "^2", "php-mock/php-mock": "^2.2", "php-mock/php-mock-mockery": "^1.3", "php-parallel-lint/php-parallel-lint": "^1.1", "phpbench/phpbench": "^1.0", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-mockery": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.1", "phpunit/phpunit": "^8.5 || ^9", - "slevomat/coding-standard": "^7.0", + "ramsey/composer-repl": "^1.4", + "slevomat/coding-standard": "^8.4", "squizlabs/php_codesniffer": "^3.5", "vimeo/psalm": "^4.9" }, "suggest": { "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", - "ext-ctype": "Enables faster processing of character classification using ctype functions.", "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", @@ -2095,9 +2128,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "4.x-dev" - }, "captainhook": { "force-install": true } @@ -2122,7 +2152,7 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.2.3" + "source": "https://github.com/ramsey/uuid/tree/4.7.5" }, "funding": [ { @@ -2134,20 +2164,20 @@ "type": "tidelift" } ], - "time": "2021-09-25T23:10:38+00:00" + "time": "2023-11-08T05:53:05+00:00" }, { "name": "rize/uri-template", - "version": "0.3.5", + "version": "0.3.6", "source": { "type": "git", "url": "https://github.com/rize/UriTemplate.git", - "reference": "5ed4ba8ea34af84485dea815d4b6b620794d1168" + "reference": "34efe65c79710eed0883884f2285ae6d4a0aad19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rize/UriTemplate/zipball/5ed4ba8ea34af84485dea815d4b6b620794d1168", - "reference": "5ed4ba8ea34af84485dea815d4b6b620794d1168", + "url": "https://api.github.com/repos/rize/UriTemplate/zipball/34efe65c79710eed0883884f2285ae6d4a0aad19", + "reference": "34efe65c79710eed0883884f2285ae6d4a0aad19", "shasum": "" }, "require": { @@ -2180,7 +2210,7 @@ ], "support": { "issues": "https://github.com/rize/UriTemplate/issues", - "source": "https://github.com/rize/UriTemplate/tree/0.3.5" + "source": "https://github.com/rize/UriTemplate/tree/0.3.6" }, "funding": [ { @@ -2196,42 +2226,38 @@ "type": "open_collective" } ], - "time": "2022-10-12T17:22:51+00:00" + "time": "2024-03-10T08:07:49+00:00" }, { "name": "symfony/config", - "version": "v5.4.2", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "2e082dae50da563c639119b7b52347a2a3db4ba5" + "reference": "6ea4affc27f2086c9d16b92ab5429ce1e3c38047" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/2e082dae50da563c639119b7b52347a2a3db4ba5", - "reference": "2e082dae50da563c639119b7b52347a2a3db4ba5", + "url": "https://api.github.com/repos/symfony/config/zipball/6ea4affc27f2086c9d16b92ab5429ce1e3c38047", + "reference": "6ea4affc27f2086c9d16b92ab5429ce1e3c38047", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/filesystem": "^4.4|^5.0|^6.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.16", - "symfony/polyfill-php81": "^1.22" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/finder": "<4.4" + "symfony/finder": "<5.4", + "symfony/service-contracts": "<2.5" }, "require-dev": { - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/messenger": "^4.4|^5.0|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/yaml": "^4.4|^5.0|^6.0" - }, - "suggest": { - "symfony/yaml": "To use the yaml reference dumper" + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -2259,7 +2285,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.2" + "source": "https://github.com/symfony/config/tree/v6.4.4" }, "funding": [ { @@ -2275,29 +2301,29 @@ "type": "tidelift" } ], - "time": "2021-12-15T11:06:13+00:00" + "time": "2024-02-26T07:52:26+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.2", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -2326,7 +2352,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" }, "funding": [ { @@ -2342,27 +2368,26 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/filesystem", - "version": "v5.4.35", + "version": "v6.4.3", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "5a553607d4ffbfa9c0ab62facadea296c9db7086" + "reference": "7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/5a553607d4ffbfa9c0ab62facadea296c9db7086", - "reference": "5a553607d4ffbfa9c0ab62facadea296c9db7086", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb", + "reference": "7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8", - "symfony/polyfill-php80": "^1.16" + "symfony/polyfill-mbstring": "~1.8" }, "type": "library", "autoload": { @@ -2390,7 +2415,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.35" + "source": "https://github.com/symfony/filesystem/tree/v6.4.3" }, "funding": [ { @@ -2406,20 +2431,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T13:51:25+00:00" + "time": "2024-01-23T14:51:35+00:00" }, { "name": "symfony/finder", - "version": "v5.4.3", + "version": "v5.4.35", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d" + "reference": "abe6d6f77d9465fed3cd2d029b29d03b56b56435" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/231313534dded84c7ecaa79d14bc5da4ccb69b7d", - "reference": "231313534dded84c7ecaa79d14bc5da4ccb69b7d", + "url": "https://api.github.com/repos/symfony/finder/zipball/abe6d6f77d9465fed3cd2d029b29d03b56b56435", + "reference": "abe6d6f77d9465fed3cd2d029b29d03b56b56435", "shasum": "" }, "require": { @@ -2453,7 +2478,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.3" + "source": "https://github.com/symfony/finder/tree/v5.4.35" }, "funding": [ { @@ -2469,7 +2494,7 @@ "type": "tidelift" } ], - "time": "2022-01-26T16:34:36+00:00" + "time": "2024-01-23T13:51:25+00:00" }, { "name": "symfony/polyfill-ctype", @@ -2710,82 +2735,6 @@ ], "time": "2024-01-29T20:11:03+00:00" }, - { - "name": "symfony/polyfill-php81", - "version": "v1.29.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/c565ad1e63f30e7477fc40738343c62b40bc672d", - "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.29.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-01-29T20:11:03+00:00" - }, { "name": "symfony/process", "version": "v5.4.36", @@ -2850,62 +2799,57 @@ }, { "name": "symfony/serializer", - "version": "v5.4.2", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "2dba9731463e0bb4fa9568ce67887ed6fa08e9bc" + "reference": "88da7f8fe03c5f4c2a69da907f1de03fab2e6872" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/2dba9731463e0bb4fa9568ce67887ed6fa08e9bc", - "reference": "2dba9731463e0bb4fa9568ce67887ed6fa08e9bc", + "url": "https://api.github.com/repos/symfony/serializer/zipball/88da7f8fe03c5f4c2a69da907f1de03fab2e6872", + "reference": "88da7f8fe03c5f4c2a69da907f1de03fab2e6872", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8" }, "conflict": { "doctrine/annotations": "<1.12", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/dependency-injection": "<4.4", + "symfony/dependency-injection": "<5.4", "symfony/property-access": "<5.4", - "symfony/property-info": "<5.3", - "symfony/uid": "<5.3", - "symfony/yaml": "<4.4" + "symfony/property-info": "<5.4.24|>=6,<6.2.11", + "symfony/uid": "<5.4", + "symfony/validator": "<6.4", + "symfony/yaml": "<5.4" }, "require-dev": { - "doctrine/annotations": "^1.12", + "doctrine/annotations": "^1.12|^2", "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", - "symfony/cache": "^4.4|^5.0|^6.0", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/filesystem": "^4.4|^5.0|^6.0", - "symfony/form": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^4.4|^5.0|^6.0", - "symfony/http-kernel": "^4.4|^5.0|^6.0", - "symfony/mime": "^4.4|^5.0|^6.0", - "symfony/property-access": "^5.4|^6.0", - "symfony/property-info": "^5.3|^6.0", - "symfony/uid": "^5.3|^6.0", - "symfony/validator": "^4.4|^5.0|^6.0", - "symfony/var-dumper": "^4.4|^5.0|^6.0", - "symfony/var-exporter": "^4.4|^5.0|^6.0", - "symfony/yaml": "^4.4|^5.0|^6.0" - }, - "suggest": { - "psr/cache-implementation": "For using the metadata cache.", - "symfony/config": "For using the XML mapping loader.", - "symfony/mime": "For using a MIME type guesser within the DataUriNormalizer.", - "symfony/property-access": "For using the ObjectNormalizer.", - "symfony/property-info": "To deserialize relations.", - "symfony/var-exporter": "For using the metadata compiler.", - "symfony/yaml": "For using the default YAML mapping loader." + "seld/jsonlint": "^1.10", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4.26|^6.3|^7.0", + "symfony/property-info": "^5.4.24|^6.2.11|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^5.4|^6.0|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -2933,7 +2877,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v5.4.2" + "source": "https://github.com/symfony/serializer/tree/v6.4.4" }, "funding": [ { @@ -2949,41 +2893,92 @@ "type": "tidelift" } ], - "time": "2021-12-25T19:17:31+00:00" + "time": "2024-02-22T20:27:10+00:00" } ], "packages-dev": [ + { + "name": "cweagans/composer-patches", + "version": "1.7.3", + "source": { + "type": "git", + "url": "https://github.com/cweagans/composer-patches.git", + "reference": "e190d4466fe2b103a55467dfa83fc2fecfcaf2db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweagans/composer-patches/zipball/e190d4466fe2b103a55467dfa83fc2fecfcaf2db", + "reference": "e190d4466fe2b103a55467dfa83fc2fecfcaf2db", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.3.0" + }, + "require-dev": { + "composer/composer": "~1.0 || ~2.0", + "phpunit/phpunit": "~4.6" + }, + "type": "composer-plugin", + "extra": { + "class": "cweagans\\Composer\\Patches" + }, + "autoload": { + "psr-4": { + "cweagans\\Composer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Cameron Eagans", + "email": "me@cweagans.net" + } + ], + "description": "Provides a way to patch Composer packages.", + "support": { + "issues": "https://github.com/cweagans/composer-patches/issues", + "source": "https://github.com/cweagans/composer-patches/tree/1.7.3" + }, + "time": "2022-12-20T22:53:13+00:00" + }, { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v0.7.1", + "version": "v1.0.0", "source": { "type": "git", - "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", - "reference": "fe390591e0241955f22eb9ba327d137e501c771c" + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/fe390591e0241955f22eb9ba327d137e501c771c", - "reference": "fe390591e0241955f22eb9ba327d137e501c771c", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", "shasum": "" }, "require": { "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.3", - "squizlabs/php_codesniffer": "^2.0 || ^3.0 || ^4.0" + "php": ">=5.4", + "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" }, "require-dev": { "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.3.1", "phpcompatibility/php-compatibility": "^9.0", - "sensiolabs/security-checker": "^4.1.0" + "yoast/phpunit-polyfills": "^1.0" }, "type": "composer-plugin", "extra": { - "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" }, "autoload": { "psr-4": { - "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2996,6 +2991,10 @@ "email": "franck.nijhof@dealerdirect.com", "homepage": "http://www.frenck.nl", "role": "Developer / IT Manager" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" } ], "description": "PHP_CodeSniffer Standards Composer Installer Plugin", @@ -3007,6 +3006,7 @@ "codesniffer", "composer", "installer", + "phpcbf", "phpcs", "plugin", "qa", @@ -3018,36 +3018,37 @@ "tests" ], "support": { - "issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues", - "source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer" + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "source": "https://github.com/PHPCSStandards/composer-installer" }, - "time": "2020-12-07T18:04:37+00:00" + "time": "2023-01-05T11:28:13+00:00" }, { "name": "doctrine/instantiator", - "version": "1.4.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^8.0", + "doctrine/coding-standard": "^11", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" }, "type": "library", "autoload": { @@ -3074,7 +3075,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" }, "funding": [ { @@ -3090,24 +3091,24 @@ "type": "tidelift" } ], - "time": "2020-11-10T18:47:58+00:00" + "time": "2022-12-30T00:23:10+00:00" }, { "name": "keboola/coding-standard", - "version": "13.0.0", + "version": "15.0.1", "source": { "type": "git", "url": "https://github.com/keboola/phpcs-standard.git", - "reference": "58db809123c6ef066e7327a9bbeef8d05d431fa2" + "reference": "39ae7c3d14776105d574c7c3636e76b72482916a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/keboola/phpcs-standard/zipball/58db809123c6ef066e7327a9bbeef8d05d431fa2", - "reference": "58db809123c6ef066e7327a9bbeef8d05d431fa2", + "url": "https://api.github.com/repos/keboola/phpcs-standard/zipball/39ae7c3d14776105d574c7c3636e76b72482916a", + "reference": "39ae7c3d14776105d574c7c3636e76b72482916a", "shasum": "" }, "require": { - "slevomat/coding-standard": "^7", + "slevomat/coding-standard": "^8", "squizlabs/php_codesniffer": "^3.2" }, "type": "phpcodesniffer-standard", @@ -3118,37 +3119,37 @@ "description": "Keboola coding standard", "support": { "issues": "https://github.com/keboola/phpcs-standard/issues", - "source": "https://github.com/keboola/phpcs-standard/tree/13.0.0" + "source": "https://github.com/keboola/phpcs-standard/tree/15.0.1" }, - "time": "2021-07-25T10:54:36+00:00" + "time": "2023-12-11T08:31:50+00:00" }, { "name": "keboola/datadir-tests", - "version": "5.2.1", + "version": "5.6.0", "source": { "type": "git", "url": "https://github.com/keboola/datadir-tests.git", - "reference": "be02e9dc7869c4224cff6dd1b0cdc7937753b234" + "reference": "d43f7657806d660f2326d8c438dd800d7ccc1e3d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/keboola/datadir-tests/zipball/be02e9dc7869c4224cff6dd1b0cdc7937753b234", - "reference": "be02e9dc7869c4224cff6dd1b0cdc7937753b234", + "url": "https://api.github.com/repos/keboola/datadir-tests/zipball/d43f7657806d660f2326d8c438dd800d7ccc1e3d", + "reference": "d43f7657806d660f2326d8c438dd800d7ccc1e3d", "shasum": "" }, "require": { "ext-json": "*", "keboola/php-temp": "^2.0", - "php": "^7.3", - "phpunit/phpunit": "^9.0", - "symfony/filesystem": "^5.0", - "symfony/finder": "^5.0", - "symfony/process": "^5.0" + "php": "^7.4|^8.0", + "phpunit/phpunit": "^9.5", + "symfony/filesystem": "^5.0|^6.0", + "symfony/finder": "^5.0|^6.0", + "symfony/process": "^5.0|^6.0" }, "require-dev": { - "jakub-onderka/php-parallel-lint": "^1.0", - "keboola/coding-standard": "^9.0", - "phpstan/phpstan": "^0.12.14" + "keboola/coding-standard": "^13.0", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpstan/phpstan": "^1.4" }, "type": "library", "autoload": { @@ -3163,9 +3164,9 @@ "description": "Tool for functional testing of Keboola Connection components", "support": { "issues": "https://github.com/keboola/datadir-tests/issues", - "source": "https://github.com/keboola/datadir-tests/tree/5.2.1" + "source": "https://github.com/keboola/datadir-tests/tree/5.6.0" }, - "time": "2020-11-30T19:23:38+00:00" + "time": "2023-10-20T08:02:53+00:00" }, { "name": "keboola/php-temp", @@ -3221,34 +3222,38 @@ }, { "name": "myclabs/deep-copy", - "version": "1.10.2", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, "files": [ "src/DeepCopy/deep_copy.php" - ] + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3264,7 +3269,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" }, "funding": [ { @@ -3272,29 +3277,31 @@ "type": "tidelift" } ], - "time": "2020-11-13T09:40:50+00:00" + "time": "2023-03-08T13:26:56+00:00" }, { "name": "nikic/php-parser", - "version": "v4.13.2", + "version": "v5.0.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077" + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13", + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -3302,7 +3309,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -3326,26 +3333,27 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2" }, - "time": "2021-11-30T19:35:32+00:00" + "time": "2024-03-05T20:51:40+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -3386,22 +3394,28 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2021-07-20T11:28:43+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { "name": "phar-io/version", - "version": "3.1.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "bae7c545bef187884426f042434e561ab1ddb182" + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", - "reference": "bae7c545bef187884426f042434e561ab1ddb182", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", "shasum": "" }, "require": { @@ -3437,22 +3451,22 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.1.0" + "source": "https://github.com/phar-io/version/tree/3.2.1" }, - "time": "2021-02-23T14:00:09+00:00" + "time": "2022-02-21T01:04:05+00:00" }, { "name": "php-parallel-lint/php-parallel-lint", - "version": "v1.3.1", + "version": "v1.3.2", "source": { "type": "git", "url": "https://github.com/php-parallel-lint/PHP-Parallel-Lint.git", - "reference": "761f3806e30239b5fcd90a0a45d41dc2138de192" + "reference": "6483c9832e71973ed29cf71bd6b3f4fde438a9de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/761f3806e30239b5fcd90a0a45d41dc2138de192", - "reference": "761f3806e30239b5fcd90a0a45d41dc2138de192", + "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/6483c9832e71973ed29cf71bd6b3f4fde438a9de", + "reference": "6483c9832e71973ed29cf71bd6b3f4fde438a9de", "shasum": "" }, "require": { @@ -3465,7 +3479,7 @@ }, "require-dev": { "nette/tester": "^1.3 || ^2.0", - "php-parallel-lint/php-console-highlighter": "~0.3", + "php-parallel-lint/php-console-highlighter": "0.* || ^1.0", "squizlabs/php_codesniffer": "^3.6" }, "suggest": { @@ -3477,7 +3491,7 @@ "type": "library", "autoload": { "classmap": [ - "./" + "./src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3494,268 +3508,39 @@ "homepage": "https://github.com/php-parallel-lint/PHP-Parallel-Lint", "support": { "issues": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/issues", - "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/v1.3.1" - }, - "time": "2021-08-13T05:35:13+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", - "shasum": "" - }, - "require": { - "ext-filter": "*", - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" - }, - "time": "2021-10-19T17:43:47+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706", - "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" - }, - "require-dev": { - "ext-tokenizer": "*", - "psalm/phar": "^4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0" - }, - "time": "2022-01-04T19:58:01+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "v1.15.0", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", - "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.2", - "phpdocumentor/reflection-docblock": "^5.2", - "sebastian/comparator": "^3.0 || ^4.0", - "sebastian/recursion-context": "^3.0 || ^4.0" - }, - "require-dev": { - "phpspec/phpspec": "^6.0 || ^7.0", - "phpunit/phpunit": "^8.0 || ^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "support": { - "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" + "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/v1.3.2" }, - "time": "2021-12-08T12:19:24+00:00" + "time": "2022-02-21T12:50:22+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.2.0", + "version": "1.26.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "dbc093d7af60eff5cd575d2ed761b15ed40bd08e" + "reference": "231e3186624c03d7e7c890ec662b81e6b0405227" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/dbc093d7af60eff5cd575d2ed761b15ed40bd08e", - "reference": "dbc093d7af60eff5cd575d2ed761b15ed40bd08e", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/231e3186624c03d7e7c890ec662b81e6b0405227", + "reference": "231e3186624c03d7e7c890ec662b81e6b0405227", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": "^7.2 || ^8.0" }, "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": "^9.5", "symfony/process": "^5.2" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, "autoload": { "psr-4": { "PHPStan\\PhpDocParser\\": [ @@ -3770,26 +3555,26 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.2.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.26.0" }, - "time": "2021-09-16T20:46:02+00:00" + "time": "2024-02-23T16:05:55+00:00" }, { "name": "phpstan/phpstan", - "version": "0.12.99", + "version": "1.10.64", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "b4d40f1d759942f523be267a1bab6884f46ca3f7" + "reference": "fb9f270daffedcb5ff46275dcafe92538b1bc4bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b4d40f1d759942f523be267a1bab6884f46ca3f7", - "reference": "b4d40f1d759942f523be267a1bab6884f46ca3f7", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fb9f270daffedcb5ff46275dcafe92538b1bc4bb", + "reference": "fb9f270daffedcb5ff46275dcafe92538b1bc4bb", "shasum": "" }, "require": { - "php": "^7.1|^8.0" + "php": "^7.2|^8.0" }, "conflict": { "phpstan/phpstan-shim": "*" @@ -3799,11 +3584,6 @@ "phpstan.phar" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.12-dev" - } - }, "autoload": { "files": [ "bootstrap.php" @@ -3814,9 +3594,16 @@ "MIT" ], "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/0.12.99" + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, "funding": [ { @@ -3827,36 +3614,32 @@ "url": "https://github.com/phpstan", "type": "github" }, - { - "url": "https://www.patreon.com/phpstan", - "type": "patreon" - }, { "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", "type": "tidelift" } ], - "time": "2021-09-12T20:09:55+00:00" + "time": "2024-03-21T09:57:47+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.10", + "version": "9.2.31", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687" + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d5850aaf931743067f4bfc1ae4cbd06468400687", - "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.13.0", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -3871,8 +3654,8 @@ "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "type": "library", "extra": { @@ -3905,7 +3688,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.10" + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" }, "funding": [ { @@ -3913,7 +3697,7 @@ "type": "github" } ], - "time": "2021-12-05T09:12:13+00:00" + "time": "2024-03-02T06:37:42+00:00" }, { "name": "phpunit/php-file-iterator", @@ -4158,20 +3942,20 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.13", + "version": "9.6.17", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "597cb647654ede35e43b137926dfdfef0fb11743" + "reference": "1a156980d78a6666721b7e8e8502fe210b587fcd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/597cb647654ede35e43b137926dfdfef0fb11743", - "reference": "597cb647654ede35e43b137926dfdfef0fb11743", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1a156980d78a6666721b7e8e8502fe210b587fcd", + "reference": "1a156980d78a6666721b7e8e8502fe210b587fcd", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1", + "doctrine/instantiator": "^1.3.1 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", @@ -4182,31 +3966,26 @@ "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", - "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.7", + "phpunit/php-code-coverage": "^9.2.28", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", "phpunit/php-timer": "^5.0.2", "sebastian/cli-parser": "^1.0.1", "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.5", + "sebastian/comparator": "^4.0.8", "sebastian/diff": "^4.0.3", "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.3", + "sebastian/exporter": "^4.0.5", "sebastian/global-state": "^5.0.1", "sebastian/object-enumerator": "^4.0.3", "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^2.3.4", + "sebastian/type": "^3.2", "sebastian/version": "^3.0.2" }, - "require-dev": { - "ext-pdo": "*", - "phpspec/prophecy-phpunit": "^2.0.1" - }, "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "bin": [ "phpunit" @@ -4214,15 +3993,15 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.5-dev" + "dev-master": "9.6-dev" } }, "autoload": { - "classmap": [ - "src/" - ], "files": [ "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -4245,7 +4024,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.13" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.17" }, "funding": [ { @@ -4255,22 +4035,26 @@ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" } ], - "time": "2022-01-24T07:33:35+00:00" + "time": "2024-02-23T13:14:51+00:00" }, { "name": "sebastian/cli-parser", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { @@ -4305,7 +4089,7 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" }, "funding": [ { @@ -4313,7 +4097,7 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2024-03-02T06:27:43+00:00" }, { "name": "sebastian/code-unit", @@ -4428,16 +4212,16 @@ }, { "name": "sebastian/comparator", - "version": "4.0.6", + "version": "4.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382" + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", "shasum": "" }, "require": { @@ -4490,7 +4274,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" }, "funding": [ { @@ -4498,24 +4282,24 @@ "type": "github" } ], - "time": "2020-10-26T15:49:45+00:00" + "time": "2022-09-14T12:41:17+00:00" }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -4547,7 +4331,7 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" }, "funding": [ { @@ -4555,20 +4339,20 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2023-12-22T06:19:30+00:00" }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { @@ -4613,7 +4397,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -4621,20 +4405,20 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", - "version": "5.1.3", + "version": "5.1.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac" + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", "shasum": "" }, "require": { @@ -4676,7 +4460,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" }, "funding": [ { @@ -4684,20 +4468,20 @@ "type": "github" } ], - "time": "2020-09-28T05:52:38+00:00" + "time": "2023-02-03T06:03:51+00:00" }, { "name": "sebastian/exporter", - "version": "4.0.4", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", - "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", "shasum": "" }, "require": { @@ -4753,7 +4537,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" }, "funding": [ { @@ -4761,20 +4545,20 @@ "type": "github" } ], - "time": "2021-11-11T14:18:36+00:00" + "time": "2024-03-02T06:33:00+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.3", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49" + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49", - "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", "shasum": "" }, "require": { @@ -4817,7 +4601,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" }, "funding": [ { @@ -4825,24 +4609,24 @@ "type": "github" } ], - "time": "2021-06-11T13:31:12+00:00" + "time": "2024-03-02T06:35:11+00:00" }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -4874,7 +4658,7 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" }, "funding": [ { @@ -4882,7 +4666,7 @@ "type": "github" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2023-12-22T06:20:34+00:00" }, { "name": "sebastian/object-enumerator", @@ -4998,16 +4782,16 @@ }, { "name": "sebastian/recursion-context", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", "shasum": "" }, "require": { @@ -5046,10 +4830,10 @@ } ], "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" }, "funding": [ { @@ -5057,20 +4841,20 @@ "type": "github" } ], - "time": "2020-10-26T13:17:30+00:00" + "time": "2023-02-03T06:07:39+00:00" }, { "name": "sebastian/resource-operations", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { @@ -5082,7 +4866,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -5103,8 +4887,7 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" }, "funding": [ { @@ -5112,32 +4895,32 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2024-03-14T16:00:52+00:00" }, { "name": "sebastian/type", - "version": "2.3.4", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914" + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914", - "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", "shasum": "" }, "require": { "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -5160,7 +4943,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3.4" + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" }, "funding": [ { @@ -5168,7 +4951,7 @@ "type": "github" } ], - "time": "2021-06-15T12:49:02+00:00" + "time": "2023-02-03T06:13:03+00:00" }, { "name": "sebastian/version", @@ -5225,42 +5008,42 @@ }, { "name": "slevomat/coding-standard", - "version": "7.0.18", + "version": "8.15.0", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "b81ac84f41a4797dc25c8ede1b0718e2a74be0fc" + "reference": "7d1d957421618a3803b593ec31ace470177d7817" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/b81ac84f41a4797dc25c8ede1b0718e2a74be0fc", - "reference": "b81ac84f41a4797dc25c8ede1b0718e2a74be0fc", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/7d1d957421618a3803b593ec31ace470177d7817", + "reference": "7d1d957421618a3803b593ec31ace470177d7817", "shasum": "" }, "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7", - "php": "^7.1 || ^8.0", - "phpstan/phpdoc-parser": "^1.0.0", - "squizlabs/php_codesniffer": "^3.6.1" + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", + "php": "^7.2 || ^8.0", + "phpstan/phpdoc-parser": "^1.23.1", + "squizlabs/php_codesniffer": "^3.9.0" }, "require-dev": { - "phing/phing": "2.17.0", - "php-parallel-lint/php-parallel-lint": "1.3.1", - "phpstan/phpstan": "1.2.0", - "phpstan/phpstan-deprecation-rules": "1.0.0", - "phpstan/phpstan-phpunit": "1.0.0", - "phpstan/phpstan-strict-rules": "1.1.0", - "phpunit/phpunit": "7.5.20|8.5.21|9.5.10" + "phing/phing": "2.17.4", + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpstan/phpstan": "1.10.60", + "phpstan/phpstan-deprecation-rules": "1.1.4", + "phpstan/phpstan-phpunit": "1.3.16", + "phpstan/phpstan-strict-rules": "1.5.2", + "phpunit/phpunit": "8.5.21|9.6.8|10.5.11" }, "type": "phpcodesniffer-standard", "extra": { "branch-alias": { - "dev-master": "7.x-dev" + "dev-master": "8.x-dev" } }, "autoload": { "psr-4": { - "SlevomatCodingStandard\\": "SlevomatCodingStandard" + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" } }, "notification-url": "https://packagist.org/downloads/", @@ -5268,9 +5051,13 @@ "MIT" ], "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/7.0.18" + "source": "https://github.com/slevomat/coding-standard/tree/8.15.0" }, "funding": [ { @@ -5282,20 +5069,20 @@ "type": "tidelift" } ], - "time": "2021-12-07T17:19:06+00:00" + "time": "2024-03-09T15:20:58+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.6.2", + "version": "3.9.0", "source": { "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a" + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5e4e71592f69da17871dba6e80dd51bce74a351a", - "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/d63cee4890a8afaf86a22e51ad4d97c91dd4579b", + "reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b", "shasum": "" }, "require": { @@ -5305,11 +5092,11 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", "extra": { @@ -5324,34 +5111,58 @@ "authors": [ { "name": "Greg Sherwood", - "role": "lead" + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", "keywords": [ "phpcs", - "standards" + "standards", + "static analysis" ], "support": { - "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", - "source": "https://github.com/squizlabs/PHP_CodeSniffer", - "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" }, - "time": "2021-12-12T21:44:58+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-02-16T15:06:51+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.1", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { @@ -5380,7 +5191,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, "funding": [ { @@ -5388,65 +5199,7 @@ "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.10.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.10.0" - }, - "time": "2021-03-09T10:59:23+00:00" + "time": "2024-03-03T12:36:25+00:00" } ], "aliases": [], @@ -5455,7 +5208,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.4" + "php": "^8.2" }, "platform-dev": [], "plugin-api-version": "2.6.0" diff --git a/docker/php-prod.ini b/docker/php/php-prod.ini similarity index 100% rename from docker/php-prod.ini rename to docker/php/php-prod.ini diff --git a/docker/php/xdebug.ini b/docker/php/xdebug.ini new file mode 100644 index 0000000..13e2f2c --- /dev/null +++ b/docker/php/xdebug.ini @@ -0,0 +1,6 @@ +[xdebug] +xdebug.mode=develop +xdebug.start_with_request=yes +xdebug.discover_client_host=0 +xdebug.client_host=host.docker.internal +xdebug.max_nesting_level = 250 \ No newline at end of file diff --git a/docker/snowflake/simba.snowflake.ini b/docker/snowflake/simba.snowflake.ini new file mode 100644 index 0000000..e1dfaf8 --- /dev/null +++ b/docker/snowflake/simba.snowflake.ini @@ -0,0 +1,10 @@ +[Driver] +DriverManagerEncoding=UTF-16 +DriverLocale=en-US +ErrorMessagesPath=/usr/lib/snowflake/odbc/ErrorMessages/ +LogNamespace= +LogPath=/tmp +ODBCInstLib=libodbcinst.so +#LogLevel=6 +CABundleFile=/usr/lib/snowflake/odbc/lib/cacert.pem +DisableOCSPCheck=true \ No newline at end of file diff --git a/docker/snowflake/snowflake-policy.pol b/docker/snowflake/snowflake-policy.pol new file mode 100644 index 0000000..3799c82 --- /dev/null +++ b/docker/snowflake/snowflake-policy.pol @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/patches/microsoft-azure-storage-common-src-common-internal-servicerestproxy-php.patch b/patches/microsoft-azure-storage-common-src-common-internal-servicerestproxy-php.patch new file mode 100644 index 0000000..9f80a17 --- /dev/null +++ b/patches/microsoft-azure-storage-common-src-common-internal-servicerestproxy-php.patch @@ -0,0 +1,11 @@ +--- /dev/null ++++ ../src/Common/Internal/ServiceRestProxy.php +@@ -77,7 +77,7 @@ + array $options = [] + ) { + $primaryUri = Utilities::appendDelimiter($primaryUri, '/'); +- $secondaryUri = Utilities::appendDelimiter($secondaryUri, '/'); ++ $secondaryUri = Utilities::appendDelimiter($secondaryUri ?? '', '/'); + + $dataSerializer = new XmlSerializer(); + parent::__construct($dataSerializer); \ No newline at end of file diff --git a/phpstan.neon b/phpstan.neon index cf09657..5c36f98 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,4 +1,4 @@ parameters: checkMissingIterableValueType: false ignoreErrors: - - '#Cannot call method scalarNode\(\) on Symfony\\Component\\Config\\Definition\\Builder\\NodeParentInterface\|null.#' + - '#Cannot call method scalarNode\(\) on Symfony\\Component\\Config\\Definition\\Builder\\NodeParentInterface\|null\.#' diff --git a/src/Component.php b/src/Component.php index 30d0c16..1a2d71d 100644 --- a/src/Component.php +++ b/src/Component.php @@ -2,9 +2,17 @@ declare(strict_types=1); -namespace AppProjectMigrateLargeTables; +namespace Keboola\AppProjectMigrateLargeTables; +use Keboola\AppProjectMigrateLargeTables\Configuration\ConfigDefinition; +use Keboola\AppProjectMigrateLargeTables\Configuration\CreateReplicationsConfigDefinition; +use Keboola\AppProjectMigrateLargeTables\Snowflake\Connection; +use Keboola\AppProjectMigrateLargeTables\Strategy\DatabaseMigrate; +use Keboola\AppProjectMigrateLargeTables\Strategy\DatabaseReplication; +use Keboola\AppProjectMigrateLargeTables\Strategy\SapiMigrate; use Keboola\Component\BaseComponent; +use Keboola\Component\UserException; +use Keboola\SnowflakeDbAdapter\Exception\SnowflakeDbAdapterException; use Keboola\StorageApi\Client; class Component extends BaseComponent @@ -16,14 +24,95 @@ protected function run(): void 'token' => $this->getConfig()->getSourceKbcToken(), ]); - $destinationSapiClient = new Client([ - 'url' => (string) getenv('KBC_URL'), - 'token' => (string) getenv('KBC_TOKEN'), + $targetSapiClient = new Client([ + 'url' => $this->getConfig()->getEnvKbcUrl(), + 'token' => $this->getConfig()->getEnvKbcToken(), ]); + switch ($this->getConfig()->getMode()) { + case 'sapi': + $strategy = new SapiMigrate( + $sourceSapiClient, + $targetSapiClient, + $this->getLogger(), + ); + break; + case 'database': + $verifyToken = $sourceSapiClient->verifyToken(); - $app = new Application($sourceSapiClient, $destinationSapiClient, $this->getLogger()); + $sourceDatabase = sprintf( + '%s_%s', + $this->getConfig()->getSourceDatabasePrefix(), + $verifyToken['owner']['id'], + ); - $app->run($this->getConfig()->getMigrateTables()); + $replicaDatabase = sprintf( + '%s_%s_REPLICA', + $this->getConfig()->getReplicaDatabasePrefix(), + $verifyToken['owner']['id'], + ); + $targetDatabase = sprintf( + '%s_%s', + $this->getConfig()->getTargetDatabasePrefix(), + $targetSapiClient->verifyToken()['owner']['id'], + ); + + try { + $targetConnection = new Connection([ + 'host' => $this->getConfig()->getTargetHost(), + 'user' => $this->getConfig()->getTargetUser(), + 'password' => $this->getConfig()->getTargetPassword(), + 'database' => $targetDatabase, + ]); + } catch (SnowflakeDbAdapterException $e) { + throw new UserException($e->getMessage(), $e->getCode(), $e); + } + + $strategy = new DatabaseMigrate( + $this->getLogger(), + $targetConnection, + $targetSapiClient, + $sourceDatabase, + $replicaDatabase, + $targetDatabase, + ); + break; + default: + throw new UserException(sprintf('Unknown mode "%s"', $this->getConfig()->getMode())); + } + + $strategy->migrate($this->getConfig()); + } + + public function createReplicationsAction(): array + { + try { + $sourceConnection = new Connection([ + 'host' => $this->getConfig()->getSourceHost(), + 'user' => $this->getConfig()->getSourceUser(), + 'password' => $this->getConfig()->getSourcePassword(), + ]); + + $targetConnection = new Connection([ + 'host' => $this->getConfig()->getTargetHost(), + 'user' => $this->getConfig()->getTargetUser(), + 'password' => $this->getConfig()->getTargetPassword(), + ]); + } catch (SnowflakeDbAdapterException $e) { + throw new UserException($e->getMessage(), $e->getCode(), $e); + } + + $strategy = new DatabaseReplication( + $this->getLogger(), + $sourceConnection, + $targetConnection, + ); + $strategy->createReplications( + $this->getConfig(), + $this->getConfig()->getProjectIdFrom(), + $this->getConfig()->getProjectIdTo(), + ); + + return ['status' => 'ok']; } public function getConfig(): Config @@ -33,6 +122,13 @@ public function getConfig(): Config return $config; } + protected function getSyncActions(): array + { + return [ + 'createReplications' => 'createReplicationsAction', + ]; + } + protected function getConfigClass(): string { return Config::class; @@ -40,6 +136,13 @@ protected function getConfigClass(): string protected function getConfigDefinitionClass(): string { - return ConfigDefinition::class; + $rawConfig = $this->getRawConfig(); + $action = $rawConfig['action'] ?? 'run'; + switch ($action) { + case 'createReplications': + return CreateReplicationsConfigDefinition::class; + default: + return ConfigDefinition::class; + } } } diff --git a/src/Config.php b/src/Config.php index b1aeb01..bc0ac55 100644 --- a/src/Config.php +++ b/src/Config.php @@ -2,24 +2,156 @@ declare(strict_types=1); -namespace AppProjectMigrateLargeTables; +namespace Keboola\AppProjectMigrateLargeTables; use Keboola\Component\Config\BaseConfig; class Config extends BaseConfig { + private const STACK_DATABASES = [ + 'connection.keboola.com' => [ + 'db_replica_prefix' => 'AWSUS', + 'db_prefix' => 'SAPI', + 'account' => 'KEBOOLA', + 'region' => 'AWS_US_WEST_2', + ], + 'connection.eu-central-1.keboola.com' => [ + 'db_replica_prefix' => 'AWSEU', + 'db_prefix' => 'KEBOOLA', + 'account' => 'KEBOOLA', + 'region' => 'AWS_EU_CENTRAL_1', + ], + 'connection.north-europe.azure.keboola.com' => [ + 'db_replica_prefix' => 'AZNE', + 'db_prefix' => 'KEBOOLA', + 'account' => 'KEBOOLA', + 'region' => 'AZURE_WESTEUROPE', + ], + 'connection.europe-west3.gcp.keboola.com' => [ + 'db_replica_prefix' => 'GCPEUW3', + 'db_prefix' => 'KBC_EUW3', + 'account' => 'IK34405', + 'region' => 'GCP_EUROPE_WEST4', + ], + 'connection.us-east4.gcp.keboola.com' => [ + 'db_replica_prefix' => 'GCPUSE4', + 'db_prefix' => 'KBC_USE4', + 'account' => 'NE35810', + 'region' => 'GCP_US_EAST4', + ], + ]; + + public function getMode(): string + { + return $this->getStringValue(['parameters', 'mode']); + } + public function getSourceKbcUrl(): string { - return $this->getValue(['parameters', 'sourceKbcUrl']); + return $this->getStringValue(['parameters', 'sourceKbcUrl']); } public function getSourceKbcToken(): string { - return $this->getValue(['parameters', '#sourceKbcToken']); + return $this->getStringValue(['parameters', '#sourceKbcToken']); } public function getMigrateTables(): array { - return $this->getValue(['parameters', 'tables']); + return $this->getArrayValue(['parameters', 'tables']); + } + + public function getTargetHost(): string + { + return $this->getDbConfigNode()['host']; + } + + public function getTargetUser(): string + { + return $this->getDbConfigNode()['username']; + } + + public function getTargetPassword(): string + { + return $this->getDbConfigNode()['#password']; + } + + public function getTargetWarehouse(): string + { + return $this->getDbConfigNode()['warehouse']; + } + + public function getSourceDatabaseAccount(): string + { + $url = parse_url($this->getSourceKbcUrl()); + assert($url && array_key_exists('host', $url)); + + return self::STACK_DATABASES[$url['host']]['account']; + } + + public function getSourceDatabaseRegion(): string + { + $url = parse_url($this->getSourceKbcUrl()); + assert($url && array_key_exists('host', $url)); + + return self::STACK_DATABASES[$url['host']]['region']; + } + + public function getSourceDatabasePrefix(): string + { + $url = parse_url($this->getSourceKbcUrl()); + assert($url && array_key_exists('host', $url)); + + return self::STACK_DATABASES[$url['host']]['db_prefix']; + } + + public function getReplicaDatabasePrefix(): string + { + $url = parse_url($this->getSourceKbcUrl()); + assert($url && array_key_exists('host', $url)); + + return self::STACK_DATABASES[$url['host']]['db_replica_prefix']; + } + + public function getTargetDatabasePrefix(): string + { + $url = parse_url($this->getEnvKbcUrl()); + assert($url && array_key_exists('host', $url)); + + return self::STACK_DATABASES[$url['host']]['db_prefix']; + } + + public function getSourceHost(): string + { + return $this->getStringValue(['parameters', 'sourceHost']); + } + + public function getSourceUser(): string + { + return $this->getStringValue(['parameters', 'sourceUsername']); + } + + public function getSourcePassword(): string + { + return $this->getStringValue(['parameters', '#sourcePassword']); + } + + public function getProjectIdFrom(): int + { + return $this->getIntValue(['parameters', 'projectIdFrom']); + } + + public function getProjectIdTo(): int + { + return $this->getIntValue(['parameters', 'projectIdTo']); + } + + private function getDbConfigNode(): array + { + $paramDb = $this->getArrayValue(['parameters', 'db'], []); + if ($paramDb) { + return $paramDb; + } + return $this->getImageParameters()['db']; } } diff --git a/src/ConfigDefinition.php b/src/Configuration/ConfigDefinition.php similarity index 56% rename from src/ConfigDefinition.php rename to src/Configuration/ConfigDefinition.php index 8ccacf0..f70b188 100644 --- a/src/ConfigDefinition.php +++ b/src/Configuration/ConfigDefinition.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace AppProjectMigrateLargeTables; +namespace Keboola\AppProjectMigrateLargeTables\Configuration; use Keboola\Component\Config\BaseConfigDefinition; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; @@ -16,9 +16,18 @@ protected function getParametersDefinition(): ArrayNodeDefinition /** @noinspection NullPointerExceptionInspection */ $parametersNode ->children() + ->enumNode('mode')->values(['sapi', 'database'])->defaultValue('sapi')->end() ->scalarNode('sourceKbcUrl')->isRequired()->cannotBeEmpty()->end() ->scalarNode('#sourceKbcToken')->isRequired()->cannotBeEmpty()->end() - ->arrayNode('tables')->prototype('scalar')->end() + ->arrayNode('tables')->prototype('scalar')->end()->end() + ->arrayNode('db') + ->children() + ->scalarNode('host')->isRequired()->cannotBeEmpty()->end() + ->scalarNode('username')->isRequired()->cannotBeEmpty()->end() + ->scalarNode('#password')->isRequired()->cannotBeEmpty()->end() + ->scalarNode('warehouse')->isRequired()->cannotBeEmpty()->end() + ->end() + ->end() ->end() ; // @formatter:on diff --git a/src/Configuration/CreateReplicationsConfigDefinition.php b/src/Configuration/CreateReplicationsConfigDefinition.php new file mode 100644 index 0000000..f9ca1e9 --- /dev/null +++ b/src/Configuration/CreateReplicationsConfigDefinition.php @@ -0,0 +1,30 @@ +children() + ->scalarNode('sourceKbcUrl')->isRequired()->cannotBeEmpty()->end() + ->scalarNode('sourceHost')->isRequired()->cannotBeEmpty()->end() + ->scalarNode('sourceUsername')->isRequired()->cannotBeEmpty()->end() + ->scalarNode('#sourcePassword')->isRequired()->cannotBeEmpty()->end() + ->integerNode('projectIdFrom')->isRequired()->end() + ->integerNode('projectIdTo')->isRequired()->end() + ->end() + ; + // @formatter:on + return $parametersNode; + } +} diff --git a/src/MigrateInterface.php b/src/MigrateInterface.php new file mode 100644 index 0000000..ed5ac71 --- /dev/null +++ b/src/MigrateInterface.php @@ -0,0 +1,12 @@ +user = $options['user']; + parent::__construct($options); + $this->useRole('ACCOUNTADMIN'); + } + + public function useRole(string $roleName): void + { + $this->query(sprintf('USE ROLE %s', QueryBuilder::quoteIdentifier($roleName))); + } + + public function getCurrentRole(): string + { + return $this->fetchAll('SELECT CURRENT_ROLE() AS "role";')[0]['role']; + } + + public function getRegion(): string + { + if (is_null($this->region)) { + $this->region = $this->fetchAll('SELECT CURRENT_REGION() AS "region";')[0]['region']; + } + return $this->region; + } + + public function getAccount(): string + { + if (is_null($this->account)) { + $this->account = $this->fetchAll('SELECT CURRENT_ACCOUNT() AS "account";')[0]['account']; + } + return $this->account; + } + + public function grantRoleToMigrateUser(string $tableRole): void + { + $previousRole = $this->getCurrentRole(); + $this->useRole('ACCOUNTADMIN'); + $this->query(sprintf( + 'GRANT ROLE %s TO USER %s;', + QueryBuilder::quoteIdentifier($tableRole), + QueryBuilder::quoteIdentifier($this->user), + )); + $this->useRole($previousRole); + } + + public function grantPrivilegesToReplicaDatabase(string $replicaDatabase, string $tableRole): void + { + $previousRole = $this->getCurrentRole(); + $this->useRole('ACCOUNTADMIN'); + $this->query(sprintf( + 'GRANT USAGE ON DATABASE %s TO ROLE %s;', + QueryBuilder::quoteIdentifier($replicaDatabase), + QueryBuilder::quoteIdentifier($tableRole), + )); + + $this->query(sprintf( + 'GRANT USAGE ON ALL SCHEMAS IN DATABASE %s TO ROLE %s;', + QueryBuilder::quoteIdentifier($replicaDatabase), + QueryBuilder::quoteIdentifier($tableRole), + )); + + $this->query(sprintf( + 'GRANT SELECT ON ALL TABLES IN DATABASE %s TO ROLE %s;', + QueryBuilder::quoteIdentifier($replicaDatabase), + QueryBuilder::quoteIdentifier($tableRole), + )); + + $this->useRole($previousRole); + } +} diff --git a/src/Strategy/DatabaseMigrate.php b/src/Strategy/DatabaseMigrate.php new file mode 100644 index 0000000..51604d6 --- /dev/null +++ b/src/Strategy/DatabaseMigrate.php @@ -0,0 +1,275 @@ +targetConnection->getCurrentRole(); + $this->targetConnection->useRole('ACCOUNTADMIN'); + $this->createReplicaDatabase($config); + $this->refreshReplicaDatabase($config); + $this->targetConnection->useRole($currentRole); + + $databaseRole = $this->getSourceRole( + $this->targetConnection, + 'DATABASE', + QueryBuilder::quoteIdentifier($this->targetDatabase), + ); + $this->targetConnection->grantRoleToMigrateUser($databaseRole); + $this->targetConnection->useRole($databaseRole); + + $hasDynamicBackend = in_array( + 'workspace-snowflake-dynamic-backend-size', + $this->targetSapiClient->verifyToken()['owner']['features'], + ); + + if ($hasDynamicBackend) { + $this->targetConnection->query(sprintf( + 'USE WAREHOUSE %s', + QueryBuilder::quoteIdentifier($config->getTargetWarehouse() . '_SMALL'), + )); + } + + $this->targetConnection->query(sprintf( + 'USE DATABASE %s;', + QueryBuilder::quoteIdentifier($this->targetDatabase), + )); + $schemas = $this->targetConnection->fetchAll(sprintf( + 'SHOW SCHEMAS IN DATABASE %s;', + QueryBuilder::quoteIdentifier($this->targetDatabase), + )); + + foreach ($schemas as $schema) { + if (in_array($schema['name'], self::SKIP_CLONE_SCHEMAS, true)) { + continue; + } + $this->migrateSchema($config->getMigrateTables(), $schema['name']); + } + $this->dropReplicaDatabase(); + } + + private function migrateSchema(array $tablesWhiteList, string $schemaName): void + { + $this->logger->info(sprintf('Migrating schema %s', $schemaName)); + $tables = $this->targetConnection->fetchAll(sprintf( + 'SHOW TABLES IN SCHEMA %s;', + QueryBuilder::quoteIdentifier($schemaName), + )); + + foreach ($tables as $table) { + $tableId = sprintf('%s.%s', $schemaName, $table['name']); + if ($tablesWhiteList && !in_array($tableId, $tablesWhiteList, true)) { + continue; + } + $this->migrateTable($schemaName, $table['name']); + } + } + + private function migrateTable(string $schemaName, string $tableName): void + { + $this->logger->info(sprintf('Migrating table %s.%s', $schemaName, $tableName)); + $tableRole = $this->getSourceRole( + $this->targetConnection, + 'TABLE', + QueryBuilder::quoteIdentifier($schemaName) . '.' . QueryBuilder::quoteIdentifier($tableName), + ); + + try { + $this->targetConnection->useRole($tableRole); + } catch (Throwable) { + $this->targetConnection->grantRoleToMigrateUser($tableRole); + $this->targetConnection->useRole($tableRole); + } + + $this->targetConnection->grantPrivilegesToReplicaDatabase( + $this->replicaDatabase, + $tableRole, + ); + + $columns = $this->targetConnection->getTableColumns($schemaName, $tableName); + + $compareTimestamp = $this->compareTableMaxTimestamp( + 'ACCOUNTADMIN', + $tableRole, + $this->replicaDatabase, + $this->targetDatabase, + $schemaName, + $tableName, + ); + + if ($compareTimestamp) { + $this->logger->info(sprintf('Table %s.%s is up to date', $schemaName, $tableName)); + return; + } + + try { + $this->targetConnection->query(sprintf( + 'TRUNCATE TABLE %s.%s.%s;', + QueryBuilder::quoteIdentifier($this->targetDatabase), + QueryBuilder::quoteIdentifier($schemaName), + QueryBuilder::quoteIdentifier($tableName), + )); + + $this->targetConnection->query(sprintf( + 'INSERT INTO %s.%s.%s (%s) SELECT %s FROM %s.%s.%s;', + QueryBuilder::quoteIdentifier($this->targetDatabase), + QueryBuilder::quoteIdentifier($schemaName), + QueryBuilder::quoteIdentifier($tableName), + implode(', ', array_map(fn($v) => QueryBuilder::quoteIdentifier($v), $columns)), + implode(', ', array_map(fn($v) => QueryBuilder::quoteIdentifier($v), $columns)), + QueryBuilder::quoteIdentifier($this->replicaDatabase), + QueryBuilder::quoteIdentifier($schemaName), + QueryBuilder::quoteIdentifier($tableName), + )); + } catch (RuntimeException $e) { + $this->logger->warning(sprintf( + 'Error while migrating table %s.%s: %s', + $schemaName, + $tableName, + $e->getMessage(), + )); + return; + } + + $this->logger->info(sprintf('Refreshing table %s.%s metadata', $schemaName, $tableName)); + $columns = array_filter($columns, fn($v) => $v !== '_timestamp'); + $csv = $this->createDataFile($columns); + $tableId = sprintf('%s.%s', $schemaName, $tableName); + if (!$this->targetSapiClient->tableExists($tableId)) { + $this->logger->warning(sprintf('Table %s does not exist in Storage API', $tableId)); + } + $this->targetSapiClient->writeTableAsync($tableId, $csv, ['incremental' => true]); + } + + private function getSourceRole(Connection $connection, string $showGrantsOn, string $targetSourceName): string + { + $grantsOnDatabase = $connection->fetchAll(sprintf( + 'SHOW GRANTS ON %s %s;', + $showGrantsOn, + $targetSourceName, + )); + + $ownershipOnDatabase = array_filter($grantsOnDatabase, fn($v) => $v['privilege'] === 'OWNERSHIP'); + assert(count($ownershipOnDatabase) === 1); + + return current($ownershipOnDatabase)['grantee_name']; + } + + private function createDataFile(array $columns): CsvFile + { + $csv = new CsvFile('/tmp/tempDataFile.csv'); + $csv->writeRow($columns); + return $csv; + } + + private function createReplicaDatabase(Config $config): void + { + // Migration database sqls + $this->logger->info(sprintf('Creating replica database %s', $this->replicaDatabase)); + $this->targetConnection->query(sprintf( + 'CREATE DATABASE IF NOT EXISTS %s AS REPLICA OF %s.%s.%s;', + QueryBuilder::quoteIdentifier($this->replicaDatabase), + $config->getSourceDatabaseRegion(), + $config->getSourceDatabaseAccount(), + QueryBuilder::quoteIdentifier($this->sourceDatabase), + )); + + $this->logger->info(sprintf('Replica database %s created', $this->replicaDatabase)); + } + + private function refreshReplicaDatabase(Config $config): void + { + $this->targetConnection->query(sprintf( + 'USE DATABASE %s', + QueryBuilder::quoteIdentifier($this->replicaDatabase), + )); + $this->targetConnection->query('USE SCHEMA PUBLIC'); + + $this->targetConnection->query(sprintf( + 'USE WAREHOUSE %s', + QueryBuilder::quoteIdentifier($config->getTargetWarehouse()), + )); + + // Run replicate of data + $this->logger->info(sprintf('Refreshing replica database %s', $this->replicaDatabase)); + $this->targetConnection->query(sprintf( + 'ALTER DATABASE %s REFRESH', + QueryBuilder::quoteIdentifier($this->replicaDatabase), + )); + } + + private function dropReplicaDatabase(): void + { + $this->targetConnection->useRole('ACCOUNTADMIN'); + $this->targetConnection->query(sprintf( + 'DROP DATABASE %s;', + QueryBuilder::quoteIdentifier($this->replicaDatabase), + )); + } + + private function compareTableMaxTimestamp( + string $firstDatabaseRole, + string $secondDatabaseRole, + string $firstDatabase, + string $secondDatabase, + string $schema, + string $table, + ): bool { + $sqlTemplate = 'SELECT max("_timestamp") as "maxTimestamp" FROM %s.%s.%s'; + + $currentRole = $this->targetConnection->getCurrentRole(); + try { + $this->targetConnection->useRole($firstDatabaseRole); + + $lastUpdateInFirstDatabase = $this->targetConnection->fetchAll(sprintf( + $sqlTemplate, + QueryBuilder::quoteIdentifier($firstDatabase), + QueryBuilder::quoteIdentifier($schema), + QueryBuilder::quoteIdentifier($table), + )); + + $this->targetConnection->useRole($secondDatabaseRole); + $lastUpdateInSecondDatabase = $this->targetConnection->fetchAll(sprintf( + $sqlTemplate, + QueryBuilder::quoteIdentifier($secondDatabase), + QueryBuilder::quoteIdentifier($schema), + QueryBuilder::quoteIdentifier($table), + )); + } catch (RuntimeException $e) { + return false; + } finally { + $this->targetConnection->useRole($currentRole); + } + + return $lastUpdateInFirstDatabase[0]['maxTimestamp'] === $lastUpdateInSecondDatabase[0]['maxTimestamp']; + } +} diff --git a/src/Strategy/DatabaseReplication.php b/src/Strategy/DatabaseReplication.php new file mode 100644 index 0000000..fe3bc5c --- /dev/null +++ b/src/Strategy/DatabaseReplication.php @@ -0,0 +1,48 @@ + $v['name'], $this->sourceConnection->fetchAll('SHOW DATABASES;')); + for ($i = $fromProjectId; $i <= $toProjectId; $i++) { + $sourceDatabase = sprintf('%s_%s', $config->getSourceDatabasePrefix(), $i); + if (!in_array($sourceDatabase, $databases, true)) { + continue; + } + $this->createReplication($sourceDatabase); + } + } + + public function createReplication(string $sourceDatabase): void + { + // Allow replication on source database + $this->logger->info(sprintf('Enabling replication on database %s', $sourceDatabase)); + + $this->sourceConnection->query(sprintf( + 'ALTER DATABASE %s ENABLE REPLICATION TO ACCOUNTS %s.%s;', + QueryBuilder::quoteIdentifier($sourceDatabase), + $this->targetConnection->getRegion(), + $this->targetConnection->getAccount(), + )); + } +} diff --git a/src/Application.php b/src/Strategy/SapiMigrate.php similarity index 76% rename from src/Application.php rename to src/Strategy/SapiMigrate.php index 3c57d3c..f010637 100644 --- a/src/Application.php +++ b/src/Strategy/SapiMigrate.php @@ -2,39 +2,35 @@ declare(strict_types=1); -namespace AppProjectMigrateLargeTables; +namespace Keboola\AppProjectMigrateLargeTables\Strategy; +use Keboola\AppProjectMigrateLargeTables\Config; +use Keboola\AppProjectMigrateLargeTables\MigrateInterface; use Keboola\StorageApi\Client; use Keboola\StorageApi\ClientException; use Keboola\StorageApi\Options\FileUploadOptions; use Keboola\Temp\Temp; use Psr\Log\LoggerInterface; -class Application +class SapiMigrate implements MigrateInterface { - private Client $sourceClient; - - private Client $destinationClient; - - private LoggerInterface $logger; - - public function __construct(Client $sourceClient, Client $destinationClient, LoggerInterface $logger) - { - $this->sourceClient = $sourceClient; - $this->destinationClient = $destinationClient; - $this->logger = $logger; + public function __construct( + private readonly Client $sourceClient, + private readonly Client $targetClient, + private readonly LoggerInterface $logger, + ) { } - public function run(array $tables = []): void + public function migrate(Config $config): void { - foreach ($tables ?: $this->getAllTables() as $tableId) { + foreach ($config->getMigrateTables() ?: $this->getAllTables() as $tableId) { try { $tableInfo = $this->sourceClient->getTable($tableId); } catch (ClientException $e) { $this->logger->warning(sprintf( 'Skipping migration Table ID "%s". Reason: "%s".', $tableId, - $e->getMessage() + $e->getMessage(), )); continue; } @@ -75,7 +71,7 @@ private function migrateTable(array $sourceTableInfo): void $slices = $this->sourceClient->downloadSlicedFile($sourceFileId, $tmp->getTmpFolder()); $this->logger->info(sprintf('Uploading table %s', $sourceTableInfo['id'])); - $destinationFileId = $this->destinationClient->uploadSlicedFile($slices, $optionUploadedFile); + $destinationFileId = $this->targetClient->uploadSlicedFile($slices, $optionUploadedFile); } else { $fileName = $tmp->getTmpFolder() . '/' . $sourceFileInfo['name']; @@ -83,26 +79,26 @@ private function migrateTable(array $sourceTableInfo): void $this->sourceClient->downloadFile($sourceFileId, $fileName); $this->logger->info(sprintf('Uploading table %s', $sourceTableInfo['id'])); - $destinationFileId = $this->destinationClient->uploadFile($fileName, $optionUploadedFile); + $destinationFileId = $this->targetClient->uploadFile($fileName, $optionUploadedFile); } // Upload data to table - $this->destinationClient->writeTableAsyncDirect( + $this->targetClient->writeTableAsyncDirect( $sourceTableInfo['id'], [ 'name' => $sourceTableInfo['name'], 'dataFileId' => $destinationFileId, 'columns' => $sourceTableInfo['columns'], - ] + ], ); } private function getAllTables(): array { - $buckets = $this->destinationClient->listBuckets(); + $buckets = $this->targetClient->listBuckets(); $listTables = []; foreach ($buckets as $bucket) { - $bucketTables = $this->destinationClient->listTables($bucket['id']); + $bucketTables = $this->targetClient->listTables($bucket['id']); // migrate only empty tables $filteredBucketTables = array_filter( diff --git a/src/run.php b/src/run.php index bec393b..bdda99d 100644 --- a/src/run.php +++ b/src/run.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use AppProjectMigrateLargeTables\Component; +use Keboola\AppProjectMigrateLargeTables\Component; use Keboola\Component\Logger; use Keboola\Component\UserException; @@ -25,7 +25,7 @@ 'errCode' => $e->getCode(), 'errTrace' => $e->getTraceAsString(), 'errPrevious' => is_object($e->getPrevious()) ? get_class($e->getPrevious()) : '', - ] + ], ); exit(2); } diff --git a/tests/functional/DatadirTest.php b/tests/functional/DatadirTest.php index 2237d10..26c2f0e 100644 --- a/tests/functional/DatadirTest.php +++ b/tests/functional/DatadirTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace AppProjectMigrateLargeTables\FunctionalTests; +namespace Keboola\AppProjectMigrateLargeTables\FunctionalTests; use Keboola\Csv\CsvFile; use Keboola\DatadirTests\DatadirTestCase; @@ -57,7 +57,7 @@ public function testDatadir(DatadirTestSpecificationInterface $specification): v $tablesData = array_combine( array_map(fn($v) => $v['id'], $tables), - array_map(fn($v) => $v['rowsCount'], $tables) + array_map(fn($v) => $v['rowsCount'], $tables), ); if ($tablesData) { @@ -80,7 +80,7 @@ protected function tearDown(): void $this->cleanupProject($this->destinationClient); } - protected function runScript(string $datadirPath): Process + protected function runScript(string $datadirPath, ?string $runId = null): Process { $fs = new Filesystem(); @@ -88,7 +88,7 @@ protected function runScript(string $datadirPath): Process if (!$fs->exists($script)) { throw new DatadirTestsException(sprintf( 'Cannot open script file "%s"', - $script + $script, )); } @@ -97,10 +97,12 @@ protected function runScript(string $datadirPath): Process $script, ]; $runProcess = new Process($runCommand); + $defaultRunId = random_int(1000, 100000) . '.' . random_int(1000, 100000) . '.' . random_int(1000, 100000); $runProcess->setEnv([ 'KBC_DATADIR' => $datadirPath, 'KBC_URL' => (string) getenv('DESTINATION_CLIENT_URL'), 'KBC_TOKEN' => (string) getenv('DESTINATION_CLIENT_TOKEN'), + 'KBC_RUNID' => $runId ?? $defaultRunId, ]); $runProcess->setTimeout(0.0); $runProcess->run();