diff --git a/.github/workflows/github_build_release.yml b/.github/workflows/github_build_release.yml new file mode 100644 index 00000000..e3dd56b7 --- /dev/null +++ b/.github/workflows/github_build_release.yml @@ -0,0 +1,45 @@ +on: + push: + tags: + - '*.*.*' + +name: Create Github Release + +permissions: + contents: write + +jobs: + create-release: + runs-on: ubuntu-latest + env: + COMPOSER_ALLOW_SUPERUSER: 1 + APP_ENV: prod + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Composer install + run: | + docker network create frontend + docker compose run --rm phpfpm composer install --no-dev -o --classmap-authoritative + docker compose run --rm phpfpm composer clear-cache + rm -rf infrastructure + + - name: Make assets dir + run: | + mkdir -p ../assets + + - name: Create archive + run: | + tar \ + -zcf ../assets/${{ github.event.repository.name }}-${{ github.ref_name }}.tar.gz ./* + + - name: Create checksum + run: sha256sum ../assets/${{ github.event.repository.name }}-${{ github.ref_name }}.tar.gz > ../assets/checksum.txt + + - name: Create a release in GitHub and uploads assets + run: | + gh release create ${{ github.ref_name }} --verify-tag --generate-notes ../assets/*.* + env: + GITHUB_TOKEN: ${{ github.TOKEN }} + shell: bash diff --git a/.github/workflows/docker_build_develop.yml b/.github/workflows/itkdev_docker_build_develop.yml similarity index 77% rename from .github/workflows/docker_build_develop.yml rename to .github/workflows/itkdev_docker_build_develop.yml index 612d81b8..6bdd7f3f 100644 --- a/.github/workflows/docker_build_develop.yml +++ b/.github/workflows/itkdev_docker_build_develop.yml @@ -3,13 +3,16 @@ on: push: branches: - 'develop' -name: Build docker image (develop) + +# This Action builds to itkdev/* using ./infrastructure/itkdev/* +name: ITK Dev - Build docker image (develop) jobs: docker: runs-on: ubuntu-latest env: APP_VERSION: develop + COMPOSER_ALLOW_SUPERUSER: 1 steps: - name: Checkout uses: actions/checkout@v3 @@ -30,8 +33,8 @@ jobs: - name: Build and push (API) uses: docker/build-push-action@v4 with: - context: ./infrastructure/display-api-service/ - file: ./infrastructure/display-api-service/Dockerfile + context: ./infrastructure/itkdev/display-api-service/ + file: ./infrastructure/itkdev/display-api-service/Dockerfile build-args: | VERSION=${{ env.APP_VERSION }} push: true @@ -48,8 +51,8 @@ jobs: - name: Build and push (Nginx) uses: docker/build-push-action@v4 with: - context: ./infrastructure/nginx/ - file: ./infrastructure/nginx/Dockerfile + context: ./infrastructure/itkdev/nginx/ + file: ./infrastructure/itkdev/nginx/Dockerfile build-args: | APP_VERSION=${{ env.APP_VERSION }} push: true diff --git a/.github/workflows/docker_build_tag.yml b/.github/workflows/itkdev_docker_build_tag.yml similarity index 78% rename from .github/workflows/docker_build_tag.yml rename to .github/workflows/itkdev_docker_build_tag.yml index cf4f3d13..96dcf9cb 100644 --- a/.github/workflows/docker_build_tag.yml +++ b/.github/workflows/itkdev_docker_build_tag.yml @@ -3,11 +3,15 @@ on: push: tags: - '*' -name: Build docker image (tag) + +# This Action builds to itkdev/* using ./infrastructure/itkdev/* +name: ITK Dev - Build docker image (tag) jobs: docker: runs-on: ubuntu-latest + env: + COMPOSER_ALLOW_SUPERUSER: 1 steps: - name: Checkout uses: actions/checkout@v3 @@ -28,8 +32,8 @@ jobs: - name: Build and push (API) uses: docker/build-push-action@v4 with: - context: ./infrastructure/display-api-service/ - file: ./infrastructure/display-api-service/Dockerfile + context: ./infrastructure/itkdev/display-api-service/ + file: ./infrastructure/itkdev/display-api-service/Dockerfile build-args: | APP_VERSION=${{ github.ref }} push: true @@ -50,8 +54,8 @@ jobs: - name: Build and push (Nginx) uses: docker/build-push-action@v4 with: - context: ./infrastructure/nginx/ - file: ./infrastructure/nginx/Dockerfile + context: ./infrastructure/itkdev/nginx/ + file: ./infrastructure/itkdev/nginx/Dockerfile build-args: | APP_VERSION=${{ steps.get_tag.outputs.git_tag }} push: true diff --git a/.github/workflows/os2display_docker_build_develop.yml b/.github/workflows/os2display_docker_build_develop.yml new file mode 100644 index 00000000..ec238678 --- /dev/null +++ b/.github/workflows/os2display_docker_build_develop.yml @@ -0,0 +1,60 @@ +--- +on: + push: + branches: + - 'develop' + +# This Action builds to os2display/* using ./infrastructure/os2display/* +name: OS2display - Build docker image (develop) + +jobs: + docker: + runs-on: ubuntu-latest + env: + APP_VERSION: develop + COMPOSER_ALLOW_SUPERUSER: 1 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + # Build api + - name: Docker meta (API) + id: meta-api + uses: docker/metadata-action@v4 + with: + images: os2display/display-api-service + + - name: Build and push (API) + uses: docker/build-push-action@v4 + with: + context: ./infrastructure/os2display/display-api-service/ + file: ./infrastructure/os2display/display-api-service/Dockerfile + build-args: | + VERSION=${{ env.APP_VERSION }} + push: true + tags: ${{ steps.meta-api.outputs.tags }} + labels: ${{ steps.meta-api.outputs.labels }} + + # Build nginx (depends on api build) + - name: Docker meta (Nginx) + id: meta-nginx + uses: docker/metadata-action@v4 + with: + images: os2display/display-api-service-nginx + + - name: Build and push (Nginx) + uses: docker/build-push-action@v4 + with: + context: ./infrastructure/os2display/nginx/ + file: ./infrastructure/os2display/nginx/Dockerfile + build-args: | + APP_VERSION=${{ env.APP_VERSION }} + push: true + tags: ${{ steps.meta-nginx.outputs.tags }} + labels: ${{ steps.meta-nginx.outputs.labels }} diff --git a/.github/workflows/os2display_docker_build_tag.yml b/.github/workflows/os2display_docker_build_tag.yml new file mode 100644 index 00000000..22bd2179 --- /dev/null +++ b/.github/workflows/os2display_docker_build_tag.yml @@ -0,0 +1,63 @@ +--- +on: + push: + tags: + - '*' + +# This Action builds to os2display/* using ./infrastructure/os2display/* +name: OS2display - Build docker image (tag) + +jobs: + docker: + runs-on: ubuntu-latest + env: + COMPOSER_ALLOW_SUPERUSER: 1 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + # Build api + - name: Docker meta (API) + id: meta-api + uses: docker/metadata-action@v4 + with: + images: os2display/display-api-service + + - name: Build and push (API) + uses: docker/build-push-action@v4 + with: + context: ./infrastructure/os2display/display-api-service/ + file: ./infrastructure/os2display/display-api-service/Dockerfile + build-args: | + APP_VERSION=${{ github.ref }} + push: true + tags: ${{ steps.meta-api.outputs.tags }} + labels: ${{ steps.meta-api.outputs.labels }} + + # Build nginx (depends on api build) + - name: Docker meta (Nginx) + id: meta-nginx + uses: docker/metadata-action@v4 + with: + images: os2display/display-api-service-nginx + + - name: Get the tag + id: get_tag + run: echo ::set-output name=git_tag::$(echo $GITHUB_REF_NAME) + + - name: Build and push (Nginx) + uses: docker/build-push-action@v4 + with: + context: ./infrastructure/os2display/nginx/ + file: ./infrastructure/os2display/nginx/Dockerfile + build-args: | + APP_VERSION=${{ steps.get_tag.outputs.git_tag }} + push: true + tags: ${{ steps.meta-nginx.outputs.tags }} + labels: ${{ steps.meta-nginx.outputs.labels }} diff --git a/.github/workflows/php_upgrade.yaml b/.github/workflows/php_upgrade.yaml index f6f67055..a4f99ff9 100644 --- a/.github/workflows/php_upgrade.yaml +++ b/.github/workflows/php_upgrade.yaml @@ -1,8 +1,10 @@ on: pull_request -name: Upgrade +name: PHP Upgrade Check jobs: test-composer-install: runs-on: ubuntu-latest + env: + COMPOSER_ALLOW_SUPERUSER: 1 strategy: fail-fast: false matrix: @@ -91,7 +93,7 @@ jobs: runs-on: ubuntu-latest services: mariadb: - image: mariadb:latest + image: mariadb:lts ports: - 3306 env: diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 07028a75..bd907ce2 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -1,8 +1,10 @@ on: pull_request -name: Review +name: Pull Request Review jobs: test-composer-install: runs-on: ubuntu-latest + env: + COMPOSER_ALLOW_SUPERUSER: 1 strategy: fail-fast: false matrix: @@ -141,7 +143,7 @@ jobs: runs-on: ubuntu-latest services: mariadb: - image: mariadb:latest + image: mariadb:lts ports: - 3306 env: diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f46561a..68267dd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,30 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +## [1.3.0] - 2023-07-11 +- [#155](https://github.com/os2display/display-api-service/pull/155) + Set up separate image builds for itkdev and os2display +- [#154](https://github.com/os2display/display-api-service/pull/154) + Updated add user command to ask which tenants user belongs to +- [#151](https://github.com/os2display/display-api-service/pull/151) + Fixed feed data provider id issue +- [#150](https://github.com/os2display/display-api-service/pull/150) + Update docker build to publish to "os2display" org on docker hub. Update github workflow to latest actions. +- [#148](https://github.com/os2display/display-api-service/pull/148) + Updated `EventDatabaseApiFeedType` query ensuring started + but not finished events are found. +- [#157](https://github.com/os2display/display-api-service/pull/157) + Refactored all feed related classes and services +- Minor update of composer packages +- Updated psalm to version 5.x + +## [1.2.9] - 2023-06-30 + +- [#153](https://github.com/os2display/display-api-service/pull/153) + Fixed nginx entry script + ## [1.2.8] - 2023-05-25 + - [#145](https://github.com/os2display/display-api-service/pull/145) Gif mime type possible. diff --git a/composer.json b/composer.json index 71bde661..6211e39d 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,7 @@ "friendsofphp/php-cs-fixer": "^3.0", "hautelook/alice-bundle": "^2.9", "phpunit/phpunit": "^9.5", - "psalm/plugin-symfony": "^3.0", + "psalm/plugin-symfony": "^5.0", "symfony/browser-kit": "5.4.*", "symfony/css-selector": "5.4.*", "symfony/debug-bundle": "5.4.*", @@ -57,8 +57,8 @@ "symfony/stopwatch": "^5.3", "symfony/var-dumper": "^5.3", "symfony/web-profiler-bundle": "^5.3", - "vimeo/psalm": "^4.8", - "weirdan/doctrine-psalm-plugin": "^1.1" + "vimeo/psalm": "^5.12.0", + "weirdan/doctrine-psalm-plugin": "^2.0" }, "replace": { "symfony/polyfill-ctype": "*", diff --git a/composer.lock b/composer.lock index 759cb0ca..d5c8e147 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": "f0656daab479fa3dd7934cffd0f4c4b6", + "content-hash": "23684fbc4cb03f357b0c4019c460745f", "packages": [ { "name": "api-platform/core", @@ -527,16 +527,16 @@ }, { "name": "doctrine/annotations", - "version": "1.14.2", + "version": "1.14.3", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "ad785217c1e9555a7d6c6c8c9f406395a5e2882b" + "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/ad785217c1e9555a7d6c6c8c9f406395a5e2882b", - "reference": "ad785217c1e9555a7d6c6c8c9f406395a5e2882b", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", + "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", "shasum": "" }, "require": { @@ -597,9 +597,9 @@ ], "support": { "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.14.2" + "source": "https://github.com/doctrine/annotations/tree/1.14.3" }, - "time": "2022-12-15T06:48:22+00:00" + "time": "2023-02-01T09:20:38+00:00" }, { "name": "doctrine/cache", @@ -873,16 +873,16 @@ }, { "name": "doctrine/dbal", - "version": "3.5.3", + "version": "3.6.3", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "88fa7e5189fd5ec6682477044264dc0ed4e3aa1e" + "reference": "9a747d29e7e6b39509b8f1847e37a23a0163ea6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/88fa7e5189fd5ec6682477044264dc0ed4e3aa1e", - "reference": "88fa7e5189fd5ec6682477044264dc0ed4e3aa1e", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/9a747d29e7e6b39509b8f1847e37a23a0163ea6a", + "reference": "9a747d29e7e6b39509b8f1847e37a23a0163ea6a", "shasum": "" }, "require": { @@ -895,13 +895,14 @@ "psr/log": "^1|^2|^3" }, "require-dev": { - "doctrine/coding-standard": "11.0.0", + "doctrine/coding-standard": "12.0.0", + "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2022.3", - "phpstan/phpstan": "1.9.4", - "phpstan/phpstan-strict-rules": "^1.4", - "phpunit/phpunit": "9.5.27", + "phpstan/phpstan": "1.10.14", + "phpstan/phpstan-strict-rules": "^1.5", + "phpunit/phpunit": "9.6.7", "psalm/plugin-phpunit": "0.18.4", - "squizlabs/php_codesniffer": "3.7.1", + "squizlabs/php_codesniffer": "3.7.2", "symfony/cache": "^5.4|^6.0", "symfony/console": "^4.4|^5.4|^6.0", "vimeo/psalm": "4.30.0" @@ -964,7 +965,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.5.3" + "source": "https://github.com/doctrine/dbal/tree/3.6.3" }, "funding": [ { @@ -980,29 +981,33 @@ "type": "tidelift" } ], - "time": "2023-01-12T10:21:44+00:00" + "time": "2023-06-01T05:46:46+00:00" }, { "name": "doctrine/deprecations", - "version": "v1.0.0", + "version": "v1.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" + "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", + "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", "shasum": "" }, "require": { - "php": "^7.1|^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5|^8.5|^9.5", - "psr/log": "^1|^2|^3" + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" @@ -1021,27 +1026,27 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + "source": "https://github.com/doctrine/deprecations/tree/v1.1.1" }, - "time": "2022-05-02T15:47:09+00:00" + "time": "2023-06-03T09:27:29+00:00" }, { "name": "doctrine/doctrine-bundle", - "version": "2.8.2", + "version": "2.10.0", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "251cd5aaea32bb92cdad4204840786b317dcdd4c" + "reference": "b2ec6c2668f6dc514e8bf51257d19c7c19398afe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/251cd5aaea32bb92cdad4204840786b317dcdd4c", - "reference": "251cd5aaea32bb92cdad4204840786b317dcdd4c", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/b2ec6c2668f6dc514e8bf51257d19c7c19398afe", + "reference": "b2ec6c2668f6dc514e8bf51257d19c7c19398afe", "shasum": "" }, "require": { "doctrine/cache": "^1.11 || ^2.0", - "doctrine/dbal": "^3.4.0", + "doctrine/dbal": "^3.6.0", "doctrine/persistence": "^2.2 || ^3", "doctrine/sql-formatter": "^1.0.1", "php": "^7.4 || ^8.0", @@ -1050,18 +1055,19 @@ "symfony/console": "^5.4 || ^6.0", "symfony/dependency-injection": "^5.4 || ^6.0", "symfony/deprecation-contracts": "^2.1 || ^3", - "symfony/doctrine-bridge": "^5.4.7 || ^6.0.7", + "symfony/doctrine-bridge": "^5.4.19 || ^6.0.7", "symfony/framework-bundle": "^5.4 || ^6.0", "symfony/service-contracts": "^1.1.1 || ^2.0 || ^3" }, "conflict": { "doctrine/annotations": ">=3.0", "doctrine/orm": "<2.11 || >=3.0", - "twig/twig": "<1.34 || >=2.0,<2.4" + "twig/twig": "<1.34 || >=2.0 <2.4" }, "require-dev": { "doctrine/annotations": "^1 || ^2", "doctrine/coding-standard": "^9.0", + "doctrine/deprecations": "^1.0", "doctrine/orm": "^2.11 || ^3.0", "friendsofphp/proxy-manager-lts": "^1.0", "phpunit/phpunit": "^9.5.26 || ^10.0", @@ -1122,7 +1128,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.8.2" + "source": "https://github.com/doctrine/DoctrineBundle/tree/2.10.0" }, "funding": [ { @@ -1138,20 +1144,20 @@ "type": "tidelift" } ], - "time": "2023-01-06T11:42:10+00:00" + "time": "2023-06-05T14:43:41+00:00" }, { "name": "doctrine/doctrine-migrations-bundle", - "version": "3.2.2", + "version": "3.2.4", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineMigrationsBundle.git", - "reference": "3393f411ba25ade21969c33f2053220044854d01" + "reference": "94e6b0fe1a50901d52f59dbb9b4b0737718b2c1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/3393f411ba25ade21969c33f2053220044854d01", - "reference": "3393f411ba25ade21969c33f2053220044854d01", + "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/94e6b0fe1a50901d52f59dbb9b4b0737718b2c1e", + "reference": "94e6b0fe1a50901d52f59dbb9b4b0737718b2c1e", "shasum": "" }, "require": { @@ -1161,15 +1167,15 @@ "symfony/framework-bundle": "~3.4|~4.0|~5.0|~6.0" }, "require-dev": { - "doctrine/coding-standard": "^8.0", + "doctrine/coding-standard": "^9", "doctrine/orm": "^2.6", "doctrine/persistence": "^1.3||^2.0", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-deprecation-rules": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpstan/phpstan-strict-rules": "^0.12", - "phpunit/phpunit": "^8.0|^9.0", - "vimeo/psalm": "^4.11" + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-deprecation-rules": "^1", + "phpstan/phpstan-phpunit": "^1", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5|^9.5", + "vimeo/psalm": "^4.22" }, "type": "symfony-bundle", "autoload": { @@ -1207,7 +1213,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineMigrationsBundle/issues", - "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.2.2" + "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.2.4" }, "funding": [ { @@ -1223,7 +1229,7 @@ "type": "tidelift" } ], - "time": "2022-02-01T18:08:07+00:00" + "time": "2023-06-02T08:19:26+00:00" }, { "name": "doctrine/event-manager", @@ -1410,30 +1416,30 @@ }, { "name": "doctrine/instantiator", - "version": "1.5.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", + "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": "^9 || ^11", + "doctrine/coding-standard": "^11", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.16 || ^1", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.30 || ^5.4" + "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": { @@ -1460,7 +1466,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.5.0" + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" }, "funding": [ { @@ -1476,7 +1482,7 @@ "type": "tidelift" } ], - "time": "2022-12-30T00:15:36+00:00" + "time": "2022-12-30T00:23:10+00:00" }, { "name": "doctrine/lexer", @@ -1558,16 +1564,16 @@ }, { "name": "doctrine/migrations", - "version": "3.5.5", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/doctrine/migrations.git", - "reference": "4b1e2b6ba71d21d0c5be22ed03b6fc954d20b204" + "reference": "e542ad8bcd606d7a18d0875babb8a6d963c9c059" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/migrations/zipball/4b1e2b6ba71d21d0c5be22ed03b6fc954d20b204", - "reference": "4b1e2b6ba71d21d0c5be22ed03b6fc954d20b204", + "url": "https://api.github.com/repos/doctrine/migrations/zipball/e542ad8bcd606d7a18d0875babb8a6d963c9c059", + "reference": "e542ad8bcd606d7a18d0875babb8a6d963c9c059", "shasum": "" }, "require": { @@ -1575,11 +1581,11 @@ "doctrine/dbal": "^3.5.1", "doctrine/deprecations": "^0.5.3 || ^1", "doctrine/event-manager": "^1.2 || ^2.0", - "friendsofphp/proxy-manager-lts": "^1.0", - "php": "^7.4 || ^8.0", + "php": "^8.1", "psr/log": "^1.1.3 || ^2 || ^3", "symfony/console": "^4.4.16 || ^5.4 || ^6.0", - "symfony/stopwatch": "^4.4 || ^5.4 || ^6.0" + "symfony/stopwatch": "^4.4 || ^5.4 || ^6.0", + "symfony/var-exporter": "^6.2" }, "conflict": { "doctrine/orm": "<2.12" @@ -1595,7 +1601,7 @@ "phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-strict-rules": "^1.1", "phpstan/phpstan-symfony": "^1.1", - "phpunit/phpunit": "^9.5", + "phpunit/phpunit": "^9.5.24", "symfony/cache": "^4.4 || ^5.4 || ^6.0", "symfony/process": "^4.4 || ^5.4 || ^6.0", "symfony/yaml": "^4.4 || ^5.4 || ^6.0" @@ -1640,7 +1646,7 @@ ], "support": { "issues": "https://github.com/doctrine/migrations/issues", - "source": "https://github.com/doctrine/migrations/tree/3.5.5" + "source": "https://github.com/doctrine/migrations/tree/3.6.0" }, "funding": [ { @@ -1656,33 +1662,33 @@ "type": "tidelift" } ], - "time": "2023-01-18T12:44:30+00:00" + "time": "2023-02-15T18:49:46+00:00" }, { "name": "doctrine/orm", - "version": "2.14.1", + "version": "2.15.2", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "de7eee5ed7b1b35c99b118f26f210a8281e6db8e" + "reference": "bf449bef7ddc47e62c22f9a06dacc1736abe1c0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/de7eee5ed7b1b35c99b118f26f210a8281e6db8e", - "reference": "de7eee5ed7b1b35c99b118f26f210a8281e6db8e", + "url": "https://api.github.com/repos/doctrine/orm/zipball/bf449bef7ddc47e62c22f9a06dacc1736abe1c0b", + "reference": "bf449bef7ddc47e62c22f9a06dacc1736abe1c0b", "shasum": "" }, "require": { "composer-runtime-api": "^2", "doctrine/cache": "^1.12.1 || ^2.1.1", - "doctrine/collections": "^1.5 || ^2.0", + "doctrine/collections": "^1.5 || ^2.1", "doctrine/common": "^3.0.3", "doctrine/dbal": "^2.13.1 || ^3.2", "doctrine/deprecations": "^0.5.3 || ^1", "doctrine/event-manager": "^1.2 || ^2", "doctrine/inflector": "^1.4 || ^2.0", - "doctrine/instantiator": "^1.3", - "doctrine/lexer": "^1.2.3 || ^2", + "doctrine/instantiator": "^1.3 || ^2", + "doctrine/lexer": "^2", "doctrine/persistence": "^2.4 || ^3", "ext-ctype": "*", "php": "^7.1 || ^8.0", @@ -1696,16 +1702,16 @@ }, "require-dev": { "doctrine/annotations": "^1.13 || ^2", - "doctrine/coding-standard": "^9.0.2 || ^11.0", + "doctrine/coding-standard": "^9.0.2 || ^12.0", "phpbench/phpbench": "^0.16.10 || ^1.0", - "phpstan/phpstan": "~1.4.10 || 1.9.8", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "phpstan/phpstan": "~1.4.10 || 1.10.14", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6", "psr/log": "^1 || ^2 || ^3", - "squizlabs/php_codesniffer": "3.7.1", + "squizlabs/php_codesniffer": "3.7.2", "symfony/cache": "^4.4 || ^5.4 || ^6.0", "symfony/var-exporter": "^4.4 || ^5.4 || ^6.2", "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0", - "vimeo/psalm": "4.30.0 || 5.4.0" + "vimeo/psalm": "4.30.0 || 5.11.0" }, "suggest": { "ext-dom": "Provides support for XSD validation for XML mapping files", @@ -1755,22 +1761,22 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/2.14.1" + "source": "https://github.com/doctrine/orm/tree/2.15.2" }, - "time": "2023-01-16T18:36:59+00:00" + "time": "2023-06-01T09:35:50+00:00" }, { "name": "doctrine/persistence", - "version": "3.1.3", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "920da294b4bb0bb527f2a91ed60c18213435880f" + "reference": "63fee8c33bef740db6730eb2a750cd3da6495603" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/920da294b4bb0bb527f2a91ed60c18213435880f", - "reference": "920da294b4bb0bb527f2a91ed60c18213435880f", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/63fee8c33bef740db6730eb2a750cd3da6495603", + "reference": "63fee8c33bef740db6730eb2a750cd3da6495603", "shasum": "" }, "require": { @@ -1839,7 +1845,7 @@ ], "support": { "issues": "https://github.com/doctrine/persistence/issues", - "source": "https://github.com/doctrine/persistence/tree/3.1.3" + "source": "https://github.com/doctrine/persistence/tree/3.2.0" }, "funding": [ { @@ -1855,7 +1861,7 @@ "type": "tidelift" } ], - "time": "2023-01-19T13:39:42+00:00" + "time": "2023-05-17T18:32:04+00:00" }, { "name": "doctrine/sql-formatter", @@ -2119,22 +2125,22 @@ }, { "name": "friendsofphp/proxy-manager-lts", - "version": "v1.0.14", + "version": "v1.0.16", "source": { "type": "git", "url": "https://github.com/FriendsOfPHP/proxy-manager-lts.git", - "reference": "a527c9d9d5348e012bd24482d83a5cd643bcbc9e" + "reference": "ecadbdc9052e4ad08c60c8a02268712e50427f7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/proxy-manager-lts/zipball/a527c9d9d5348e012bd24482d83a5cd643bcbc9e", - "reference": "a527c9d9d5348e012bd24482d83a5cd643bcbc9e", + "url": "https://api.github.com/repos/FriendsOfPHP/proxy-manager-lts/zipball/ecadbdc9052e4ad08c60c8a02268712e50427f7c", + "reference": "ecadbdc9052e4ad08c60c8a02268712e50427f7c", "shasum": "" }, "require": { "laminas/laminas-code": "~3.4.1|^4.0", "php": ">=7.1", - "symfony/filesystem": "^4.4.17|^5.0|^6.0" + "symfony/filesystem": "^4.4.17|^5.0|^6.0|^7.0" }, "conflict": { "laminas/laminas-stdlib": "<3.2.1", @@ -2145,7 +2151,7 @@ }, "require-dev": { "ext-phar": "*", - "symfony/phpunit-bridge": "^5.4|^6.0" + "symfony/phpunit-bridge": "^5.4|^6.0|^7.0" }, "type": "library", "extra": { @@ -2185,7 +2191,7 @@ ], "support": { "issues": "https://github.com/FriendsOfPHP/proxy-manager-lts/issues", - "source": "https://github.com/FriendsOfPHP/proxy-manager-lts/tree/v1.0.14" + "source": "https://github.com/FriendsOfPHP/proxy-manager-lts/tree/v1.0.16" }, "funding": [ { @@ -2197,7 +2203,7 @@ "type": "tidelift" } ], - "time": "2023-01-30T10:40:19+00:00" + "time": "2023-05-24T07:17:17+00:00" }, { "name": "gesdinet/jwt-refresh-token-bundle", @@ -2281,22 +2287,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.5.0", + "version": "7.7.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba" + "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b50a2a1251152e43f6a37f0fa053e730a67d25ba", - "reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/fb7566caccf22d74d1ab270de3551f72a58399f5", + "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5", - "guzzlehttp/psr7": "^1.9 || ^2.4", + "guzzlehttp/promises": "^1.5.3 || ^2.0", + "guzzlehttp/psr7": "^1.9.1 || ^2.4.5", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -2307,7 +2313,8 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.1", "ext-curl": "*", - "php-http/client-integration-tests": "^3.0", + "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "php-http/message-factory": "^1.1", "phpunit/phpunit": "^8.5.29 || ^9.5.23", "psr/log": "^1.1 || ^2.0 || ^3.0" }, @@ -2321,9 +2328,6 @@ "bamarni-bin": { "bin-links": true, "forward-command": false - }, - "branch-alias": { - "dev-master": "7.5-dev" } }, "autoload": { @@ -2389,7 +2393,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.5.0" + "source": "https://github.com/guzzle/guzzle/tree/7.7.0" }, "funding": [ { @@ -2405,38 +2409,37 @@ "type": "tidelift" } ], - "time": "2022-08-28T15:39:27+00:00" + "time": "2023-05-21T14:04:53+00:00" }, { "name": "guzzlehttp/promises", - "version": "1.5.2", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "b94b2807d85443f9719887892882d0329d1e2598" + "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598", - "reference": "b94b2807d85443f9719887892882d0329d1e2598", + "url": "https://api.github.com/repos/guzzle/promises/zipball/3a494dc7dc1d7d12e511890177ae2d0e6c107da6", + "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6", "shasum": "" }, "require": { - "php": ">=5.5" + "php": "^7.2.5 || ^8.0" }, "require-dev": { - "symfony/phpunit-bridge": "^4.4 || ^5.1" + "bamarni/composer-bin-plugin": "^1.8.1", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.5-dev" + "bamarni-bin": { + "bin-links": true, + "forward-command": false } }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { "GuzzleHttp\\Promise\\": "src/" } @@ -2473,7 +2476,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.5.2" + "source": "https://github.com/guzzle/promises/tree/2.0.0" }, "funding": [ { @@ -2489,26 +2492,26 @@ "type": "tidelift" } ], - "time": "2022-08-28T14:55:35+00:00" + "time": "2023-05-21T13:50:22+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.4.3", + "version": "2.5.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "67c26b443f348a51926030c83481b85718457d3d" + "reference": "b635f279edd83fc275f822a1188157ffea568ff6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/67c26b443f348a51926030c83481b85718457d3d", - "reference": "67c26b443f348a51926030c83481b85718457d3d", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6", + "reference": "b635f279edd83fc275f822a1188157ffea568ff6", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", + "psr/http-message": "^1.1 || ^2.0", "ralouphie/getallheaders": "^3.0" }, "provide": { @@ -2528,9 +2531,6 @@ "bamarni-bin": { "bin-links": true, "forward-command": false - }, - "branch-alias": { - "dev-master": "2.4-dev" } }, "autoload": { @@ -2592,7 +2592,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.4.3" + "source": "https://github.com/guzzle/psr7/tree/2.5.0" }, "funding": [ { @@ -2608,7 +2608,7 @@ "type": "tidelift" } ], - "time": "2022-10-26T14:07:24+00:00" + "time": "2023-04-17T16:11:26+00:00" }, { "name": "itk-dev/openid-connect", @@ -2734,16 +2734,16 @@ }, { "name": "jms/metadata", - "version": "2.7.0", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/metadata.git", - "reference": "283c714831d272d78ddd6e52e08ac16d76be30fd" + "reference": "7ca240dcac0c655eb15933ee55736ccd2ea0d7a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/283c714831d272d78ddd6e52e08ac16d76be30fd", - "reference": "283c714831d272d78ddd6e52e08ac16d76be30fd", + "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/7ca240dcac0c655eb15933ee55736ccd2ea0d7a6", + "reference": "7ca240dcac0c655eb15933ee55736ccd2ea0d7a6", "shasum": "" }, "require": { @@ -2754,7 +2754,7 @@ "doctrine/coding-standard": "^8.0", "mikey179/vfsstream": "^1.6.7", "phpunit/phpunit": "^8.5|^9.0", - "psr/container": "^1.0", + "psr/container": "^1.0|^2.0", "symfony/cache": "^3.1|^4.0|^5.0", "symfony/dependency-injection": "^3.1|^4.0|^5.0" }, @@ -2792,9 +2792,9 @@ ], "support": { "issues": "https://github.com/schmittjoh/metadata/issues", - "source": "https://github.com/schmittjoh/metadata/tree/2.7.0" + "source": "https://github.com/schmittjoh/metadata/tree/2.8.0" }, - "time": "2022-09-13T19:18:27+00:00" + "time": "2023-02-15T13:44:18+00:00" }, { "name": "justinrainbow/json-schema", @@ -2868,16 +2868,16 @@ }, { "name": "kubawerlos/php-cs-fixer-custom-fixers", - "version": "v3.11.3", + "version": "v3.13.0", "source": { "type": "git", "url": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers.git", - "reference": "3f3cce89eb74662d4c6b63e67cdbc42dce596692" + "reference": "fb53d8bbe2224383a84c71f451d76eb7bc6c8e33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kubawerlos/php-cs-fixer-custom-fixers/zipball/3f3cce89eb74662d4c6b63e67cdbc42dce596692", - "reference": "3f3cce89eb74662d4c6b63e67cdbc42dce596692", + "url": "https://api.github.com/repos/kubawerlos/php-cs-fixer-custom-fixers/zipball/fb53d8bbe2224383a84c71f451d76eb7bc6c8e33", + "reference": "fb53d8bbe2224383a84c71f451d76eb7bc6c8e33", "shasum": "" }, "require": { @@ -2908,35 +2908,35 @@ "description": "A set of custom fixers for PHP CS Fixer", "support": { "issues": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/issues", - "source": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/tree/v3.11.3" + "source": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/tree/v3.13.0" }, - "time": "2022-12-17T09:45:21+00:00" + "time": "2023-02-15T18:51:16+00:00" }, { "name": "laminas/laminas-code", - "version": "4.8.0", + "version": "4.11.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-code.git", - "reference": "dd19fe8e07cc3f374308565667eecd4958c22106" + "reference": "169123b3ede20a9193480c53de2a8194f8c073ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-code/zipball/dd19fe8e07cc3f374308565667eecd4958c22106", - "reference": "dd19fe8e07cc3f374308565667eecd4958c22106", + "url": "https://api.github.com/repos/laminas/laminas-code/zipball/169123b3ede20a9193480c53de2a8194f8c073ec", + "reference": "169123b3ede20a9193480c53de2a8194f8c073ec", "shasum": "" }, "require": { "php": "~8.1.0 || ~8.2.0" }, "require-dev": { - "doctrine/annotations": "^1.13.3", + "doctrine/annotations": "^2.0.0", "ext-phar": "*", "laminas/laminas-coding-standard": "^2.3.0", "laminas/laminas-stdlib": "^3.6.1", - "phpunit/phpunit": "^9.5.26", - "psalm/plugin-phpunit": "^0.18.0", - "vimeo/psalm": "^5.1.0" + "phpunit/phpunit": "^10.0.9", + "psalm/plugin-phpunit": "^0.18.4", + "vimeo/psalm": "^5.7.1" }, "suggest": { "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features", @@ -2973,7 +2973,7 @@ "type": "community_bridge" } ], - "time": "2022-12-08T02:08:23+00:00" + "time": "2023-05-14T12:05:38+00:00" }, { "name": "lcobucci/clock", @@ -3041,39 +3041,40 @@ }, { "name": "lcobucci/jwt", - "version": "4.3.0", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/lcobucci/jwt.git", - "reference": "4d7de2fe0d51a96418c0d04004986e410e87f6b4" + "reference": "47bdb0e0b5d00c2f89ebe33e7e384c77e84e7c34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/4d7de2fe0d51a96418c0d04004986e410e87f6b4", - "reference": "4d7de2fe0d51a96418c0d04004986e410e87f6b4", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/47bdb0e0b5d00c2f89ebe33e7e384c77e84e7c34", + "reference": "47bdb0e0b5d00c2f89ebe33e7e384c77e84e7c34", "shasum": "" }, "require": { "ext-hash": "*", "ext-json": "*", - "ext-mbstring": "*", "ext-openssl": "*", "ext-sodium": "*", - "lcobucci/clock": "^2.0 || ^3.0", - "php": "^7.4 || ^8.0" + "php": "~8.1.0 || ~8.2.0", + "psr/clock": "^1.0" }, "require-dev": { - "infection/infection": "^0.21", - "lcobucci/coding-standard": "^6.0", - "mikey179/vfsstream": "^1.6.7", - "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/php-invoker": "^3.1", - "phpunit/phpunit": "^9.5" + "infection/infection": "^0.26.19", + "lcobucci/clock": "^3.0", + "lcobucci/coding-standard": "^9.0", + "phpbench/phpbench": "^1.2.8", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.10.3", + "phpstan/phpstan-deprecation-rules": "^1.1.2", + "phpstan/phpstan-phpunit": "^1.3.8", + "phpstan/phpstan-strict-rules": "^1.5.0", + "phpunit/phpunit": "^10.0.12" + }, + "suggest": { + "lcobucci/clock": ">= 3.0" }, "type": "library", "autoload": { @@ -3099,7 +3100,7 @@ ], "support": { "issues": "https://github.com/lcobucci/jwt/issues", - "source": "https://github.com/lcobucci/jwt/tree/4.3.0" + "source": "https://github.com/lcobucci/jwt/tree/5.0.0" }, "funding": [ { @@ -3111,20 +3112,20 @@ "type": "patreon" } ], - "time": "2023-01-02T13:28:00+00:00" + "time": "2023-02-25T21:35:16+00:00" }, { "name": "league/oauth2-client", - "version": "2.6.1", + "version": "2.7.0", "source": { "type": "git", "url": "https://github.com/thephpleague/oauth2-client.git", - "reference": "2334c249907190c132364f5dae0287ab8666aa19" + "reference": "160d6274b03562ebeb55ed18399281d8118b76c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/2334c249907190c132364f5dae0287ab8666aa19", - "reference": "2334c249907190c132364f5dae0287ab8666aa19", + "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/160d6274b03562ebeb55ed18399281d8118b76c8", + "reference": "160d6274b03562ebeb55ed18399281d8118b76c8", "shasum": "" }, "require": { @@ -3179,27 +3180,28 @@ ], "support": { "issues": "https://github.com/thephpleague/oauth2-client/issues", - "source": "https://github.com/thephpleague/oauth2-client/tree/2.6.1" + "source": "https://github.com/thephpleague/oauth2-client/tree/2.7.0" }, - "time": "2021-12-22T16:42:49+00:00" + "time": "2023-04-16T18:19:15+00:00" }, { "name": "lexik/jwt-authentication-bundle", - "version": "v2.16.0", + "version": "v2.19.0", "source": { "type": "git", "url": "https://github.com/lexik/LexikJWTAuthenticationBundle.git", - "reference": "0a0922a2442c52724c09deb099b263300cc12d54" + "reference": "1305d7ec0ee540340d9041bd97659a13a0d1e6ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lexik/LexikJWTAuthenticationBundle/zipball/0a0922a2442c52724c09deb099b263300cc12d54", - "reference": "0a0922a2442c52724c09deb099b263300cc12d54", + "url": "https://api.github.com/repos/lexik/LexikJWTAuthenticationBundle/zipball/1305d7ec0ee540340d9041bd97659a13a0d1e6ed", + "reference": "1305d7ec0ee540340d9041bd97659a13a0d1e6ed", "shasum": "" }, "require": { "ext-openssl": "*", - "lcobucci/jwt": "^3.4|^4.0", + "lcobucci/clock": "^1.2|^2.0|^3.0", + "lcobucci/jwt": "^3.4|^4.1|^5.0", "namshi/jose": "^7.2", "php": ">=7.1", "symfony/config": "^4.4|^5.3|^6.0", @@ -3210,17 +3212,15 @@ "symfony/http-kernel": "^4.4|^5.3|^6.0", "symfony/property-access": "^4.4|^5.3|^6.0", "symfony/security-bundle": "^4.4|^5.3|^6.0", - "symfony/security-core": "^4.4|^5.3|^6.0", - "symfony/security-http": "^4.4|^5.3|^6.0", "symfony/translation-contracts": "^1.0|^2.0|^3.0" }, "conflict": { "symfony/console": "<4.4" }, "require-dev": { - "symfony/browser-kit": "^4.4|^5.3|^6.0", + "symfony/browser-kit": "^5.4|^6.0", "symfony/console": "^4.4|^5.3|^6.0", - "symfony/dom-crawler": "^4.4|^5.3|^6.0", + "symfony/dom-crawler": "^5.4|^6.0", "symfony/filesystem": "^4.4|^5.3|^6.0", "symfony/framework-bundle": "^4.4|^5.3|^6.0", "symfony/phpunit-bridge": "^4.4|^5.3|^6.0", @@ -3289,7 +3289,7 @@ ], "support": { "issues": "https://github.com/lexik/LexikJWTAuthenticationBundle/issues", - "source": "https://github.com/lexik/LexikJWTAuthenticationBundle/tree/v2.16.0" + "source": "https://github.com/lexik/LexikJWTAuthenticationBundle/tree/v2.19.0" }, "funding": [ { @@ -3301,20 +3301,20 @@ "type": "tidelift" } ], - "time": "2022-06-12T16:22:12+00:00" + "time": "2023-05-06T15:58:15+00:00" }, { "name": "monolog/monolog", - "version": "2.8.0", + "version": "2.9.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "720488632c590286b88b80e62aa3d3d551ad4a50" + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/720488632c590286b88b80e62aa3d3d551ad4a50", - "reference": "720488632c590286b88b80e62aa3d3d551ad4a50", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1", + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1", "shasum": "" }, "require": { @@ -3329,7 +3329,7 @@ "doctrine/couchdb": "~1.0@dev", "elasticsearch/elasticsearch": "^7 || ^8", "ext-json": "*", - "graylog2/gelf-php": "^1.4.2", + "graylog2/gelf-php": "^1.4.2 || ^2@dev", "guzzlehttp/guzzle": "^7.4", "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", @@ -3391,7 +3391,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.8.0" + "source": "https://github.com/Seldaek/monolog/tree/2.9.1" }, "funding": [ { @@ -3403,7 +3403,7 @@ "type": "tidelift" } ], - "time": "2022-07-24T11:55:47+00:00" + "time": "2023-02-06T13:44:46+00:00" }, { "name": "namshi/jose", @@ -3474,29 +3474,30 @@ }, { "name": "nelmio/cors-bundle", - "version": "2.2.0", + "version": "2.3.1", "source": { "type": "git", "url": "https://github.com/nelmio/NelmioCorsBundle.git", - "reference": "0ee5ee30b0ee08ea122d431ae6e0ddeb87f035c0" + "reference": "185d2c0ae50a3f0b628790170164d5f1c5b7c281" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nelmio/NelmioCorsBundle/zipball/0ee5ee30b0ee08ea122d431ae6e0ddeb87f035c0", - "reference": "0ee5ee30b0ee08ea122d431ae6e0ddeb87f035c0", + "url": "https://api.github.com/repos/nelmio/NelmioCorsBundle/zipball/185d2c0ae50a3f0b628790170164d5f1c5b7c281", + "reference": "185d2c0ae50a3f0b628790170164d5f1c5b7c281", "shasum": "" }, "require": { - "symfony/framework-bundle": "^4.3 || ^5.0 || ^6.0" + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/framework-bundle": "^4.4 || ^5.4 || ^6.0" }, "require-dev": { "mockery/mockery": "^1.2", - "symfony/phpunit-bridge": "^4.3 || ^5.0 || ^6.0" + "symfony/phpunit-bridge": "^4.4 || ^5.4 || ^6.0" }, "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { @@ -3529,9 +3530,9 @@ ], "support": { "issues": "https://github.com/nelmio/NelmioCorsBundle/issues", - "source": "https://github.com/nelmio/NelmioCorsBundle/tree/2.2.0" + "source": "https://github.com/nelmio/NelmioCorsBundle/tree/2.3.1" }, - "time": "2021-12-01T09:34:27+00:00" + "time": "2023-02-16T08:49:29+00:00" }, { "name": "paragonie/random_compat", @@ -3695,24 +3696,27 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.6.2", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d", + "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.0", "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" }, "require-dev": { "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.8", "phpstan/phpstan-phpunit": "^1.1", @@ -3744,9 +3748,56 @@ "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.2" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2" + }, + "time": "2023-05-30T18:13:47+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.22.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "ec58baf7b3c7f1c81b3b00617c953249fb8cf30c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/ec58baf7b3c7f1c81b3b00617c953249fb8cf30c", + "reference": "ec58baf7b3c7f1c81b3b00617c953249fb8cf30c", + "shasum": "" + }, + "require": { + "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.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "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.22.0" }, - "time": "2022-10-14T12:47:21+00:00" + "time": "2023-06-01T12:35:21+00:00" }, { "name": "psr/cache", @@ -3945,21 +3996,21 @@ }, { "name": "psr/http-client", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/http-client.git", - "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621" + "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", - "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", "shasum": "" }, "require": { "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", "extra": { @@ -3979,7 +4030,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP clients", @@ -3991,27 +4042,27 @@ "psr-18" ], "support": { - "source": "https://github.com/php-fig/http-client/tree/master" + "source": "https://github.com/php-fig/http-client/tree/1.0.2" }, - "time": "2020-06-29T06:28:15+00:00" + "time": "2023-04-10T20:12:12+00:00" }, { "name": "psr/http-factory", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + "reference": "e616d01114759c4c489f93b099585439f795fe35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", - "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", + "reference": "e616d01114759c4c489f93b099585439f795fe35", "shasum": "" }, "require": { "php": ">=7.0.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", "extra": { @@ -4031,7 +4082,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interfaces for PSR-7 HTTP message factories", @@ -4046,31 +4097,31 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/master" + "source": "https://github.com/php-fig/http-factory/tree/1.0.2" }, - "time": "2019-04-30T12:38:16+00:00" + "time": "2023-04-10T20:10:41+00:00" }, { "name": "psr/http-message", - "version": "1.0.1", + "version": "2.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -4085,7 +4136,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP messages", @@ -4099,9 +4150,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/master" + "source": "https://github.com/php-fig/http-message/tree/2.0" }, - "time": "2016-08-06T14:39:51+00:00" + "time": "2023-04-04T09:54:51+00:00" }, { "name": "psr/link", @@ -4252,16 +4303,16 @@ }, { "name": "rlanvin/php-rrule", - "version": "v2.4.0", + "version": "v2.4.1", "source": { "type": "git", "url": "https://github.com/rlanvin/php-rrule.git", - "reference": "2acd9950e803ea65514d6440212d39096df9c528" + "reference": "7ddef3d49b7a6461dc070f671f0d94509c9a537b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rlanvin/php-rrule/zipball/2acd9950e803ea65514d6440212d39096df9c528", - "reference": "2acd9950e803ea65514d6440212d39096df9c528", + "url": "https://api.github.com/repos/rlanvin/php-rrule/zipball/7ddef3d49b7a6461dc070f671f0d94509c9a537b", + "reference": "7ddef3d49b7a6461dc070f671f0d94509c9a537b", "shasum": "" }, "require": { @@ -4295,9 +4346,9 @@ ], "support": { "issues": "https://github.com/rlanvin/php-rrule/issues", - "source": "https://github.com/rlanvin/php-rrule/tree/v2.4.0" + "source": "https://github.com/rlanvin/php-rrule/tree/v2.4.1" }, - "time": "2023-01-06T10:19:10+00:00" + "time": "2023-06-07T13:15:59+00:00" }, { "name": "robrichards/xmlseclibs", @@ -4343,16 +4394,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { @@ -4397,7 +4448,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.5" }, "funding": [ { @@ -4405,20 +4456,20 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2023-05-07T05:35:17+00:00" }, { "name": "symfony/asset", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "64738384c91e25ad59a66e42b3b0dc0967ca03e3" + "reference": "1504b6773c6b90118f9871e90a67833b5d1dca3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/64738384c91e25ad59a66e42b3b0dc0967ca03e3", - "reference": "64738384c91e25ad59a66e42b3b0dc0967ca03e3", + "url": "https://api.github.com/repos/symfony/asset/zipball/1504b6773c6b90118f9871e90a67833b5d1dca3c", + "reference": "1504b6773c6b90118f9871e90a67833b5d1dca3c", "shasum": "" }, "require": { @@ -4463,7 +4514,7 @@ "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset/tree/v5.4.19" + "source": "https://github.com/symfony/asset/tree/v5.4.21" }, "funding": [ { @@ -4479,20 +4530,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/cache", - "version": "v5.4.19", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "e9147c89fdfdc5d5ef798bb7193f23726ad609f5" + "reference": "983c79ff28612cdfd66d8e44e1a06e5afc87e107" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/e9147c89fdfdc5d5ef798bb7193f23726ad609f5", - "reference": "e9147c89fdfdc5d5ef798bb7193f23726ad609f5", + "url": "https://api.github.com/repos/symfony/cache/zipball/983c79ff28612cdfd66d8e44e1a06e5afc87e107", + "reference": "983c79ff28612cdfd66d8e44e1a06e5afc87e107", "shasum": "" }, "require": { @@ -4560,7 +4611,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v5.4.19" + "source": "https://github.com/symfony/cache/tree/v5.4.23" }, "funding": [ { @@ -4576,7 +4627,7 @@ "type": "tidelift" } ], - "time": "2023-01-19T09:49:58+00:00" + "time": "2023-04-21T15:38:51+00:00" }, { "name": "symfony/cache-contracts", @@ -4659,16 +4710,16 @@ }, { "name": "symfony/config", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "9bd60843443cda9638efdca7c41eb82ed0026179" + "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/9bd60843443cda9638efdca7c41eb82ed0026179", - "reference": "9bd60843443cda9638efdca7c41eb82ed0026179", + "url": "https://api.github.com/repos/symfony/config/zipball/2a6b1111d038adfa15d52c0871e540f3b352d1e4", + "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4", "shasum": "" }, "require": { @@ -4718,7 +4769,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.19" + "source": "https://github.com/symfony/config/tree/v5.4.21" }, "funding": [ { @@ -4734,20 +4785,20 @@ "type": "tidelift" } ], - "time": "2023-01-08T13:23:55+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/console", - "version": "v5.4.19", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740" + "reference": "560fc3ed7a43e6d30ea94a07d77f9a60b8ed0fb8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/dccb8d251a9017d5994c988b034d3e18aaabf740", - "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740", + "url": "https://api.github.com/repos/symfony/console/zipball/560fc3ed7a43e6d30ea94a07d77f9a60b8ed0fb8", + "reference": "560fc3ed7a43e6d30ea94a07d77f9a60b8ed0fb8", "shasum": "" }, "require": { @@ -4812,12 +4863,12 @@ "homepage": "https://symfony.com", "keywords": [ "cli", - "command line", + "command-line", "console", "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.19" + "source": "https://github.com/symfony/console/tree/v5.4.24" }, "funding": [ { @@ -4833,20 +4884,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-05-26T05:13:16+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.4.20", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "8185ed0df129005a26715902f1a53bad0fe67102" + "reference": "4645e032d0963fb614969398ca28e47605b1a7da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8185ed0df129005a26715902f1a53bad0fe67102", - "reference": "8185ed0df129005a26715902f1a53bad0fe67102", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/4645e032d0963fb614969398ca28e47605b1a7da", + "reference": "4645e032d0963fb614969398ca28e47605b1a7da", "shasum": "" }, "require": { @@ -4906,7 +4957,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.20" + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.24" }, "funding": [ { @@ -4922,20 +4973,20 @@ "type": "tidelift" } ], - "time": "2023-01-27T11:08:11+00:00" + "time": "2023-05-05T14:42:55+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.2.0", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3" + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/1ee04c65529dea5d8744774d474e7cbd2f1206d3", - "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", "shasum": "" }, "require": { @@ -4944,7 +4995,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -4973,7 +5024,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" }, "funding": [ { @@ -4989,20 +5040,20 @@ "type": "tidelift" } ], - "time": "2022-11-25T10:21:52+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/doctrine-bridge", - "version": "v5.4.19", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "359ba96a1e494f1fc08b36d51a74d2fe01d68e68" + "reference": "1eeb02bcad51cb99ab3b73bc83adf80f9b1a75cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/359ba96a1e494f1fc08b36d51a74d2fe01d68e68", - "reference": "359ba96a1e494f1fc08b36d51a74d2fe01d68e68", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/1eeb02bcad51cb99ab3b73bc83adf80f9b1a75cf", + "reference": "1eeb02bcad51cb99ab3b73bc83adf80f9b1a75cf", "shasum": "" }, "require": { @@ -5019,10 +5070,9 @@ "doctrine/dbal": "<2.13.1", "doctrine/lexer": "<1.1", "doctrine/orm": "<2.7.4", - "phpunit/phpunit": "<5.4.3", "symfony/cache": "<5.4", "symfony/dependency-injection": "<4.4", - "symfony/form": "<5.1", + "symfony/form": "<5.4.21|>=6,<6.2.7", "symfony/http-kernel": "<5", "symfony/messenger": "<4.4", "symfony/property-info": "<5", @@ -5043,7 +5093,7 @@ "symfony/dependency-injection": "^4.4|^5.0|^6.0", "symfony/doctrine-messenger": "^5.1|^6.0", "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/form": "^5.4.9|^6.0.9", + "symfony/form": "^5.4.21|^6.2.7", "symfony/http-kernel": "^5.0|^6.0", "symfony/messenger": "^4.4|^5.0|^6.0", "symfony/property-access": "^4.4|^5.0|^6.0", @@ -5090,7 +5140,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v5.4.19" + "source": "https://github.com/symfony/doctrine-bridge/tree/v5.4.24" }, "funding": [ { @@ -5106,20 +5156,20 @@ "type": "tidelift" } ], - "time": "2023-01-06T12:33:31+00:00" + "time": "2023-05-25T13:05:00+00:00" }, { "name": "symfony/dotenv", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "38190ba62566afa26ca723a795d0a004e061bd2a" + "reference": "77b7660bfcb85e8f28287d557d7af0046bcd2ca3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/38190ba62566afa26ca723a795d0a004e061bd2a", - "reference": "38190ba62566afa26ca723a795d0a004e061bd2a", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/77b7660bfcb85e8f28287d557d7af0046bcd2ca3", + "reference": "77b7660bfcb85e8f28287d557d7af0046bcd2ca3", "shasum": "" }, "require": { @@ -5161,7 +5211,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v5.4.19" + "source": "https://github.com/symfony/dotenv/tree/v5.4.22" }, "funding": [ { @@ -5177,20 +5227,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-03-09T20:36:58+00:00" }, { "name": "symfony/error-handler", - "version": "v5.4.19", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "438ef3e5e6481244785da3ce8cf8f4e74e7f2822" + "reference": "c1b9be3b8a6f60f720bec28c4ffb6fb5b00a8946" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/438ef3e5e6481244785da3ce8cf8f4e74e7f2822", - "reference": "438ef3e5e6481244785da3ce8cf8f4e74e7f2822", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/c1b9be3b8a6f60f720bec28c4ffb6fb5b00a8946", + "reference": "c1b9be3b8a6f60f720bec28c4ffb6fb5b00a8946", "shasum": "" }, "require": { @@ -5232,7 +5282,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.4.19" + "source": "https://github.com/symfony/error-handler/tree/v5.4.24" }, "funding": [ { @@ -5248,20 +5298,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-05-02T16:13:31+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "abf49cc084c087d94b4cb939c3f3672971784e0c" + "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/abf49cc084c087d94b4cb939c3f3672971784e0c", - "reference": "abf49cc084c087d94b4cb939c3f3672971784e0c", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1df20e45d56da29a4b1d8259dd6e950acbf1b13f", + "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f", "shasum": "" }, "require": { @@ -5317,7 +5367,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.19" + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.22" }, "funding": [ { @@ -5333,33 +5383,30 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-03-17T11:31:58+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.2.0", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "0782b0b52a737a05b4383d0df35a474303cabdae" + "reference": "a76aed96a42d2b521153fb382d418e30d18b59df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/0782b0b52a737a05b4383d0df35a474303cabdae", - "reference": "0782b0b52a737a05b4383d0df35a474303cabdae", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df", + "reference": "a76aed96a42d2b521153fb382d418e30d18b59df", "shasum": "" }, "require": { "php": ">=8.1", "psr/event-dispatcher": "^1" }, - "suggest": { - "symfony/event-dispatcher-implementation": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -5396,7 +5443,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.2.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.3.0" }, "funding": [ { @@ -5412,20 +5459,20 @@ "type": "tidelift" } ], - "time": "2022-11-25T10:21:52+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/expression-language", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "5db17a4a1c41e2d43d9b84c2eb98a5f63b11c646" + "reference": "501589522b844b8eecf012c133f0404f0eef77ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/5db17a4a1c41e2d43d9b84c2eb98a5f63b11c646", - "reference": "5db17a4a1c41e2d43d9b84c2eb98a5f63b11c646", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/501589522b844b8eecf012c133f0404f0eef77ac", + "reference": "501589522b844b8eecf012c133f0404f0eef77ac", "shasum": "" }, "require": { @@ -5459,7 +5506,7 @@ "description": "Provides an engine that can compile and evaluate expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v5.4.19" + "source": "https://github.com/symfony/expression-language/tree/v5.4.21" }, "funding": [ { @@ -5475,20 +5522,20 @@ "type": "tidelift" } ], - "time": "2023-01-14T19:14:44+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/filesystem", - "version": "v5.4.19", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "648bfaca6a494f3e22378123bcee2894045dc9d8" + "reference": "b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/648bfaca6a494f3e22378123bcee2894045dc9d8", - "reference": "648bfaca6a494f3e22378123bcee2894045dc9d8", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5", + "reference": "b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5", "shasum": "" }, "require": { @@ -5523,7 +5570,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.19" + "source": "https://github.com/symfony/filesystem/tree/v5.4.23" }, "funding": [ { @@ -5539,20 +5586,20 @@ "type": "tidelift" } ], - "time": "2023-01-14T19:14:44+00:00" + "time": "2023-03-02T11:38:35+00:00" }, { "name": "symfony/finder", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "6071aebf810ad13fe8200c224f36103abb37cf1f" + "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/6071aebf810ad13fe8200c224f36103abb37cf1f", - "reference": "6071aebf810ad13fe8200c224f36103abb37cf1f", + "url": "https://api.github.com/repos/symfony/finder/zipball/078e9a5e1871fcfe6a5ce421b539344c21afef19", + "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19", "shasum": "" }, "require": { @@ -5586,7 +5633,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.19" + "source": "https://github.com/symfony/finder/tree/v5.4.21" }, "funding": [ { @@ -5602,20 +5649,20 @@ "type": "tidelift" } ], - "time": "2023-01-14T19:14:44+00:00" + "time": "2023-02-16T09:33:00+00:00" }, { "name": "symfony/flex", - "version": "v1.19.4", + "version": "v1.20.0", "source": { "type": "git", "url": "https://github.com/symfony/flex.git", - "reference": "c82477240111bfe41a1067c9f0ab91d40bafa5b6" + "reference": "49059a10127ac8270957e116a2251ae535d202ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/flex/zipball/c82477240111bfe41a1067c9f0ab91d40bafa5b6", - "reference": "c82477240111bfe41a1067c9f0ab91d40bafa5b6", + "url": "https://api.github.com/repos/symfony/flex/zipball/49059a10127ac8270957e116a2251ae535d202ac", + "reference": "49059a10127ac8270957e116a2251ae535d202ac", "shasum": "" }, "require": { @@ -5651,7 +5698,7 @@ "description": "Composer plugin for Symfony", "support": { "issues": "https://github.com/symfony/flex/issues", - "source": "https://github.com/symfony/flex/tree/v1.19.4" + "source": "https://github.com/symfony/flex/tree/v1.20.0" }, "funding": [ { @@ -5667,20 +5714,20 @@ "type": "tidelift" } ], - "time": "2022-12-20T07:19:24+00:00" + "time": "2023-05-26T16:25:26+00:00" }, { "name": "symfony/framework-bundle", - "version": "v5.4.19", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "a208ee578000f9dedcb50a9784ec7ff8706a7bf1" + "reference": "c06a56a47817d29318aaace1c655cbde16c998e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/a208ee578000f9dedcb50a9784ec7ff8706a7bf1", - "reference": "a208ee578000f9dedcb50a9784ec7ff8706a7bf1", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/c06a56a47817d29318aaace1c655cbde16c998e8", + "reference": "c06a56a47817d29318aaace1c655cbde16c998e8", "shasum": "" }, "require": { @@ -5694,7 +5741,7 @@ "symfony/event-dispatcher": "^5.1|^6.0", "symfony/filesystem": "^4.4|^5.0|^6.0", "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^5.3|^6.0", + "symfony/http-foundation": "^5.4.24|^6.2.11", "symfony/http-kernel": "^5.4|^6.0", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php80": "^1.16", @@ -5707,7 +5754,6 @@ "doctrine/persistence": "<1.3", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "phpunit/phpunit": "<5.4.3", "symfony/asset": "<5.3", "symfony/console": "<5.2.5", "symfony/dom-crawler": "<4.4", @@ -5802,7 +5848,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v5.4.19" + "source": "https://github.com/symfony/framework-bundle/tree/v5.4.24" }, "funding": [ { @@ -5818,20 +5864,20 @@ "type": "tidelift" } ], - "time": "2023-01-10T17:40:25+00:00" + "time": "2023-05-25T13:05:00+00:00" }, { "name": "symfony/http-client", - "version": "v5.4.20", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "b4d936b657c7952a41e89efd0ddcea51f8c90f34" + "reference": "9e89ac4c9dfe29f4ed2b10a36e62720286632ad6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/b4d936b657c7952a41e89efd0ddcea51f8c90f34", - "reference": "b4d936b657c7952a41e89efd0ddcea51f8c90f34", + "url": "https://api.github.com/repos/symfony/http-client/zipball/9e89ac4c9dfe29f4ed2b10a36e62720286632ad6", + "reference": "9e89ac4c9dfe29f4ed2b10a36e62720286632ad6", "shasum": "" }, "require": { @@ -5857,6 +5903,7 @@ "guzzlehttp/promises": "^1.4", "nyholm/psr7": "^1.0", "php-http/httplug": "^1.0|^2.0", + "php-http/message-factory": "^1.0", "psr/http-client": "^1.0", "symfony/dependency-injection": "^4.4|^5.0|^6.0", "symfony/http-kernel": "^4.4.13|^5.1.5|^6.0", @@ -5888,8 +5935,11 @@ ], "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", "homepage": "https://symfony.com", + "keywords": [ + "http" + ], "support": { - "source": "https://github.com/symfony/http-client/tree/v5.4.20" + "source": "https://github.com/symfony/http-client/tree/v5.4.24" }, "funding": [ { @@ -5905,7 +5955,7 @@ "type": "tidelift" } ], - "time": "2023-01-25T18:32:18+00:00" + "time": "2023-05-07T13:11:28+00:00" }, { "name": "symfony/http-client-contracts", @@ -5987,16 +6037,16 @@ }, { "name": "symfony/http-foundation", - "version": "v5.4.20", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "d0435363362a47c14e9cf50663cb8ffbf491875a" + "reference": "3c59f97f6249ce552a44f01b93bfcbd786a954f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d0435363362a47c14e9cf50663cb8ffbf491875a", - "reference": "d0435363362a47c14e9cf50663cb8ffbf491875a", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/3c59f97f6249ce552a44f01b93bfcbd786a954f5", + "reference": "3c59f97f6249ce552a44f01b93bfcbd786a954f5", "shasum": "" }, "require": { @@ -6043,7 +6093,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.20" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.24" }, "funding": [ { @@ -6059,20 +6109,20 @@ "type": "tidelift" } ], - "time": "2023-01-29T11:11:52+00:00" + "time": "2023-05-19T07:21:23+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.4.20", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "aaeec341582d3c160cc9ecfa8b2419ba6c69954e" + "reference": "f38b722e1557eb3f487d351b48f5a1279b50e9d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aaeec341582d3c160cc9ecfa8b2419ba6c69954e", - "reference": "aaeec341582d3c160cc9ecfa8b2419ba6c69954e", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f38b722e1557eb3f487d351b48f5a1279b50e9d1", + "reference": "f38b722e1557eb3f487d351b48f5a1279b50e9d1", "shasum": "" }, "require": { @@ -6081,7 +6131,7 @@ "symfony/deprecation-contracts": "^2.1|^3", "symfony/error-handler": "^4.4|^5.0|^6.0", "symfony/event-dispatcher": "^5.0|^6.0", - "symfony/http-foundation": "^5.3.7|^6.0", + "symfony/http-foundation": "^5.4.21|^6.2.7", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-php73": "^1.9", "symfony/polyfill-php80": "^1.16" @@ -6155,7 +6205,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.4.20" + "source": "https://github.com/symfony/http-kernel/tree/v5.4.24" }, "funding": [ { @@ -6171,20 +6221,20 @@ "type": "tidelift" } ], - "time": "2023-02-01T08:18:48+00:00" + "time": "2023-05-27T08:06:30+00:00" }, { "name": "symfony/mime", - "version": "v5.4.19", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "a858429a9c704edc53fe057228cf9ca282ba48eb" + "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/a858429a9c704edc53fe057228cf9ca282ba48eb", - "reference": "a858429a9c704edc53fe057228cf9ca282ba48eb", + "url": "https://api.github.com/repos/symfony/mime/zipball/ae0a1032a450a3abf305ee44fc55ed423fbf16e3", + "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3", "shasum": "" }, "require": { @@ -6239,7 +6289,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.4.19" + "source": "https://github.com/symfony/mime/tree/v5.4.23" }, "funding": [ { @@ -6255,20 +6305,20 @@ "type": "tidelift" } ], - "time": "2023-01-09T05:43:46+00:00" + "time": "2023-04-19T09:49:13+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "6b2732feb1335d588a902ca744cae9812cc0e7d3" + "reference": "34be6f0695e4187dbb832a05905fb4c6581ac39a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/6b2732feb1335d588a902ca744cae9812cc0e7d3", - "reference": "6b2732feb1335d588a902ca744cae9812cc0e7d3", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/34be6f0695e4187dbb832a05905fb4c6581ac39a", + "reference": "34be6f0695e4187dbb832a05905fb4c6581ac39a", "shasum": "" }, "require": { @@ -6323,7 +6373,7 @@ "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v5.4.19" + "source": "https://github.com/symfony/monolog-bridge/tree/v5.4.22" }, "funding": [ { @@ -6339,7 +6389,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-03-06T21:29:33+00:00" }, { "name": "symfony/monolog-bundle", @@ -6424,16 +6474,16 @@ }, { "name": "symfony/options-resolver", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "b03c99236445492f20c61666e8f7e5d388b078e5" + "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b03c99236445492f20c61666e8f7e5d388b078e5", - "reference": "b03c99236445492f20c61666e8f7e5d388b078e5", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", + "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", "shasum": "" }, "require": { @@ -6473,7 +6523,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.4.19" + "source": "https://github.com/symfony/options-resolver/tree/v5.4.21" }, "funding": [ { @@ -6489,20 +6539,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/password-hasher", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "51b4b4d9e368fa6e31daa24866499781848c77d3" + "reference": "7ce4529b2b2ea7de3b6f344a1a41f58201999180" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/51b4b4d9e368fa6e31daa24866499781848c77d3", - "reference": "51b4b4d9e368fa6e31daa24866499781848c77d3", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/7ce4529b2b2ea7de3b6f344a1a41f58201999180", + "reference": "7ce4529b2b2ea7de3b6f344a1a41f58201999180", "shasum": "" }, "require": { @@ -6546,7 +6596,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v5.4.19" + "source": "https://github.com/symfony/password-hasher/tree/v5.4.21" }, "funding": [ { @@ -6562,7 +6612,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -7292,16 +7342,16 @@ }, { "name": "symfony/process", - "version": "v5.4.19", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1" + "reference": "e3c46cc5689c8782944274bb30702106ecbe3b64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/c5ba874c9b636dbccf761e22ce750e88ec3f55e1", - "reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1", + "url": "https://api.github.com/repos/symfony/process/zipball/e3c46cc5689c8782944274bb30702106ecbe3b64", + "reference": "e3c46cc5689c8782944274bb30702106ecbe3b64", "shasum": "" }, "require": { @@ -7334,7 +7384,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.19" + "source": "https://github.com/symfony/process/tree/v5.4.24" }, "funding": [ { @@ -7350,20 +7400,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-05-17T11:26:05+00:00" }, { "name": "symfony/property-access", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "20fcf370aed6b2b4a2d8170fa23d2d07250e94ab" + "reference": "ffee082889586b5718347b291e04071f4d07b38f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/20fcf370aed6b2b4a2d8170fa23d2d07250e94ab", - "reference": "20fcf370aed6b2b4a2d8170fa23d2d07250e94ab", + "url": "https://api.github.com/repos/symfony/property-access/zipball/ffee082889586b5718347b291e04071f4d07b38f", + "reference": "ffee082889586b5718347b291e04071f4d07b38f", "shasum": "" }, "require": { @@ -7411,11 +7461,11 @@ "injection", "object", "property", - "property path", + "property-path", "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v5.4.19" + "source": "https://github.com/symfony/property-access/tree/v5.4.22" }, "funding": [ { @@ -7431,20 +7481,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-03-14T14:59:20+00:00" }, { "name": "symfony/property-info", - "version": "v5.4.19", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "8ccf54bce2e2edbface1e99cb5a2560a290c9e2d" + "reference": "d43b85b00699b4484964c297575b5c6f9dc5f6e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/8ccf54bce2e2edbface1e99cb5a2560a290c9e2d", - "reference": "8ccf54bce2e2edbface1e99cb5a2560a290c9e2d", + "url": "https://api.github.com/repos/symfony/property-info/zipball/d43b85b00699b4484964c297575b5c6f9dc5f6e1", + "reference": "d43b85b00699b4484964c297575b5c6f9dc5f6e1", "shasum": "" }, "require": { @@ -7506,7 +7556,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v5.4.19" + "source": "https://github.com/symfony/property-info/tree/v5.4.24" }, "funding": [ { @@ -7522,20 +7572,20 @@ "type": "tidelift" } ], - "time": "2023-01-14T11:26:56+00:00" + "time": "2023-05-15T20:11:03+00:00" }, { "name": "symfony/proxy-manager-bridge", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/proxy-manager-bridge.git", - "reference": "02dea4937f05236483ebc3ff97b91bb414111344" + "reference": "a4cf96f3acfa252503a216bea877478f9621c7c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/proxy-manager-bridge/zipball/02dea4937f05236483ebc3ff97b91bb414111344", - "reference": "02dea4937f05236483ebc3ff97b91bb414111344", + "url": "https://api.github.com/repos/symfony/proxy-manager-bridge/zipball/a4cf96f3acfa252503a216bea877478f9621c7c0", + "reference": "a4cf96f3acfa252503a216bea877478f9621c7c0", "shasum": "" }, "require": { @@ -7573,7 +7623,7 @@ "description": "Provides integration for ProxyManager with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/proxy-manager-bridge/tree/v5.4.19" + "source": "https://github.com/symfony/proxy-manager-bridge/tree/v5.4.21" }, "funding": [ { @@ -7589,20 +7639,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-16T09:33:00+00:00" }, { "name": "symfony/routing", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "df1b28f37c8e78912213c58ef6ab2f2037bbfdc5" + "reference": "c2ac11eb34947999b7c38fb4c835a57306907e6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/df1b28f37c8e78912213c58ef6ab2f2037bbfdc5", - "reference": "df1b28f37c8e78912213c58ef6ab2f2037bbfdc5", + "url": "https://api.github.com/repos/symfony/routing/zipball/c2ac11eb34947999b7c38fb4c835a57306907e6d", + "reference": "c2ac11eb34947999b7c38fb4c835a57306907e6d", "shasum": "" }, "require": { @@ -7663,7 +7713,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.4.19" + "source": "https://github.com/symfony/routing/tree/v5.4.22" }, "funding": [ { @@ -7679,20 +7729,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-03-14T14:59:20+00:00" }, { "name": "symfony/runtime", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/runtime.git", - "reference": "a33478ef6d8e6ea642449001949aafd330ca0486" + "reference": "4a78e519d40a3845437e29dc514959631badfed4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/runtime/zipball/a33478ef6d8e6ea642449001949aafd330ca0486", - "reference": "a33478ef6d8e6ea642449001949aafd330ca0486", + "url": "https://api.github.com/repos/symfony/runtime/zipball/4a78e519d40a3845437e29dc514959631badfed4", + "reference": "4a78e519d40a3845437e29dc514959631badfed4", "shasum": "" }, "require": { @@ -7739,8 +7789,11 @@ ], "description": "Enables decoupling PHP applications from global state", "homepage": "https://symfony.com", + "keywords": [ + "runtime" + ], "support": { - "source": "https://github.com/symfony/runtime/tree/v5.4.19" + "source": "https://github.com/symfony/runtime/tree/v5.4.22" }, "funding": [ { @@ -7756,20 +7809,20 @@ "type": "tidelift" } ], - "time": "2023-01-20T16:47:48+00:00" + "time": "2023-03-14T15:48:23+00:00" }, { "name": "symfony/security-bundle", - "version": "v5.4.20", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "1a049b77e70e890c5d5d2105d96ce8b35890197e" + "reference": "36eddff8266126de032ab528417ad13eb43f6cb5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/1a049b77e70e890c5d5d2105d96ce8b35890197e", - "reference": "1a049b77e70e890c5d5d2105d96ce8b35890197e", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/36eddff8266126de032ab528417ad13eb43f6cb5", + "reference": "36eddff8266126de032ab528417ad13eb43f6cb5", "shasum": "" }, "require": { @@ -7842,7 +7895,7 @@ "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-bundle/tree/v5.4.20" + "source": "https://github.com/symfony/security-bundle/tree/v5.4.22" }, "funding": [ { @@ -7858,20 +7911,20 @@ "type": "tidelift" } ], - "time": "2023-01-30T09:35:58+00:00" + "time": "2023-03-10T10:02:45+00:00" }, { "name": "symfony/security-core", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "76fe5a7c62a3f23a5d7b72a55529e94ae2c1ae07" + "reference": "a801d525c7545332e2ddf7f52c163959354b1650" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/76fe5a7c62a3f23a5d7b72a55529e94ae2c1ae07", - "reference": "76fe5a7c62a3f23a5d7b72a55529e94ae2c1ae07", + "url": "https://api.github.com/repos/symfony/security-core/zipball/a801d525c7545332e2ddf7f52c163959354b1650", + "reference": "a801d525c7545332e2ddf7f52c163959354b1650", "shasum": "" }, "require": { @@ -7935,7 +7988,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v5.4.19" + "source": "https://github.com/symfony/security-core/tree/v5.4.22" }, "funding": [ { @@ -7951,20 +8004,20 @@ "type": "tidelift" } ], - "time": "2023-01-24T10:56:59+00:00" + "time": "2023-03-10T10:02:45+00:00" }, { "name": "symfony/security-csrf", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "892dc11b003c0d3da377264bb3d5f178cb894944" + "reference": "776a538e5f20fb560a182f790979c71455694203" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/892dc11b003c0d3da377264bb3d5f178cb894944", - "reference": "892dc11b003c0d3da377264bb3d5f178cb894944", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/776a538e5f20fb560a182f790979c71455694203", + "reference": "776a538e5f20fb560a182f790979c71455694203", "shasum": "" }, "require": { @@ -8007,7 +8060,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v5.4.19" + "source": "https://github.com/symfony/security-csrf/tree/v5.4.21" }, "funding": [ { @@ -8023,20 +8076,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-16T09:33:00+00:00" }, { "name": "symfony/security-guard", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/security-guard.git", - "reference": "6f9d69b1ef4adaae02ac99af09bbe5de151e824c" + "reference": "62d064b1ee682e4617f4c5ddc0d31f73e1a7ecaa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-guard/zipball/6f9d69b1ef4adaae02ac99af09bbe5de151e824c", - "reference": "6f9d69b1ef4adaae02ac99af09bbe5de151e824c", + "url": "https://api.github.com/repos/symfony/security-guard/zipball/62d064b1ee682e4617f4c5ddc0d31f73e1a7ecaa", + "reference": "62d064b1ee682e4617f4c5ddc0d31f73e1a7ecaa", "shasum": "" }, "require": { @@ -8074,7 +8127,7 @@ "description": "Symfony Security Component - Guard", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-guard/tree/v5.4.19" + "source": "https://github.com/symfony/security-guard/tree/v5.4.22" }, "funding": [ { @@ -8090,20 +8143,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-03-06T21:29:33+00:00" }, { "name": "symfony/security-http", - "version": "v5.4.20", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/security-http.git", - "reference": "0236efe37462df3204e758e3a55661a43285d948" + "reference": "6791856229cc605834d169091981e4eae77dad45" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/0236efe37462df3204e758e3a55661a43285d948", - "reference": "0236efe37462df3204e758e3a55661a43285d948", + "url": "https://api.github.com/repos/symfony/security-http/zipball/6791856229cc605834d169091981e4eae77dad45", + "reference": "6791856229cc605834d169091981e4eae77dad45", "shasum": "" }, "require": { @@ -8159,7 +8212,7 @@ "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-http/tree/v5.4.20" + "source": "https://github.com/symfony/security-http/tree/v5.4.23" }, "funding": [ { @@ -8175,20 +8228,20 @@ "type": "tidelift" } ], - "time": "2023-01-30T09:35:58+00:00" + "time": "2023-04-21T11:34:27+00:00" }, { "name": "symfony/serializer", - "version": "v5.4.19", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "2139fa01c19a764af81191d635b2b9302f4bafd8" + "reference": "12535bb7b1d3b53802bf18d61a98bb1145fabcdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/2139fa01c19a764af81191d635b2b9302f4bafd8", - "reference": "2139fa01c19a764af81191d635b2b9302f4bafd8", + "url": "https://api.github.com/repos/symfony/serializer/zipball/12535bb7b1d3b53802bf18d61a98bb1145fabcdb", + "reference": "12535bb7b1d3b53802bf18d61a98bb1145fabcdb", "shasum": "" }, "require": { @@ -8200,7 +8253,7 @@ "conflict": { "doctrine/annotations": "<1.12", "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0|>=1.7.0", + "phpdocumentor/type-resolver": "<1.4.0", "symfony/dependency-injection": "<4.4", "symfony/property-access": "<5.4", "symfony/property-info": "<5.3.13", @@ -8262,7 +8315,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.19" + "source": "https://github.com/symfony/serializer/tree/v5.4.24" }, "funding": [ { @@ -8278,7 +8331,7 @@ "type": "tidelift" } ], - "time": "2023-01-14T08:18:46+00:00" + "time": "2023-05-12T08:37:35+00:00" }, { "name": "symfony/service-contracts", @@ -8365,16 +8418,16 @@ }, { "name": "symfony/stopwatch", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "bd2b066090fd6a67039371098fa25a84cb2679ec" + "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/bd2b066090fd6a67039371098fa25a84cb2679ec", - "reference": "bd2b066090fd6a67039371098fa25a84cb2679ec", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/f83692cd869a6f2391691d40a01e8acb89e76fee", + "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee", "shasum": "" }, "require": { @@ -8407,7 +8460,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.4.19" + "source": "https://github.com/symfony/stopwatch/tree/v5.4.21" }, "funding": [ { @@ -8423,20 +8476,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/string", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb" + "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/0a01071610fd861cc160dfb7e2682ceec66064cb", - "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb", + "url": "https://api.github.com/repos/symfony/string/zipball/8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", + "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", "shasum": "" }, "require": { @@ -8493,7 +8546,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.19" + "source": "https://github.com/symfony/string/tree/v5.4.22" }, "funding": [ { @@ -8509,7 +8562,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-03-14T06:11:53+00:00" }, { "name": "symfony/translation-contracts", @@ -8591,16 +8644,16 @@ }, { "name": "symfony/twig-bridge", - "version": "v5.4.19", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "0526188cb886be64351454826fecc6d35356eaf1" + "reference": "e5b174464f68be6876046db3ad6e217d9a7dbbac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/0526188cb886be64351454826fecc6d35356eaf1", - "reference": "0526188cb886be64351454826fecc6d35356eaf1", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/e5b174464f68be6876046db3ad6e217d9a7dbbac", + "reference": "e5b174464f68be6876046db3ad6e217d9a7dbbac", "shasum": "" }, "require": { @@ -8613,7 +8666,7 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/console": "<5.3", - "symfony/form": "<5.3", + "symfony/form": "<5.4.21|>=6,<6.2.7", "symfony/http-foundation": "<5.3", "symfony/http-kernel": "<4.4", "symfony/translation": "<5.2", @@ -8628,7 +8681,7 @@ "symfony/dependency-injection": "^4.4|^5.0|^6.0", "symfony/expression-language": "^4.4|^5.0|^6.0", "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/form": "^5.3|^6.0", + "symfony/form": "^5.4.21|^6.2.7", "symfony/http-foundation": "^5.3|^6.0", "symfony/http-kernel": "^4.4|^5.0|^6.0", "symfony/intl": "^4.4|^5.0|^6.0", @@ -8692,7 +8745,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v5.4.19" + "source": "https://github.com/symfony/twig-bridge/tree/v5.4.22" }, "funding": [ { @@ -8708,20 +8761,20 @@ "type": "tidelift" } ], - "time": "2023-01-09T05:43:46+00:00" + "time": "2023-03-31T08:28:44+00:00" }, { "name": "symfony/twig-bundle", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "286bd9e38b9bcb142f1eda0a75b0bbeb49ff34bd" + "reference": "875d0edfc8df7505c1993419882c4071fc28c477" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/286bd9e38b9bcb142f1eda0a75b0bbeb49ff34bd", - "reference": "286bd9e38b9bcb142f1eda0a75b0bbeb49ff34bd", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/875d0edfc8df7505c1993419882c4071fc28c477", + "reference": "875d0edfc8df7505c1993419882c4071fc28c477", "shasum": "" }, "require": { @@ -8781,7 +8834,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v5.4.19" + "source": "https://github.com/symfony/twig-bundle/tree/v5.4.21" }, "funding": [ { @@ -8797,20 +8850,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/uid", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "962c08ab8e0621e966ff1a19d398308b34f24aa2" + "reference": "a30744506976aafc807ccb0d4f95865c0a690d02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/962c08ab8e0621e966ff1a19d398308b34f24aa2", - "reference": "962c08ab8e0621e966ff1a19d398308b34f24aa2", + "url": "https://api.github.com/repos/symfony/uid/zipball/a30744506976aafc807ccb0d4f95865c0a690d02", + "reference": "a30744506976aafc807ccb0d4f95865c0a690d02", "shasum": "" }, "require": { @@ -8855,7 +8908,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v5.4.19" + "source": "https://github.com/symfony/uid/tree/v5.4.21" }, "funding": [ { @@ -8871,20 +8924,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/validator", - "version": "v5.4.19", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "98582557a107e2db3a4e95e6dea0df8016dc246c" + "reference": "47794a3cb530e01593ecad9856ba80f5c011e36b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/98582557a107e2db3a4e95e6dea0df8016dc246c", - "reference": "98582557a107e2db3a4e95e6dea0df8016dc246c", + "url": "https://api.github.com/repos/symfony/validator/zipball/47794a3cb530e01593ecad9856ba80f5c011e36b", + "reference": "47794a3cb530e01593ecad9856ba80f5c011e36b", "shasum": "" }, "require": { @@ -8901,7 +8954,6 @@ "doctrine/annotations": "<1.13", "doctrine/cache": "<1.11", "doctrine/lexer": "<1.1", - "phpunit/phpunit": "<5.4.3", "symfony/dependency-injection": "<4.4", "symfony/expression-language": "<5.1", "symfony/http-kernel": "<4.4", @@ -8968,7 +9020,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v5.4.19" + "source": "https://github.com/symfony/validator/tree/v5.4.24" }, "funding": [ { @@ -8984,20 +9036,20 @@ "type": "tidelift" } ], - "time": "2023-01-15T15:23:36+00:00" + "time": "2023-05-25T13:05:00+00:00" }, { "name": "symfony/var-dumper", - "version": "v5.4.19", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "2944bbc23f5f8da2b962fbcbf7c4a6109b2f4b7b" + "reference": "8e12706bf9c68a2da633f23bfdc15b4dce5970b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2944bbc23f5f8da2b962fbcbf7c4a6109b2f4b7b", - "reference": "2944bbc23f5f8da2b962fbcbf7c4a6109b2f4b7b", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/8e12706bf9c68a2da633f23bfdc15b4dce5970b3", + "reference": "8e12706bf9c68a2da633f23bfdc15b4dce5970b3", "shasum": "" }, "require": { @@ -9006,7 +9058,6 @@ "symfony/polyfill-php80": "^1.16" }, "conflict": { - "phpunit/phpunit": "<5.4.3", "symfony/console": "<4.4" }, "require-dev": { @@ -9057,7 +9108,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.19" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.24" }, "funding": [ { @@ -9073,28 +9124,27 @@ "type": "tidelift" } ], - "time": "2023-01-16T10:52:33+00:00" + "time": "2023-05-25T13:05:00+00:00" }, { "name": "symfony/var-exporter", - "version": "v5.4.19", + "version": "v6.3.0", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "2a1d06fcf2b30829d6c01dae8e6e188424d1f8f6" + "reference": "db5416d04269f2827d8c54331ba4cfa42620d350" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/2a1d06fcf2b30829d6c01dae8e6e188424d1f8f6", - "reference": "2a1d06fcf2b30829d6c01dae8e6e188424d1f8f6", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/db5416d04269f2827d8c54331ba4cfa42620d350", + "reference": "db5416d04269f2827d8c54331ba4cfa42620d350", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1" }, "require-dev": { - "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0" + "symfony/var-dumper": "^5.4|^6.0" }, "type": "library", "autoload": { @@ -9127,10 +9177,12 @@ "export", "hydrate", "instantiate", + "lazy-loading", + "proxy", "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v5.4.19" + "source": "https://github.com/symfony/var-exporter/tree/v6.3.0" }, "funding": [ { @@ -9146,20 +9198,20 @@ "type": "tidelift" } ], - "time": "2023-01-12T16:39:29+00:00" + "time": "2023-04-21T08:48:44+00:00" }, { "name": "symfony/web-link", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/web-link.git", - "reference": "c5b5d4a84249959d0df65c0e804d7f57f6873ecd" + "reference": "57c03a5e89ed7c2d7a1a09258dfec12f95f95adb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-link/zipball/c5b5d4a84249959d0df65c0e804d7f57f6873ecd", - "reference": "c5b5d4a84249959d0df65c0e804d7f57f6873ecd", + "url": "https://api.github.com/repos/symfony/web-link/zipball/57c03a5e89ed7c2d7a1a09258dfec12f95f95adb", + "reference": "57c03a5e89ed7c2d7a1a09258dfec12f95f95adb", "shasum": "" }, "require": { @@ -9217,7 +9269,7 @@ "push" ], "support": { - "source": "https://github.com/symfony/web-link/tree/v5.4.19" + "source": "https://github.com/symfony/web-link/tree/v5.4.21" }, "funding": [ { @@ -9233,20 +9285,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/yaml", - "version": "v5.4.19", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "71c05db20cb9b54d381a28255f17580e2b7e36a5" + "reference": "4cd2e3ea301aadd76a4172756296fe552fb45b0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/71c05db20cb9b54d381a28255f17580e2b7e36a5", - "reference": "71c05db20cb9b54d381a28255f17580e2b7e36a5", + "url": "https://api.github.com/repos/symfony/yaml/zipball/4cd2e3ea301aadd76a4172756296fe552fb45b0b", + "reference": "4cd2e3ea301aadd76a4172756296fe552fb45b0b", "shasum": "" }, "require": { @@ -9292,7 +9344,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.4.19" + "source": "https://github.com/symfony/yaml/tree/v5.4.23" }, "funding": [ { @@ -9308,20 +9360,20 @@ "type": "tidelift" } ], - "time": "2023-01-10T18:51:14+00:00" + "time": "2023-04-23T19:33:36+00:00" }, { "name": "twig/twig", - "version": "v3.5.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "3ffcf4b7d890770466da3b2666f82ac054e7ec72" + "reference": "7e7d5839d4bec168dfeef0ac66d5c5a2edbabffd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/3ffcf4b7d890770466da3b2666f82ac054e7ec72", - "reference": "3ffcf4b7d890770466da3b2666f82ac054e7ec72", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/7e7d5839d4bec168dfeef0ac66d5c5a2edbabffd", + "reference": "7e7d5839d4bec168dfeef0ac66d5c5a2edbabffd", "shasum": "" }, "require": { @@ -9330,15 +9382,10 @@ "symfony/polyfill-mbstring": "^1.3" }, "require-dev": { - "psr/container": "^1.0", + "psr/container": "^1.0|^2.0", "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.5-dev" - } - }, "autoload": { "psr-4": { "Twig\\": "src/" @@ -9372,7 +9419,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.5.0" + "source": "https://github.com/twigphp/Twig/tree/v3.6.1" }, "funding": [ { @@ -9384,20 +9431,20 @@ "type": "tidelift" } ], - "time": "2022-12-27T12:28:18+00:00" + "time": "2023-06-08T12:52:13+00:00" }, { "name": "vich/uploader-bundle", - "version": "1.21.1", + "version": "1.23.1", "source": { "type": "git", "url": "https://github.com/dustin10/VichUploaderBundle.git", - "reference": "6b428642694cbfeb1be6e956ba59382d89ae1ee6" + "reference": "7d20347fc92243ab8e261c0b6196c25b77c579f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dustin10/VichUploaderBundle/zipball/6b428642694cbfeb1be6e956ba59382d89ae1ee6", - "reference": "6b428642694cbfeb1be6e956ba59382d89ae1ee6", + "url": "https://api.github.com/repos/dustin10/VichUploaderBundle/zipball/7d20347fc92243ab8e261c0b6196c25b77c579f8", + "reference": "7d20347fc92243ab8e261c0b6196c25b77c579f8", "shasum": "" }, "require": { @@ -9490,9 +9537,9 @@ ], "support": { "issues": "https://github.com/dustin10/VichUploaderBundle/issues", - "source": "https://github.com/dustin10/VichUploaderBundle/tree/1.21.1" + "source": "https://github.com/dustin10/VichUploaderBundle/tree/1.23.1" }, - "time": "2022-08-12T07:38:44+00:00" + "time": "2023-04-14T09:05:19+00:00" }, { "name": "webmozart/assert", @@ -9815,20 +9862,21 @@ }, { "name": "doctrine/data-fixtures", - "version": "1.6.3", + "version": "1.6.6", "source": { "type": "git", "url": "https://github.com/doctrine/data-fixtures.git", - "reference": "c27821d038e64f1bfc852a94064d65d2a75ad01f" + "reference": "4af35dadbfcf4b00abb2a217c4c8c8800cf5fcf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/c27821d038e64f1bfc852a94064d65d2a75ad01f", - "reference": "c27821d038e64f1bfc852a94064d65d2a75ad01f", + "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/4af35dadbfcf4b00abb2a217c4c8c8800cf5fcf4", + "reference": "4af35dadbfcf4b00abb2a217c4c8c8800cf5fcf4", "shasum": "" }, "require": { - "doctrine/persistence": "^1.3.3|^2.0|^3.0", + "doctrine/deprecations": "^0.5.3 || ^1.0", + "doctrine/persistence": "^1.3.3 || ^2.0 || ^3.0", "php": "^7.2 || ^8.0" }, "conflict": { @@ -9837,16 +9885,15 @@ "doctrine/phpcr-odm": "<1.3.0" }, "require-dev": { - "doctrine/coding-standard": "^10.0", + "doctrine/coding-standard": "^11.0", "doctrine/dbal": "^2.13 || ^3.0", - "doctrine/deprecations": "^1.0", "doctrine/mongodb-odm": "^1.3.0 || ^2.0.0", "doctrine/orm": "^2.12", "ext-sqlite3": "*", "phpstan/phpstan": "^1.5", - "phpunit/phpunit": "^8.5 || ^9.5", + "phpunit/phpunit": "^8.5 || ^9.5 || ^10.0", "symfony/cache": "^5.0 || ^6.0", - "vimeo/psalm": "^4.10" + "vimeo/psalm": "^4.10 || ^5.9" }, "suggest": { "alcaeus/mongo-php-adapter": "For using MongoDB ODM 1.3 with PHP 7 (deprecated)", @@ -9857,7 +9904,7 @@ "type": "library", "autoload": { "psr-4": { - "Doctrine\\Common\\DataFixtures\\": "lib/Doctrine/Common/DataFixtures" + "Doctrine\\Common\\DataFixtures\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -9877,7 +9924,7 @@ ], "support": { "issues": "https://github.com/doctrine/data-fixtures/issues", - "source": "https://github.com/doctrine/data-fixtures/tree/1.6.3" + "source": "https://github.com/doctrine/data-fixtures/tree/1.6.6" }, "funding": [ { @@ -9893,39 +9940,43 @@ "type": "tidelift" } ], - "time": "2023-01-07T15:10:22+00:00" + "time": "2023-04-20T13:08:54+00:00" }, { "name": "ergebnis/composer-normalize", - "version": "2.29.0", + "version": "2.31.0", "source": { "type": "git", "url": "https://github.com/ergebnis/composer-normalize.git", - "reference": "fad0e99b16c625817a5bfd910e4d7e31999c53b2" + "reference": "da1d18bcc2ca02111359c2c76fd938a907ba0a16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ergebnis/composer-normalize/zipball/fad0e99b16c625817a5bfd910e4d7e31999c53b2", - "reference": "fad0e99b16c625817a5bfd910e4d7e31999c53b2", + "url": "https://api.github.com/repos/ergebnis/composer-normalize/zipball/da1d18bcc2ca02111359c2c76fd938a907ba0a16", + "reference": "da1d18bcc2ca02111359c2c76fd938a907ba0a16", "shasum": "" }, "require": { "composer-plugin-api": "^2.0.0", - "ergebnis/json-normalizer": "~2.1.0", + "ergebnis/json": "^1.0.1", + "ergebnis/json-normalizer": "^4.1.0", "ergebnis/json-printer": "^3.3.0", + "ext-json": "*", "justinrainbow/json-schema": "^5.2.12", "localheinz/diff": "^1.1.1", - "php": "^8.0" + "php": "~8.0.0 || ~8.1.0 || ~8.2.0" }, "require-dev": { - "composer/composer": "^2.4.4", + "composer/composer": "^2.5.5", "ergebnis/license": "^2.1.0", - "ergebnis/php-cs-fixer-config": "^5.0.0", - "fakerphp/faker": "^1.20.0", - "phpunit/phpunit": "^9.5.26", - "psalm/plugin-phpunit": "~0.18.3", + "ergebnis/php-cs-fixer-config": "^5.5.2", + "fakerphp/faker": "^1.21.0", + "infection/infection": "~0.26.19", + "phpunit/phpunit": "^9.6.7", + "psalm/plugin-phpunit": "~0.18.4", + "rector/rector": "~0.15.25", "symfony/filesystem": "^6.0.13", - "vimeo/psalm": "^5.0.0" + "vimeo/psalm": "^5.9.0" }, "type": "composer-plugin", "extra": { @@ -9933,7 +9984,8 @@ "composer-normalize": { "indent-size": 2, "indent-style": "space" - } + }, + "plugin-optional": true }, "autoload": { "psr-4": { @@ -9960,40 +10012,112 @@ ], "support": { "issues": "https://github.com/ergebnis/composer-normalize/issues", + "security": "https://github.com/ergebnis/composer-normalize/blob/main/.github/SECURITY.md", "source": "https://github.com/ergebnis/composer-normalize" }, - "time": "2022-12-01T11:51:19+00:00" + "time": "2023-05-02T14:10:33+00:00" + }, + { + "name": "ergebnis/json", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/json.git", + "reference": "d66ea30060856d0729a4aa319a02752519ca63a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/json/zipball/d66ea30060856d0729a4aa319a02752519ca63a0", + "reference": "d66ea30060856d0729a4aa319a02752519ca63a0", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.29.0", + "ergebnis/data-provider": "^1.2.0", + "ergebnis/license": "^2.1.0", + "ergebnis/php-cs-fixer-config": "^5.0.0", + "ergebnis/phpstan-rules": "^1.0.0", + "fakerphp/faker": "^1.20.0", + "infection/infection": "~0.26.16", + "phpunit/phpunit": "^9.5.27", + "psalm/plugin-phpunit": "~0.18.4", + "vimeo/psalm": "^5.1.0" + }, + "type": "library", + "extra": { + "composer-normalize": { + "indent-size": 2, + "indent-style": "space" + } + }, + "autoload": { + "psr-4": { + "Ergebnis\\Json\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com" + } + ], + "description": "Provides a Json value object for representing a valid JSON string.", + "homepage": "https://github.com/ergebnis/json", + "keywords": [ + "json" + ], + "support": { + "issues": "https://github.com/ergebnis/json/issues", + "source": "https://github.com/ergebnis/json" + }, + "time": "2022-12-10T22:38:50+00:00" }, { "name": "ergebnis/json-normalizer", - "version": "2.1.0", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/ergebnis/json-normalizer.git", - "reference": "2039eb11131a243b9204bf51219baa08935e6b1d" + "reference": "e38f8b27f908686b200e3bd68e1b7bdfb5d53061" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ergebnis/json-normalizer/zipball/2039eb11131a243b9204bf51219baa08935e6b1d", - "reference": "2039eb11131a243b9204bf51219baa08935e6b1d", + "url": "https://api.github.com/repos/ergebnis/json-normalizer/zipball/e38f8b27f908686b200e3bd68e1b7bdfb5d53061", + "reference": "e38f8b27f908686b200e3bd68e1b7bdfb5d53061", "shasum": "" }, "require": { - "ergebnis/json-printer": "^3.2.0", - "ergebnis/json-schema-validator": "^2.0.0", + "ergebnis/json": "^1.0.1", + "ergebnis/json-pointer": "^3.2.0", + "ergebnis/json-printer": "^3.3.0", + "ergebnis/json-schema-validator": "^4.0.0", "ext-json": "*", - "justinrainbow/json-schema": "^5.2.11", - "php": "^7.4 || ^8.0" + "justinrainbow/json-schema": "^5.2.12", + "php": "~8.0.0 || ~8.1.0 || ~8.2.0" }, "require-dev": { - "ergebnis/data-provider": "^1.0.0", - "ergebnis/license": "^1.2.0", - "ergebnis/php-cs-fixer-config": "^3.4.0", - "fakerphp/faker": "^1.17.0", - "infection/infection": "~0.25.5", - "phpunit/phpunit": "^9.5.11", - "psalm/plugin-phpunit": "~0.16.1", - "vimeo/psalm": "^4.17.0" + "composer/semver": "^3.2.1", + "ergebnis/data-provider": "^1.3.0", + "ergebnis/license": "^2.1.0", + "ergebnis/php-cs-fixer-config": "^5.5.2", + "fakerphp/faker": "^1.21.0", + "infection/infection": "~0.26.19", + "phpunit/phpunit": "^9.6.7", + "psalm/plugin-phpunit": "~0.18.4", + "rector/rector": "~0.15.25", + "symfony/filesystem": "^6.0.19", + "symfony/finder": "^6.0.19", + "vimeo/psalm": "^5.9.0" + }, + "suggest": { + "composer/semver": "If you want to use ComposerJsonNormalizer or VersionConstraintNormalizer" }, "type": "library", "autoload": { @@ -10021,13 +10145,70 @@ "issues": "https://github.com/ergebnis/json-normalizer/issues", "source": "https://github.com/ergebnis/json-normalizer" }, - "funding": [ + "time": "2023-05-02T11:08:03+00:00" + }, + { + "name": "ergebnis/json-pointer", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/json-pointer.git", + "reference": "861516ff5afa1aa8905fdf3361315909523a1bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/json-pointer/zipball/861516ff5afa1aa8905fdf3361315909523a1bf8", + "reference": "861516ff5afa1aa8905fdf3361315909523a1bf8", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.28.3", + "ergebnis/data-provider": "^1.2.0", + "ergebnis/license": "^2.1.0", + "ergebnis/php-cs-fixer-config": "^5.0.0", + "fakerphp/faker": "^1.20.0", + "infection/infection": "~0.26.16", + "phpunit/phpunit": "^9.5.26", + "psalm/plugin-phpunit": "~0.18.3", + "vimeo/psalm": "^4.30" + }, + "type": "library", + "extra": { + "composer-normalize": { + "indent-size": 2, + "indent-style": "space" + } + }, + "autoload": { + "psr-4": { + "Ergebnis\\Json\\Pointer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "url": "https://github.com/localheinz", - "type": "github" + "name": "Andreas Möller", + "email": "am@localheinz.com" } ], - "time": "2022-01-04T11:19:55+00:00" + "description": "Provides JSON pointer as a value object.", + "homepage": "https://github.com/ergebnis/json-pointer", + "keywords": [ + "RFC6901", + "json", + "pointer" + ], + "support": { + "issues": "https://github.com/ergebnis/json-pointer/issues", + "source": "https://github.com/ergebnis/json-pointer" + }, + "time": "2022-11-28T17:03:31+00:00" }, { "name": "ergebnis/json-printer", @@ -10088,33 +10269,35 @@ }, { "name": "ergebnis/json-schema-validator", - "version": "2.0.0", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/ergebnis/json-schema-validator.git", - "reference": "dacd8a47c1cc2c426ec71e952da3609ebe901fac" + "reference": "a6166272ac5691a9bc791f185841e5f92a6d4723" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ergebnis/json-schema-validator/zipball/dacd8a47c1cc2c426ec71e952da3609ebe901fac", - "reference": "dacd8a47c1cc2c426ec71e952da3609ebe901fac", + "url": "https://api.github.com/repos/ergebnis/json-schema-validator/zipball/a6166272ac5691a9bc791f185841e5f92a6d4723", + "reference": "a6166272ac5691a9bc791f185841e5f92a6d4723", "shasum": "" }, "require": { + "ergebnis/json": "^1.0.0", + "ergebnis/json-pointer": "^3.2.0", "ext-json": "*", - "justinrainbow/json-schema": "^5.2.10", - "php": "^7.4 || ^8.0" + "justinrainbow/json-schema": "^5.2.12", + "php": "^8.0" }, "require-dev": { - "ergebnis/composer-normalize": "^2.18.0", - "ergebnis/data-provider": "^1.0.0", - "ergebnis/license": "^1.1.0", - "ergebnis/php-cs-fixer-config": "~3.4.0", - "fakerphp/faker": "^1.17.0", - "infection/infection": "~0.25.3", - "phpunit/phpunit": "~9.5.10", - "psalm/plugin-phpunit": "~0.16.1", - "vimeo/psalm": "^4.15.0" + "ergebnis/composer-normalize": "^2.21.0", + "ergebnis/data-provider": "^1.2.0", + "ergebnis/license": "^2.1.0", + "ergebnis/php-cs-fixer-config": "~5.0.0", + "fakerphp/faker": "^1.20.0", + "infection/infection": "~0.26.16", + "phpunit/phpunit": "~9.5.27", + "psalm/plugin-phpunit": "~0.18.4", + "vimeo/psalm": "^5.1.0" }, "type": "library", "extra": { @@ -10149,26 +10332,20 @@ "issues": "https://github.com/ergebnis/json-schema-validator/issues", "source": "https://github.com/ergebnis/json-schema-validator" }, - "funding": [ - { - "url": "https://github.com/localheinz", - "type": "github" - } - ], - "time": "2021-12-13T16:54:56+00:00" + "time": "2022-12-10T14:50:15+00:00" }, { "name": "fakerphp/faker", - "version": "v1.21.0", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "92efad6a967f0b79c499705c69b662f738cc9e4d" + "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/92efad6a967f0b79c499705c69b662f738cc9e4d", - "reference": "92efad6a967f0b79c499705c69b662f738cc9e4d", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", + "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", "shasum": "" }, "require": { @@ -10221,9 +10398,9 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v1.21.0" + "source": "https://github.com/FakerPHP/Faker/tree/v1.23.0" }, - "time": "2022-12-13T13:54:32+00:00" + "time": "2023-06-12T08:44:38+00:00" }, { "name": "felixfbecker/advanced-json-rpc", @@ -10326,18 +10503,79 @@ }, "time": "2022-03-02T22:36:06+00:00" }, + { + "name": "fidry/cpu-core-counter", + "version": "0.5.1", + "source": { + "type": "git", + "url": "https://github.com/theofidry/cpu-core-counter.git", + "reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/b58e5a3933e541dc286cc91fc4f3898bbc6f1623", + "reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "fidry/makefile": "^0.2.0", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^1.9.2", + "phpstan/phpstan-deprecation-rules": "^1.0.0", + "phpstan/phpstan-phpunit": "^1.2.2", + "phpstan/phpstan-strict-rules": "^1.4.4", + "phpunit/phpunit": "^9.5.26 || ^8.5.31", + "theofidry/php-cs-fixer-config": "^1.0", + "webmozarts/strict-phpunit": "^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Fidry\\CpuCoreCounter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com" + } + ], + "description": "Tiny utility to get the number of CPU cores.", + "keywords": [ + "CPU", + "core" + ], + "support": { + "issues": "https://github.com/theofidry/cpu-core-counter/issues", + "source": "https://github.com/theofidry/cpu-core-counter/tree/0.5.1" + }, + "funding": [ + { + "url": "https://github.com/theofidry", + "type": "github" + } + ], + "time": "2022-12-24T12:35:10+00:00" + }, { "name": "hautelook/alice-bundle", - "version": "2.11.0", + "version": "2.12.0", "source": { "type": "git", "url": "https://github.com/theofidry/AliceBundle.git", - "reference": "0dd4e9e5391e0c7acc21602f0fadb66210b33726" + "reference": "ebaf24ec0318583d8c022966687e2a4979bb9af8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/AliceBundle/zipball/0dd4e9e5391e0c7acc21602f0fadb66210b33726", - "reference": "0dd4e9e5391e0c7acc21602f0fadb66210b33726", + "url": "https://api.github.com/repos/theofidry/AliceBundle/zipball/ebaf24ec0318583d8c022966687e2a4979bb9af8", + "reference": "ebaf24ec0318583d8c022966687e2a4979bb9af8", "shasum": "" }, "require": { @@ -10352,7 +10590,6 @@ "theofidry/alice-data-fixtures": "^1.5" }, "require-dev": { - "doctrine/shards": "^1.0", "phpspec/prophecy": "^1.7", "phpspec/prophecy-phpunit": "^2.0", "phpunit/phpunit": "^9.5", @@ -10396,9 +10633,9 @@ ], "support": { "issues": "https://github.com/theofidry/AliceBundle/issues", - "source": "https://github.com/theofidry/AliceBundle/tree/2.11.0" + "source": "https://github.com/theofidry/AliceBundle/tree/2.12.0" }, - "time": "2022-07-03T14:56:03+00:00" + "time": "2023-03-26T09:04:39+00:00" }, { "name": "localheinz/diff", @@ -10462,16 +10699,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.11.0", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "shasum": "" }, "require": { @@ -10509,7 +10746,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" }, "funding": [ { @@ -10517,27 +10754,27 @@ "type": "tidelift" } ], - "time": "2022-03-03T13:19:32+00:00" + "time": "2023-03-08T13:26:56+00:00" }, { "name": "nelmio/alice", - "version": "3.12.1", + "version": "3.12.2", "source": { "type": "git", "url": "https://github.com/nelmio/alice.git", - "reference": "e7d3275a9137bea1436b89f0fea770d0feca5358" + "reference": "a020c0767e10dbb7bf1c193e16e94710691133d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nelmio/alice/zipball/e7d3275a9137bea1436b89f0fea770d0feca5358", - "reference": "e7d3275a9137bea1436b89f0fea770d0feca5358", + "url": "https://api.github.com/repos/nelmio/alice/zipball/a020c0767e10dbb7bf1c193e16e94710691133d9", + "reference": "a020c0767e10dbb7bf1c193e16e94710691133d9", "shasum": "" }, "require": { "fakerphp/faker": "^1.10", "myclabs/deep-copy": "^1.10", "php": "^8.1", - "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/comparator": "^3.0 || ^4.0 || ^5.0", "symfony/property-access": "^5.4 || ^6.0", "symfony/yaml": "^5.4 || ^6.0" }, @@ -10603,7 +10840,7 @@ ], "support": { "issues": "https://github.com/nelmio/alice/issues", - "source": "https://github.com/nelmio/alice/tree/3.12.1" + "source": "https://github.com/nelmio/alice/tree/3.12.2" }, "funding": [ { @@ -10611,20 +10848,20 @@ "type": "github" } ], - "time": "2022-11-14T18:45:17+00:00" + "time": "2023-02-13T11:17:55+00:00" }, { "name": "netresearch/jsonmapper", - "version": "v4.1.0", + "version": "v4.2.0", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f" + "reference": "f60565f8c0566a31acf06884cdaa591867ecc956" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", - "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956", + "reference": "f60565f8c0566a31acf06884cdaa591867ecc956", "shasum": "" }, "require": { @@ -10660,22 +10897,22 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.1.0" + "source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0" }, - "time": "2022-12-08T20:46:14+00:00" + "time": "2023-04-09T17:37:40+00:00" }, { "name": "nikic/php-parser", - "version": "v4.15.3", + "version": "v4.15.5", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", - "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", "shasum": "" }, "require": { @@ -10716,62 +10953,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" - }, - "time": "2023-01-16T22:05:37+00:00" - }, - { - "name": "openlss/lib-array2xml", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/nullivex/lib-array2xml.git", - "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", - "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "type": "library", - "autoload": { - "psr-0": { - "LSS": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Bryan Tong", - "email": "bryan@nullivex.com", - "homepage": "https://www.nullivex.com" - }, - { - "name": "Tony Butler", - "email": "spudz76@gmail.com", - "homepage": "https://www.nullivex.com" - } - ], - "description": "Array2XML conversion library credit to lalit.org", - "homepage": "https://www.nullivex.com", - "keywords": [ - "array", - "array conversion", - "xml", - "xml conversion" - ], - "support": { - "issues": "https://github.com/nullivex/lib-array2xml/issues", - "source": "https://github.com/nullivex/lib-array2xml/tree/master" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" }, - "time": "2019-03-29T20:06:56+00:00" + "time": "2023-05-19T20:20:00+00:00" }, { "name": "phar-io/manifest", @@ -10886,23 +11070,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.24", + "version": "9.2.26", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed" + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed", - "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.14", + "nikic/php-parser": "^4.15", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -10917,8 +11101,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": { @@ -10951,7 +11135,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" }, "funding": [ { @@ -10959,7 +11143,7 @@ "type": "github" } ], - "time": "2023-01-26T08:26:55+00:00" + "time": "2023-03-06T12:58:08+00:00" }, { "name": "phpunit/php-file-iterator", @@ -11204,16 +11388,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.28", + "version": "9.6.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "954ca3113a03bf780d22f07bf055d883ee04b65e" + "reference": "a9aceaf20a682aeacf28d582654a1670d8826778" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/954ca3113a03bf780d22f07bf055d883ee04b65e", - "reference": "954ca3113a03bf780d22f07bf055d883ee04b65e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a9aceaf20a682aeacf28d582654a1670d8826778", + "reference": "a9aceaf20a682aeacf28d582654a1670d8826778", "shasum": "" }, "require": { @@ -11246,8 +11430,8 @@ "sebastian/version": "^3.0.2" }, "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" @@ -11255,7 +11439,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.5-dev" + "dev-master": "9.6-dev" } }, "autoload": { @@ -11286,7 +11470,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.28" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.9" }, "funding": [ { @@ -11302,41 +11487,41 @@ "type": "tidelift" } ], - "time": "2023-01-14T12:32:24+00:00" + "time": "2023-06-11T06:13:56+00:00" }, { "name": "psalm/plugin-symfony", - "version": "v3.1.10", + "version": "v5.0.3", "source": { "type": "git", "url": "https://github.com/psalm/psalm-plugin-symfony.git", - "reference": "5dca17839a6d48766ac760b8aa6d1f6d12759b28" + "reference": "a6cef9c701686d17d4254b544d05345e9d3e0b88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/psalm/psalm-plugin-symfony/zipball/5dca17839a6d48766ac760b8aa6d1f6d12759b28", - "reference": "5dca17839a6d48766ac760b8aa6d1f6d12759b28", + "url": "https://api.github.com/repos/psalm/psalm-plugin-symfony/zipball/a6cef9c701686d17d4254b544d05345e9d3e0b88", + "reference": "a6cef9c701686d17d4254b544d05345e9d3e0b88", "shasum": "" }, "require": { "ext-simplexml": "*", - "php": "^7.1 || ^8.0", - "symfony/framework-bundle": "^4.0 || ^5.0 || ^6.0", - "vimeo/psalm": "^4.12" + "php": "^7.4 || ^8.0", + "symfony/framework-bundle": "^5.0 || ^6.0", + "vimeo/psalm": "^5.1" }, "require-dev": { - "doctrine/annotations": "^1.8", - "doctrine/orm": "^2.7", + "doctrine/annotations": "^1.8|^2", + "doctrine/orm": "^2.9", "phpunit/phpunit": "~7.5 || ~9.5", "symfony/cache-contracts": "^1.0 || ^2.0", "symfony/console": "*", - "symfony/form": "^4.0 || ^5.0 || ^6.0", - "symfony/messenger": "^4.2 || ^5.0 || ^6.0", + "symfony/form": "^5.0 || ^6.0", + "symfony/messenger": "^5.0 || ^6.0", "symfony/security-guard": "*", - "symfony/serializer": "^4.0 || ^5.0 || ^6.0", + "symfony/serializer": "^5.0 || ^6.0", "symfony/validator": "*", "twig/twig": "^2.10 || ^3.0", - "weirdan/codeception-psalm-module": "^0.13.1" + "weirdan/codeception-psalm-module": "dev-master" }, "suggest": { "weirdan/doctrine-psalm-plugin": "If Doctrine is used, it is recommended install this plugin" @@ -11365,9 +11550,9 @@ "description": "Psalm Plugin for Symfony", "support": { "issues": "https://github.com/psalm/psalm-plugin-symfony/issues", - "source": "https://github.com/psalm/psalm-plugin-symfony/tree/v3.1.10" + "source": "https://github.com/psalm/psalm-plugin-symfony/tree/v5.0.3" }, - "time": "2022-10-22T13:09:05+00:00" + "time": "2023-04-21T15:40:12+00:00" }, { "name": "sebastian/cli-parser", @@ -11669,16 +11854,16 @@ }, { "name": "sebastian/environment", - "version": "5.1.4", + "version": "5.1.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7" + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1b5dff7bb151a4db11d49d90e5408e4e938270f7", - "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", "shasum": "" }, "require": { @@ -11720,7 +11905,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.4" + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" }, "funding": [ { @@ -11728,7 +11913,7 @@ "type": "github" } ], - "time": "2022-04-03T09:37:03+00:00" + "time": "2023-02-03T06:03:51+00:00" }, { "name": "sebastian/exporter", @@ -12042,16 +12227,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": { @@ -12090,10 +12275,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": [ { @@ -12101,7 +12286,7 @@ "type": "github" } ], - "time": "2020-10-26T13:17:30+00:00" + "time": "2023-02-03T06:07:39+00:00" }, { "name": "sebastian/resource-operations", @@ -12160,16 +12345,16 @@ }, { "name": "sebastian/type", - "version": "3.2.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e" + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", - "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", "shasum": "" }, "require": { @@ -12204,7 +12389,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.0" + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" }, "funding": [ { @@ -12212,7 +12397,7 @@ "type": "github" } ], - "time": "2022-09-12T14:47:03+00:00" + "time": "2023-02-03T06:13:03+00:00" }, { "name": "sebastian/version", @@ -12267,18 +12452,81 @@ ], "time": "2020-09-28T06:39:44+00:00" }, + { + "name": "spatie/array-to-xml", + "version": "3.1.6", + "source": { + "type": "git", + "url": "https://github.com/spatie/array-to-xml.git", + "reference": "e210b98957987c755372465be105d32113f339a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/e210b98957987c755372465be105d32113f339a4", + "reference": "e210b98957987c755372465be105d32113f339a4", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": "^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.2", + "pestphp/pest": "^1.21", + "spatie/pest-plugin-snapshots": "^1.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\ArrayToXml\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://freek.dev", + "role": "Developer" + } + ], + "description": "Convert an array to xml", + "homepage": "https://github.com/spatie/array-to-xml", + "keywords": [ + "array", + "convert", + "xml" + ], + "support": { + "source": "https://github.com/spatie/array-to-xml/tree/3.1.6" + }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + }, + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2023-05-11T14:04:07+00:00" + }, { "name": "symfony/browser-kit", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "572b9e03741051b97c316f65f8c361eed08fdb14" + "reference": "a866ca7e396f15d7efb6d74a8a7d364d4e05b704" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/572b9e03741051b97c316f65f8c361eed08fdb14", - "reference": "572b9e03741051b97c316f65f8c361eed08fdb14", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/a866ca7e396f15d7efb6d74a8a7d364d4e05b704", + "reference": "a866ca7e396f15d7efb6d74a8a7d364d4e05b704", "shasum": "" }, "require": { @@ -12321,7 +12569,7 @@ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/browser-kit/tree/v5.4.19" + "source": "https://github.com/symfony/browser-kit/tree/v5.4.21" }, "funding": [ { @@ -12337,20 +12585,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/css-selector", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "f4a7d150f5b9e8f974f6f127d8167e420d11fc62" + "reference": "95f3c7468db1da8cc360b24fa2a26e7cefcb355d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/f4a7d150f5b9e8f974f6f127d8167e420d11fc62", - "reference": "f4a7d150f5b9e8f974f6f127d8167e420d11fc62", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/95f3c7468db1da8cc360b24fa2a26e7cefcb355d", + "reference": "95f3c7468db1da8cc360b24fa2a26e7cefcb355d", "shasum": "" }, "require": { @@ -12387,7 +12635,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.4.19" + "source": "https://github.com/symfony/css-selector/tree/v5.4.21" }, "funding": [ { @@ -12403,20 +12651,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/debug-bundle", - "version": "v5.4.19", + "version": "v5.4.21", "source": { "type": "git", "url": "https://github.com/symfony/debug-bundle.git", - "reference": "40e9ffe230aed8518c80816da27c80433ec220c7" + "reference": "8b4360bf8ce9a917ef8796c5e6065a185d8722bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/40e9ffe230aed8518c80816da27c80433ec220c7", - "reference": "40e9ffe230aed8518c80816da27c80433ec220c7", + "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/8b4360bf8ce9a917ef8796c5e6065a185d8722bd", + "reference": "8b4360bf8ce9a917ef8796c5e6065a185d8722bd", "shasum": "" }, "require": { @@ -12466,7 +12714,7 @@ "description": "Provides a tight integration of the Symfony VarDumper component and the ServerLogCommand from MonologBridge into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug-bundle/tree/v5.4.19" + "source": "https://github.com/symfony/debug-bundle/tree/v5.4.21" }, "funding": [ { @@ -12482,20 +12730,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-02-14T08:03:56+00:00" }, { "name": "symfony/dom-crawler", - "version": "v5.4.19", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "224a1820e7669babdd85970230ed72bd6e342ad4" + "reference": "4a286c916b74ecfb6e2caf1aa31d3fe2a34b7e08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/224a1820e7669babdd85970230ed72bd6e342ad4", - "reference": "224a1820e7669babdd85970230ed72bd6e342ad4", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4a286c916b74ecfb6e2caf1aa31d3fe2a34b7e08", + "reference": "4a286c916b74ecfb6e2caf1aa31d3fe2a34b7e08", "shasum": "" }, "require": { @@ -12541,7 +12789,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v5.4.19" + "source": "https://github.com/symfony/dom-crawler/tree/v5.4.23" }, "funding": [ { @@ -12557,20 +12805,20 @@ "type": "tidelift" } ], - "time": "2023-01-14T19:14:44+00:00" + "time": "2023-04-08T21:20:19+00:00" }, { "name": "symfony/maker-bundle", - "version": "v1.48.0", + "version": "v1.49.0", "source": { "type": "git", "url": "https://github.com/symfony/maker-bundle.git", - "reference": "2e428e8432e9879187672fe08f1cc335e2a31dd6" + "reference": "ce1d424f76bbb377f1956cc7641e8e2eafe81cde" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/2e428e8432e9879187672fe08f1cc335e2a31dd6", - "reference": "2e428e8432e9879187672fe08f1cc335e2a31dd6", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/ce1d424f76bbb377f1956cc7641e8e2eafe81cde", + "reference": "ce1d424f76bbb377f1956cc7641e8e2eafe81cde", "shasum": "" }, "require": { @@ -12584,7 +12832,8 @@ "symfony/filesystem": "^5.4.7|^6.0", "symfony/finder": "^5.4.3|^6.0", "symfony/framework-bundle": "^5.4.7|^6.0", - "symfony/http-kernel": "^5.4.7|^6.0" + "symfony/http-kernel": "^5.4.7|^6.0", + "symfony/process": "^5.4.7|^6.0" }, "conflict": { "doctrine/doctrine-bundle": "<2.4", @@ -12596,9 +12845,8 @@ "doctrine/doctrine-bundle": "^2.4", "doctrine/orm": "^2.10.0", "symfony/http-client": "^5.4.7|^6.0", - "symfony/phpunit-bridge": "^5.4.7|^6.0", + "symfony/phpunit-bridge": "^5.4.17|^6.0", "symfony/polyfill-php80": "^1.16.0", - "symfony/process": "^5.4.7|^6.0", "symfony/security-core": "^5.4.7|^6.0", "symfony/yaml": "^5.4.3|^6.0", "twig/twig": "^2.0|^3.0" @@ -12634,7 +12882,7 @@ ], "support": { "issues": "https://github.com/symfony/maker-bundle/issues", - "source": "https://github.com/symfony/maker-bundle/tree/v1.48.0" + "source": "https://github.com/symfony/maker-bundle/tree/v1.49.0" }, "funding": [ { @@ -12650,20 +12898,20 @@ "type": "tidelift" } ], - "time": "2022-11-14T10:48:46+00:00" + "time": "2023-06-07T13:10:14+00:00" }, { "name": "symfony/phpunit-bridge", - "version": "v5.4.19", + "version": "v5.4.23", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "3b213e88832612c5eee0f8a9b764897896b23bf0" + "reference": "1572c5b7cad812bdf0414d89a32a33a2dafb38ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/3b213e88832612c5eee0f8a9b764897896b23bf0", - "reference": "3b213e88832612c5eee0f8a9b764897896b23bf0", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/1572c5b7cad812bdf0414d89a32a33a2dafb38ba", + "reference": "1572c5b7cad812bdf0414d89a32a33a2dafb38ba", "shasum": "" }, "require": { @@ -12717,7 +12965,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v5.4.19" + "source": "https://github.com/symfony/phpunit-bridge/tree/v5.4.23" }, "funding": [ { @@ -12733,20 +12981,20 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-04-18T09:42:03+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v5.4.19", + "version": "v5.4.24", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "cd83822071f2bc05583af1e53c1bc46be625a56d" + "reference": "42dbb751c0363d75a3697775e662d6f21f3d8b83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/cd83822071f2bc05583af1e53c1bc46be625a56d", - "reference": "cd83822071f2bc05583af1e53c1bc46be625a56d", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/42dbb751c0363d75a3697775e662d6f21f3d8b83", + "reference": "42dbb751c0363d75a3697775e662d6f21f3d8b83", "shasum": "" }, "require": { @@ -12797,7 +13045,7 @@ "description": "Provides a development tool that gives detailed information about the execution of any request", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v5.4.19" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v5.4.24" }, "funding": [ { @@ -12813,7 +13061,7 @@ "type": "tidelift" } ], - "time": "2023-01-01T08:32:19+00:00" + "time": "2023-05-02T16:38:36+00:00" }, { "name": "theofidry/alice-data-fixtures", @@ -12961,24 +13209,24 @@ }, { "name": "vimeo/psalm", - "version": "4.30.0", + "version": "5.12.0", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "d0bc6e25d89f649e4f36a534f330f8bb4643dd69" + "reference": "f90118cdeacd0088e7215e64c0c99ceca819e176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/d0bc6e25d89f649e4f36a534f330f8bb4643dd69", - "reference": "d0bc6e25d89f649e4f36a534f330f8bb4643dd69", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/f90118cdeacd0088e7215e64c0c99ceca819e176", + "reference": "f90118cdeacd0088e7215e64c0c99ceca819e176", "shasum": "" }, "require": { "amphp/amp": "^2.4.2", "amphp/byte-stream": "^1.5", - "composer/package-versions-deprecated": "^1.8.0", + "composer-runtime-api": "^2", "composer/semver": "^1.4 || ^2.0 || ^3.0", - "composer/xdebug-handler": "^1.1 || ^2.0 || ^3.0", + "composer/xdebug-handler": "^2.0 || ^3.0", "dnoegel/php-xdg-base-dir": "^0.1.1", "ext-ctype": "*", "ext-dom": "*", @@ -12987,35 +13235,35 @@ "ext-mbstring": "*", "ext-simplexml": "*", "ext-tokenizer": "*", - "felixfbecker/advanced-json-rpc": "^3.0.3", - "felixfbecker/language-server-protocol": "^1.5", + "felixfbecker/advanced-json-rpc": "^3.1", + "felixfbecker/language-server-protocol": "^1.5.2", + "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1", "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "nikic/php-parser": "^4.13", - "openlss/lib-array2xml": "^1.0", - "php": "^7.1|^8", - "sebastian/diff": "^3.0 || ^4.0", - "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0 || ^6.0", - "symfony/polyfill-php80": "^1.25", - "webmozart/path-util": "^2.3" + "nikic/php-parser": "^4.14", + "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0", + "sebastian/diff": "^4.0 || ^5.0", + "spatie/array-to-xml": "^2.17.0 || ^3.0", + "symfony/console": "^4.1.6 || ^5.0 || ^6.0", + "symfony/filesystem": "^5.4 || ^6.0" }, "provide": { "psalm/psalm": "self.version" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.2", - "brianium/paratest": "^4.0||^6.0", + "amphp/phpunit-util": "^2.0", + "bamarni/composer-bin-plugin": "^1.4", + "brianium/paratest": "^6.9", "ext-curl": "*", + "mockery/mockery": "^1.5", + "nunomaduro/mock-final-classes": "^1.1", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpdocumentor/reflection-docblock": "^5", - "phpmyadmin/sql-parser": "5.1.0||dev-master", - "phpspec/prophecy": ">=1.9.0", - "phpstan/phpdoc-parser": "1.2.* || 1.6.4", - "phpunit/phpunit": "^9.0", - "psalm/plugin-phpunit": "^0.16", - "slevomat/coding-standard": "^7.0", - "squizlabs/php_codesniffer": "^3.5", - "symfony/process": "^4.3 || ^5.0 || ^6.0", - "weirdan/prophecy-shim": "^1.0 || ^2.0" + "phpstan/phpdoc-parser": "^1.6", + "phpunit/phpunit": "^9.6", + "psalm/plugin-mockery": "^1.1", + "psalm/plugin-phpunit": "^0.18", + "slevomat/coding-standard": "^8.4", + "squizlabs/php_codesniffer": "^3.6", + "symfony/process": "^4.4 || ^5.0 || ^6.0" }, "suggest": { "ext-curl": "In order to send data to shepherd", @@ -13031,17 +13279,14 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev", + "dev-master": "5.x-dev", + "dev-4.x": "4.x-dev", "dev-3.x": "3.x-dev", "dev-2.x": "2.x-dev", "dev-1.x": "1.x-dev" } }, "autoload": { - "files": [ - "src/functions.php", - "src/spl_object_id.php" - ], "psr-4": { "Psalm\\": "src/Psalm/" } @@ -13059,94 +13304,46 @@ "keywords": [ "code", "inspection", - "php" + "php", + "static analysis" ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/4.30.0" - }, - "time": "2022-11-06T20:37:08+00:00" - }, - { - "name": "webmozart/path-util", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/webmozart/path-util.git", - "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", - "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "webmozart/assert": "~1.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\PathUtil\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", - "support": { - "issues": "https://github.com/webmozart/path-util/issues", - "source": "https://github.com/webmozart/path-util/tree/2.3.0" + "source": "https://github.com/vimeo/psalm/tree/5.12.0" }, - "abandoned": "symfony/filesystem", - "time": "2015-12-17T08:42:14+00:00" + "time": "2023-05-22T21:19:03+00:00" }, { "name": "weirdan/doctrine-psalm-plugin", - "version": "v1.2.0", + "version": "v2.8.1", "source": { "type": "git", "url": "https://github.com/psalm/psalm-plugin-doctrine.git", - "reference": "b24dcfd4815eed489800e97c0b605932800aabec" + "reference": "4f62e33f523b2e452997228405dfe8d5d886d13a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/psalm/psalm-plugin-doctrine/zipball/b24dcfd4815eed489800e97c0b605932800aabec", - "reference": "b24dcfd4815eed489800e97c0b605932800aabec", + "url": "https://api.github.com/repos/psalm/psalm-plugin-doctrine/zipball/4f62e33f523b2e452997228405dfe8d5d886d13a", + "reference": "4f62e33f523b2e452997228405dfe8d5d886d13a", "shasum": "" }, "require": { "composer/semver": "^1.4 || ^2.0 || ^3.0", "php": "^7.2 || ^8", - "vimeo/psalm": "^4.9 || dev-master" + "vimeo/psalm": "^4.28|^5.0" }, "conflict": { - "doctrine/collections": "<1.6", - "doctrine/orm": "<2.6" + "doctrine/collections": "<1.8", + "doctrine/orm": "<2.6", + "doctrine/persistence": "<2.0" }, "require-dev": { "codeception/codeception": "^4.0", "doctrine/coding-standard": "^9.0", - "doctrine/collections": "^1.0", + "doctrine/collections": "^1.8 || ^2.0", "doctrine/doctrine-bundle": "^1.11 || ^2.0", "doctrine/orm": "^2.6", + "doctrine/persistence": "^2.0", "phly/keep-a-changelog": "^2.1", "squizlabs/php_codesniffer": "^3.3", "weirdan/codeception-psalm-module": "^0.13.1" @@ -13190,9 +13387,9 @@ ], "support": { "issues": "https://github.com/psalm/psalm-plugin-doctrine/issues", - "source": "https://github.com/psalm/psalm-plugin-doctrine/tree/v1.2.0" + "source": "https://github.com/psalm/psalm-plugin-doctrine/tree/v2.8.1" }, - "time": "2021-10-31T17:59:51+00:00" + "time": "2023-01-17T23:18:44+00:00" } ], "aliases": [], diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml deleted file mode 100644 index 0e734f29..00000000 --- a/docker-compose.dev.yml +++ /dev/null @@ -1,28 +0,0 @@ -# itk-version: 3.0.0 -version: "3" - -services: - phpfpm: - environment: - - PHP_SENDMAIL_PATH='/usr/local/bin/mhsendmail --smtp-addr="mailhog:1025"' - - nginx: - labels: - - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=ITKBasicAuth@file" - - mailhog: - image: itkdev/mailhog - networks: - - app - - frontend - labels: - - "traefik.enable=true" - - "traefik.docker.network=frontend" - - "traefik.http.routers.mailhog_${COMPOSE_PROJECT_NAME}-http.rule=Host(`mailhog.${COMPOSE_SERVER_DOMAIN}`)" - - "traefik.http.routers.mailhog_${COMPOSE_PROJECT_NAME}-http.entrypoints=web" - - "traefik.http.routers.mailhog_${COMPOSE_PROJECT_NAME}-http.middlewares=redirect-to-https" - - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - - "traefik.http.routers.mailhog_${COMPOSE_PROJECT_NAME}.rule=Host(`mailhog.${COMPOSE_SERVER_DOMAIN}`)" - - "traefik.http.routers.mailhog_${COMPOSE_PROJECT_NAME}.entrypoints=websecure" - - "traefik.http.services.mailhog_${COMPOSE_PROJECT_NAME}.loadbalancer.server.port=8025" - - "traefik.http.routers.mailhog_${COMPOSE_PROJECT_NAME}.middlewares=ITKMailhogAuth@file" diff --git a/docker-compose.redirect.yml b/docker-compose.redirect.yml deleted file mode 100644 index 9c1d2af1..00000000 --- a/docker-compose.redirect.yml +++ /dev/null @@ -1,17 +0,0 @@ -# itk-version: 3.0.0 -version: "3" - -services: - nginx: - labels: - # Add www before domain and set redirect to non-www - - "traefik.http.routers.www_${COMPOSE_PROJECT_NAME}-http.rule=Host(`www.${COMPOSE_SERVER_DOMAIN}`)" - - "traefik.http.routers.www_${COMPOSE_PROJECT_NAME}-http.entrypoints=web" - - "traefik.http.routers.www_${COMPOSE_PROJECT_NAME}-http.middlewares=redirect-to-https,non_www" - - "traefik.http.routers.www_${COMPOSE_PROJECT_NAME}.rule=Host(`www.${COMPOSE_SERVER_DOMAIN}`)" - - "traefik.http.routers.www_${COMPOSE_PROJECT_NAME}.entrypoints=websecure" - - "traefik.http.routers.www_${COMPOSE_PROJECT_NAME}.middlewares=non_www" - - - traefik.http.middlewares.non_www.redirectregex.regex=^(http|https)?://(?:www\.)?(.+) - - traefik.http.middlewares.non_www.redirectregex.replacement=https://$${2} - - traefik.http.middlewares.non_www.redirectregex.permanent=true diff --git a/docker-compose.server.yml b/docker-compose.server.yml deleted file mode 100644 index 47797eb6..00000000 --- a/docker-compose.server.yml +++ /dev/null @@ -1,48 +0,0 @@ -# itk-version: 3.0.0 -version: "3" - -networks: - frontend: - external: true - app: - driver: bridge - internal: false - -services: - phpfpm: - image: itkdev/php8.1-fpm:alpine - restart: unless-stopped - networks: - - app - extra_hosts: - - "host.docker.internal:host-gateway" - environment: - - PHP_MAX_EXECUTION_TIME=30 - - PHP_MEMORY_LIMIT=128M - - COMPOSER_VERSION=2 - volumes: - - .:/app - - nginx: - image: nginxinc/nginx-unprivileged:alpine - restart: unless-stopped - networks: - - app - - frontend - depends_on: - - phpfpm - ports: - - '8080' - volumes: - - ./.docker/vhost.conf:/etc/nginx/conf.d/default.conf:ro - - ./.docker/nginx.conf:/etc/nginx/nginx.conf:ro - - ./:/app:rw - labels: - - "traefik.enable=true" - - "traefik.docker.network=frontend" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME}-http.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME}-http.entrypoints=web" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME}-http.middlewares=redirect-to-https" - - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.rule=Host(`${COMPOSE_SERVER_DOMAIN}`)" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.entrypoints=websecure" diff --git a/docker-compose.yml b/docker-compose.yml index 9b760af7..aed02bd3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -26,6 +26,8 @@ services: image: itkdev/php8.1-fpm:latest networks: - app + extra_hosts: + - "host.docker.internal:host-gateway" environment: - PHP_XDEBUG_MODE=${PHP_XDEBUG_MODE:-off} - PHP_MAX_EXECUTION_TIME=30 diff --git a/infrastructure/itkdev/Readme.md b/infrastructure/itkdev/Readme.md new file mode 100644 index 00000000..f5566795 --- /dev/null +++ b/infrastructure/itkdev/Readme.md @@ -0,0 +1,3 @@ +# ITK-development image build + +This folder contains the infrastructure files for building the `itkdev/*` images \ No newline at end of file diff --git a/infrastructure/display-api-service/Dockerfile b/infrastructure/itkdev/display-api-service/Dockerfile similarity index 98% rename from infrastructure/display-api-service/Dockerfile rename to infrastructure/itkdev/display-api-service/Dockerfile index f8ec6fe8..7726eb57 100644 --- a/infrastructure/display-api-service/Dockerfile +++ b/infrastructure/itkdev/display-api-service/Dockerfile @@ -44,14 +44,14 @@ RUN mkdir -p ${APP_PATH}/config/secrets \ COPY --from=hipages/php-fpm_exporter:1.1.1 /php-fpm_exporter /usr/local/bin/php-fpm_exporter # Copy configuration. -COPY etc/ /etc/ +COPY etc /etc/ # Install configuration template handler ADD https://github.com/kelseyhightower/confd/releases/download/v0.16.0/confd-0.16.0-linux-amd64 /usr/local/bin/confd RUN chmod +x /usr/local/bin/confd # Copy confd onfiguration. -COPY etc/ /etc/ +COPY etc /etc/ COPY docker-entrypoint.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/docker-entrypoint.sh diff --git a/infrastructure/display-api-service/docker-entrypoint.sh b/infrastructure/itkdev/display-api-service/docker-entrypoint.sh similarity index 100% rename from infrastructure/display-api-service/docker-entrypoint.sh rename to infrastructure/itkdev/display-api-service/docker-entrypoint.sh diff --git a/infrastructure/display-api-service/etc/confd/conf.d/env.local.toml b/infrastructure/itkdev/display-api-service/etc/confd/conf.d/env.local.toml similarity index 98% rename from infrastructure/display-api-service/etc/confd/conf.d/env.local.toml rename to infrastructure/itkdev/display-api-service/etc/confd/conf.d/env.local.toml index 1b8fded5..d614cc69 100644 --- a/infrastructure/display-api-service/etc/confd/conf.d/env.local.toml +++ b/infrastructure/itkdev/display-api-service/etc/confd/conf.d/env.local.toml @@ -5,4 +5,4 @@ owner = "deploy" mode = "0644" keys = [ "/app-config" -] \ No newline at end of file +] diff --git a/infrastructure/display-api-service/etc/confd/templates/env.local.tmpl b/infrastructure/itkdev/display-api-service/etc/confd/templates/env.local.tmpl similarity index 100% rename from infrastructure/display-api-service/etc/confd/templates/env.local.tmpl rename to infrastructure/itkdev/display-api-service/etc/confd/templates/env.local.tmpl diff --git a/infrastructure/nginx/Dockerfile b/infrastructure/itkdev/nginx/Dockerfile similarity index 100% rename from infrastructure/nginx/Dockerfile rename to infrastructure/itkdev/nginx/Dockerfile diff --git a/infrastructure/nginx/docker-entrypoint.sh b/infrastructure/itkdev/nginx/docker-entrypoint.sh similarity index 100% rename from infrastructure/nginx/docker-entrypoint.sh rename to infrastructure/itkdev/nginx/docker-entrypoint.sh diff --git a/infrastructure/nginx/etc/confd/conf.d/default.conf.toml b/infrastructure/itkdev/nginx/etc/confd/conf.d/default.conf.toml similarity index 98% rename from infrastructure/nginx/etc/confd/conf.d/default.conf.toml rename to infrastructure/itkdev/nginx/etc/confd/conf.d/default.conf.toml index 68f7ecaa..185954f0 100644 --- a/infrastructure/nginx/etc/confd/conf.d/default.conf.toml +++ b/infrastructure/itkdev/nginx/etc/confd/conf.d/default.conf.toml @@ -4,4 +4,4 @@ dest = "/etc/nginx/conf.d/default.conf" mode = "0644" keys = [ "/nginx-config" -] \ No newline at end of file +] diff --git a/infrastructure/nginx/etc/confd/conf.d/nginx.conf.toml b/infrastructure/itkdev/nginx/etc/confd/conf.d/nginx.conf.toml similarity index 98% rename from infrastructure/nginx/etc/confd/conf.d/nginx.conf.toml rename to infrastructure/itkdev/nginx/etc/confd/conf.d/nginx.conf.toml index 9838edc0..7c81a661 100644 --- a/infrastructure/nginx/etc/confd/conf.d/nginx.conf.toml +++ b/infrastructure/itkdev/nginx/etc/confd/conf.d/nginx.conf.toml @@ -4,4 +4,4 @@ dest = "/etc/nginx/nginx.conf" mode = "0644" keys = [ "/nginx-config" -] \ No newline at end of file +] diff --git a/infrastructure/nginx/etc/confd/templates/default.conf.tmpl b/infrastructure/itkdev/nginx/etc/confd/templates/default.conf.tmpl similarity index 100% rename from infrastructure/nginx/etc/confd/templates/default.conf.tmpl rename to infrastructure/itkdev/nginx/etc/confd/templates/default.conf.tmpl diff --git a/infrastructure/nginx/etc/confd/templates/nginx.conf.tmpl b/infrastructure/itkdev/nginx/etc/confd/templates/nginx.conf.tmpl similarity index 100% rename from infrastructure/nginx/etc/confd/templates/nginx.conf.tmpl rename to infrastructure/itkdev/nginx/etc/confd/templates/nginx.conf.tmpl diff --git a/infrastructure/run.sh b/infrastructure/itkdev/run.sh old mode 100755 new mode 100644 similarity index 100% rename from infrastructure/run.sh rename to infrastructure/itkdev/run.sh diff --git a/infrastructure/os2display/Readme.md b/infrastructure/os2display/Readme.md new file mode 100644 index 00000000..f7a40e5d --- /dev/null +++ b/infrastructure/os2display/Readme.md @@ -0,0 +1,3 @@ +# OS2display image build + +This folder contains the infrastructure files for building the `os2display/*` images \ No newline at end of file diff --git a/infrastructure/os2display/display-api-service/Dockerfile b/infrastructure/os2display/display-api-service/Dockerfile new file mode 100644 index 00000000..99ba3975 --- /dev/null +++ b/infrastructure/os2display/display-api-service/Dockerfile @@ -0,0 +1,154 @@ +FROM php:8.1-fpm-alpine +LABEL maintainer="ITK Dev " + +############# SETUP CONTAINER ############# + +USER root + +ARG APP_VERSION="develop" + +ENV APP_PATH=/var/www/html \ + # PHP + TZ="Europe/Copenhagen" \ + PHP_TIMEZONE="Europe/Copenhagen" \ + PHP_MAX_EXECUTION_TIME="30" \ + PHP_MEMORY_LIMIT="128M" \ + PHP_POST_MAX_SIZE="8M" \ + PHP_UPLOAD_MAX_FILESIZE="2M" \ + PHP_USER="www-data" \ + PHP_GROUP="www-data" \ + PHP_SENDMAIL_PATH='/usr/sbin/sendmail -S host.docker.internal -t -i' \ + # OpCache + PHP_OPCACHE_ENABLED="1" \ + PHP_OPCACHE_JIT="off" \ + PHP_OPCACHE_REVALIDATE_FREQ=0 \ + PHP_OPCACHE_VALIDATE_TIMESTAMPS="1" \ + PHP_OPCACHE_MAX_ACCELERATED_FILES="20000" \ + PHP_OPCACHE_MEMORY_CONSUMPTION="64" \ + PHP_OPCACHE_MAX_WASTED_PERCENTAGE="10" \ + # APCU + PHP_APCU_ENABLED=0 \ + PHP_APCU_ENABLED_CLI=0 \ + PHP_APCU_MEMORY_SIZE="16M" \ + PHP_APCU_SEGMENTS=1 \ + PHP_APCU_PRELOAD_PATH='' \ + # FPM pool + PHP_PM_TYPE="static" \ + PHP_PM_MAX_CHILDREN="8" \ + PHP_PM_MAX_REQUESTS="0" \ + PHP_PM_START_SERVERS="5" \ + PHP_PM_MIN_SPARE_SERVERS="5" \ + PHP_PM_MAX_SPARE_SERVERS="8" \ + # Other + PHP_REQUEST_SLOWLOG_TIMEOUT="0" \ + PHP_SLOWLOG="/dev/stderr" \ + COMPOSER_ALLOW_SUPERUSER=1 + +RUN apk upgrade --no-cache --ignore curl +RUN apk --update add --no-cache \ + libxslt-dev \ + libzip-dev \ + libpng-dev \ + gettext-dev \ + git \ + unzip \ + icu-dev \ + icu-data-full \ + openldap-dev \ + libmcrypt-dev \ + mysql-client \ + libmemcached-libs \ + zlib \ + patch \ + tzdata \ + freetype-dev \ + libjpeg-turbo-dev \ + libjpeg-turbo \ + libwebp-dev \ + && docker-php-ext-configure gd --with-freetype --with-webp --with-jpeg \ + && docker-php-ext-install -j$(nproc) \ + bcmath \ + calendar \ + gd \ + gettext \ + intl \ + ldap \ + mysqli \ + opcache \ + pdo_mysql \ + sysvsem \ + soap \ + xsl \ + zip + +# Extension that are not available via ext- +RUN apk --update add --no-cache --virtual .build-deps autoconf g++ make zlib-dev libmemcached-dev cyrus-sasl-dev \ + && pecl channel-update pecl.php.net \ + && pecl install redis memcached apcu \ + && docker-php-ext-enable apcu redis memcached \ + && apk del .build-deps + +# Install AMQP support +RUN apk --update add --no-cache rabbitmq-c +RUN apk --update add --no-cache --virtual .build-deps autoconf g++ make rabbitmq-c-dev \ + && pecl install amqp \ + && docker-php-ext-enable amqp memcached \ + && apk del .build-deps + +# Install composer +COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer + +# Use default PHP production configuration. +RUN mv ${PHP_INI_DIR}/php.ini-production ${PHP_INI_DIR}/php.ini + +# # Copy custom PHP configuration. +COPY php/opcache.ini ${PHP_INI_DIR}/conf.d/docker-php-ext-opcache.ini +COPY php/php.ini ${PHP_INI_DIR}/conf.d/zz-php.ini +COPY php/apcu.ini ${PHP_INI_DIR}/conf.d/docker-php-ext-apcu.ini + +# Custom FPM configuration. +COPY php/fpm.ini ${PHP_INI_DIR}/../php-fpm.d/zz-fpm-docker.conf + +# Add mhsendmail for mailhog +ADD https://github.com/mailhog/mhsendmail/releases/download/v0.2.0/mhsendmail_linux_amd64 /usr/local/bin/mhsendmail +RUN chmod +x /usr/local/bin/mhsendmail + +# Added FPM health check script (https://github.com/renatomefi/php-fpm-healthcheck) +ADD https://raw.githubusercontent.com/renatomefi/php-fpm-healthcheck/master/php-fpm-healthcheck /usr/local/bin/php-fpm-healthcheck +RUN chmod +x /usr/local/bin/php-fpm-healthcheck + +# Add git global config +COPY gitconfig /root/.gitconfig + +############# SETUP APPLICATION ############# + +# Move site into the container. +ADD https://github.com/os2display/display-api-service/archive/${APP_VERSION}.tar.gz /tmp/app.tar +RUN tar -zxf /tmp/app.tar --strip-components=1 -C ${APP_PATH} \ + && rm /tmp/app.tar + +## Install assets, which requires a HACK as redis is not available (should be removed later on). +RUN APP_ENV=prod composer install --no-dev -o --classmap-authoritative \ + && rm -rf infrastructure \ + && APP_ENV=prod composer clear-cache + +# Install the application. +RUN mkdir -p ${APP_PATH}/config/secrets \ + && chown -R www-data:www-data ${APP_PATH} + +# Copy configuration. +COPY etc /etc/ + +# Install configuration template handler +ADD https://github.com/kelseyhightower/confd/releases/download/v0.16.0/confd-0.16.0-linux-amd64 /usr/local/bin/confd +RUN chmod +x /usr/local/bin/confd + +# Copy confd onfiguration. +COPY etc /etc/ + +COPY docker-entrypoint.sh /usr/local/bin/ +RUN chmod +x /usr/local/bin/docker-entrypoint.sh + +WORKDIR ${APP_PATH} + +CMD [ "docker-entrypoint.sh" ] diff --git a/infrastructure/os2display/display-api-service/docker-entrypoint.sh b/infrastructure/os2display/display-api-service/docker-entrypoint.sh new file mode 100644 index 00000000..0ed90848 --- /dev/null +++ b/infrastructure/os2display/display-api-service/docker-entrypoint.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +set -eux + +## Run templates with configuration. +/usr/local/bin/confd --onetime --backend env --confdir /etc/confd + +## Bump env.local into PHP for better performance. +composer dump-env prod + +## Warm-up Symfony cache (with the current configuration). +/var/www/html/bin/console --env=prod cache:warmup + +# first arg is `-f` or `--some-option` +if [ "${1#-}" != "$1" ]; then + set -- php-fpm "$@" +fi + +## Start the PHP FPM process. +echo "Starting PHP 8.1 FPM" + +exec php-fpm "$@" diff --git a/infrastructure/os2display/display-api-service/etc/confd/conf.d/env.local.toml b/infrastructure/os2display/display-api-service/etc/confd/conf.d/env.local.toml new file mode 100644 index 00000000..e7f303a3 --- /dev/null +++ b/infrastructure/os2display/display-api-service/etc/confd/conf.d/env.local.toml @@ -0,0 +1,8 @@ +[template] +src = "env.local.tmpl" +dest = "/var/www/html/.env.local" +owner = "www-data" +mode = "0644" +keys = [ + "/app-config" +] diff --git a/infrastructure/os2display/display-api-service/etc/confd/templates/env.local.tmpl b/infrastructure/os2display/display-api-service/etc/confd/templates/env.local.tmpl new file mode 100644 index 00000000..5a24a362 --- /dev/null +++ b/infrastructure/os2display/display-api-service/etc/confd/templates/env.local.tmpl @@ -0,0 +1,44 @@ +###> symfony/framework-bundle ### +APP_ENV={{ getenv "APP_ENV" "prod" }} +APP_SECRET={{ getenv "APP_SECRET" "MySuperSecret" }} +TRUSTED_PROXIES={{ getenv "APP_TRUSTED_PROXIES" "127.0.0.1,REMOTE_ADDR" }} +###< symfony/framework-bundle ### + +###> doctrine/doctrine-bundle ### +DATABASE_URL={{ getenv "APP_DATABASE_URL" "mysql://db:db@mariadb:3306/db?serverVersion=mariadb-10.4.0" }} +###< doctrine/doctrine-bundle ### + +###> nelmio/cors-bundle ### +CORS_ALLOW_ORIGIN={{ getenv "APP_CORS_ALLOW_ORIGIN" "'^https?://localhost(:[0-9]+)?$'" }} +###< nelmio/cors-bundle ### + +###> App ### +APP_DEFAULT_DATE_FORMAT='{{ getenv "APP_DEFAULT_DATE_FORMAT" "Y-m-d\\TH:i:s\\Z" }}' +###< App ### + +###> lexik/jwt-authentication-bundle ### +JWT_PASSPHRASE={{ getenv "APP_JWT_PASSPHRASE" }} +JWT_TOKEN_TTL={{ getenv "APP_JWT_TOKEN_TTL" "3600" }} +JWT_SCREEN_TOKEN_TTL={{ getenv "APP_JWT_SCREEN_TOKEN_TTL" "3600" }} +###< lexik/jwt-authentication-bundle ### + +###> gesdinet/jwt-refresh-token-bundle ### +JWT_REFRESH_TOKEN_TTL={{ getenv "APP_JWT_REFRESH_TOKEN_TTL" "2592000" }} +JWT_SCREEN_REFRESH_TOKEN_TTL={{ getenv "APP_JWT_SCREEN_REFRESH_TOKEN_TTL" "2592000" }} +###< gesdinet/jwt-refresh-token-bundle ### + +###> itk-dev/openid-connect-bundle ### +# "admin" open id connect configuration variables (values provided by the OIDC IdP) +OIDC_METADATA_URL={{ getenv "APP_OIDC_METADATA_URL" "" }} +OIDC_CLIENT_ID={{ getenv "APP_OIDC_CLIENT_ID" "" }} +OIDC_CLIENT_SECRET={{ getenv "APP_OIDC_CLIENT_SECRET" "" }} +OIDC_REDIRECT_URI={{ getenv "APP_OIDC_REDIRECT_URI" "" }} +OIDC_LEEWAY={{ getenv "APP_OIDC_LEEWAY" "30" }} + +CLI_REDIRECT={{ getenv "APP_CLI_REDIRECT" "" }} +###< itk-dev/openid-connect-bundle ### + +###> redis ### +REDIS_CACHE_PREFIX={{ getenv "APP_CLI_REDIRECT" "DisplayApiService" }} +REDIS_CACHE_DSN={{ getenv "APP_CLI_REDIRECT" "redis://redis:6379/0" }} +###< redis ### diff --git a/infrastructure/os2display/display-api-service/gitconfig b/infrastructure/os2display/display-api-service/gitconfig new file mode 100644 index 00000000..60a3b020 --- /dev/null +++ b/infrastructure/os2display/display-api-service/gitconfig @@ -0,0 +1,9 @@ +[color] + ui = true + +[alias] + branch-name = !git for-each-ref --format='%(refname:short)' `git symbolic-ref HEAD` + lg = log --graph --pretty=format:'%Cred%h%Creset %Cgreen(%cr) -%C(yellow)%d%Creset %s %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative + +[safe] + directory = * \ No newline at end of file diff --git a/infrastructure/os2display/display-api-service/php/apcu.ini b/infrastructure/os2display/display-api-service/php/apcu.ini new file mode 100644 index 00000000..86164be8 --- /dev/null +++ b/infrastructure/os2display/display-api-service/php/apcu.ini @@ -0,0 +1,7 @@ +extension=apcu +apc.enabled=${PHP_APCU_ENABLED} +apc.shm_segments=${PHP_APCU_SEGMENTS} +apc.shm_size=${PHP_APCU_MEMORY_SIZE} + +apc.enable_cli=${PHP_APCU_ENABLED_CLI} +apc.preload_path=${PHP_APCU_PRELOAD_PATH} \ No newline at end of file diff --git a/infrastructure/os2display/display-api-service/php/fpm.ini b/infrastructure/os2display/display-api-service/php/fpm.ini new file mode 100644 index 00000000..49e0aeb4 --- /dev/null +++ b/infrastructure/os2display/display-api-service/php/fpm.ini @@ -0,0 +1,17 @@ +[www] +pm = ${PHP_PM_TYPE} +pm.max_children = ${PHP_PM_MAX_CHILDREN} +pm.start_servers = ${PHP_PM_START_SERVERS} +pm.min_spare_servers = ${PHP_PM_MIN_SPARE_SERVERS} +pm.max_spare_servers = ${PHP_PM_MAX_SPARE_SERVERS} +pm.max_requests = ${PHP_PM_MAX_REQUESTS} + +request_slowlog_timeout = ${PHP_REQUEST_SLOWLOG_TIMEOUT} +slowlog = ${PHP_SLOWLOG} + +; Enable the FPM status page +pm.status_path = /status + +user = ${PHP_USER} +group = ${PHP_GROUP} + diff --git a/infrastructure/os2display/display-api-service/php/opcache.ini b/infrastructure/os2display/display-api-service/php/opcache.ini new file mode 100644 index 00000000..8ff17863 --- /dev/null +++ b/infrastructure/os2display/display-api-service/php/opcache.ini @@ -0,0 +1,15 @@ +zend_extension=opcache.so + +[opcache] +opcache.jit=${PHP_OPCACHE_JIT} + +opcache.enable=${PHP_OPCACHE_ENABLED} +opcache.revalidate_freq=${PHP_OPCACHE_REVALIDATE_FREQ} +opcache.validate_timestamps=${PHP_OPCACHE_VALIDATE_TIMESTAMPS} +opcache.max_accelerated_files=${PHP_OPCACHE_MAX_ACCELERATED_FILES} +opcache.memory_consumption=${PHP_OPCACHE_MEMORY_CONSUMPTION} +opcache.max_wasted_percentage=${PHP_OPCACHE_MAX_WASTED_PERCENTAGE} +opcache.interned_strings_buffer=16 +opcache.fast_shutdown=1 + +opcache.optimization_level=0xFFFFFFEF diff --git a/infrastructure/os2display/display-api-service/php/php.ini b/infrastructure/os2display/display-api-service/php/php.ini new file mode 100644 index 00000000..2bfde2b4 --- /dev/null +++ b/infrastructure/os2display/display-api-service/php/php.ini @@ -0,0 +1,13 @@ +realpath_cache_size = 4096k +realpath_cache_ttl = 600 + +expose_php = Off +max_execution_time = ${PHP_MAX_EXECUTION_TIME} +memory_limit = ${PHP_MEMORY_LIMIT} + +post_max_size = ${PHP_POST_MAX_SIZE} +upload_max_filesize = ${PHP_UPLOAD_MAX_FILESIZE} + +date.timezone = ${PHP_TIMEZONE} + +sendmail_path = ${PHP_SENDMAIL_PATH} diff --git a/infrastructure/os2display/nginx/Dockerfile b/infrastructure/os2display/nginx/Dockerfile new file mode 100644 index 00000000..bc13dcd1 --- /dev/null +++ b/infrastructure/os2display/nginx/Dockerfile @@ -0,0 +1,37 @@ +ARG APP_VERSION="develop" +FROM os2display/display-api-service:${APP_VERSION} as APPLICATION + +FROM nginxinc/nginx-unprivileged:alpine +LABEL maintainer="ITK Dev " +ARG UID=101 +ARG GID=101 + +ENV APP_PATH=/var/www/html + +USER root + +RUN mkdir -p ${APP_PATH}/public + +COPY --from=APPLICATION ${APP_PATH}/public ${APP_PATH}/public + +WORKDIR ${APP_PATH} + +# Copy configuration. +COPY etc /etc/ + +# Install configuration template handler +ADD https://github.com/kelseyhightower/confd/releases/download/v0.16.0/confd-0.16.0-linux-amd64 /usr/local/bin/confd +RUN chmod +x /usr/local/bin/confd + +COPY docker-entrypoint.sh / +RUN chmod +x /docker-entrypoint.sh \ + && chown -R $UID:0 ${APP_PATH} \ + && chmod -R g+w ${APP_PATH} + +USER $UID + +EXPOSE 8080 + +ENTRYPOINT [ "/docker-entrypoint.sh" ] + +CMD ["nginx", "-g", "daemon off;"] diff --git a/infrastructure/os2display/nginx/docker-entrypoint.sh b/infrastructure/os2display/nginx/docker-entrypoint.sh new file mode 100644 index 00000000..978fa9f4 --- /dev/null +++ b/infrastructure/os2display/nginx/docker-entrypoint.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +set -eux + +## Run templates with configuration. +/usr/local/bin/confd --onetime --backend env --confdir /etc/confd + +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then + if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then + entrypoint_log "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" + + entrypoint_log "$0: Looking for shell scripts in /docker-entrypoint.d/" + find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do + case "$f" in + *.envsh) + if [ -x "$f" ]; then + entrypoint_log "$0: Sourcing $f"; + . "$f" + else + # warn on shell scripts without exec bit + entrypoint_log "$0: Ignoring $f, not executable"; + fi + ;; + *.sh) + if [ -x "$f" ]; then + entrypoint_log "$0: Launching $f"; + "$f" + else + # warn on shell scripts without exec bit + entrypoint_log "$0: Ignoring $f, not executable"; + fi + ;; + *) entrypoint_log "$0: Ignoring $f";; + esac + done + + entrypoint_log "$0: Configuration complete; ready for start up" + else + entrypoint_log "$0: No files found in /docker-entrypoint.d/, skipping configuration" + fi +fi + +exec "$@" diff --git a/infrastructure/os2display/nginx/etc/confd/conf.d/default.conf.toml b/infrastructure/os2display/nginx/etc/confd/conf.d/default.conf.toml new file mode 100644 index 00000000..185954f0 --- /dev/null +++ b/infrastructure/os2display/nginx/etc/confd/conf.d/default.conf.toml @@ -0,0 +1,7 @@ +[template] +src = "default.conf.tmpl" +dest = "/etc/nginx/conf.d/default.conf" +mode = "0644" +keys = [ + "/nginx-config" +] diff --git a/infrastructure/os2display/nginx/etc/confd/conf.d/nginx.conf.toml b/infrastructure/os2display/nginx/etc/confd/conf.d/nginx.conf.toml new file mode 100644 index 00000000..7c81a661 --- /dev/null +++ b/infrastructure/os2display/nginx/etc/confd/conf.d/nginx.conf.toml @@ -0,0 +1,7 @@ +[template] +src = "nginx.conf.tmpl" +dest = "/etc/nginx/nginx.conf" +mode = "0644" +keys = [ + "/nginx-config" +] diff --git a/infrastructure/os2display/nginx/etc/confd/templates/default.conf.tmpl b/infrastructure/os2display/nginx/etc/confd/templates/default.conf.tmpl new file mode 100644 index 00000000..b6f32099 --- /dev/null +++ b/infrastructure/os2display/nginx/etc/confd/templates/default.conf.tmpl @@ -0,0 +1,52 @@ +# @see https://symfony.com/doc/current/setup/web_server_configuration.html +server { + listen 8080; + server_name localhost; + root /var/www/html/public; + + location / { + add_header X-Robots-Tag "noindex, nofollow, nosnippet, noarchive"; + + # try to serve file directly, fallback to index.php + try_files $uri /index.php$is_args$args; + } + + location = /robots.txt { + add_header Content-Type text/plain; + add_header X-Robots-Tag "noindex, nofollow, nosnippet, noarchive"; + return 200 "User-agent: *\nDisallow: /\n"; + } + + location ~ ^/index\.php(/|$) { + fastcgi_pass {{ getenv "PHP_FPM_SERVER" "phpfpm" }}:{{ getenv "PHP_FPM_SERVER_PORT" "9000" }}; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + include fastcgi_params; + + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT $realpath_root; + + internal; + } + + # return 404 for all other php files not matching the front controller + # this prevents access to other php files you don't want to be accessible. + location ~ \.php$ { + return 404; + } + + error_log /var/log/nginx/error.log; + access_log /var/log/nginx/access.log; +} + +server { + listen 8080; + server_name localhost; + root /var/www/html/public; + + error_log off; + access_log off; + + location /stub_status { + stub_status; + } +} diff --git a/infrastructure/os2display/nginx/etc/confd/templates/nginx.conf.tmpl b/infrastructure/os2display/nginx/etc/confd/templates/nginx.conf.tmpl new file mode 100644 index 00000000..6e77365d --- /dev/null +++ b/infrastructure/os2display/nginx/etc/confd/templates/nginx.conf.tmpl @@ -0,0 +1,48 @@ +worker_processes auto; + +error_log /var/log/nginx/error.log warn; +pid /tmp/nginx.pid; + +events { + worker_connections 2048; + multi_accept on; +} + + +http { + open_file_cache max=10000 inactive=5m; + open_file_cache_valid 5m; + open_file_cache_min_uses 5; + open_file_cache_errors off; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 15 15; + types_hash_max_size 2048; + + server_tokens off; + + client_max_body_size {{ getenv "NGINX_FPM_UPLOAD_MAX" "8M" }}; + + gzip on; + gzip_disable "msie6"; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_http_version 1.0; + gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + error_log /dev/stderr; + access_log /dev/stdout main; + + include /etc/nginx/conf.d/*.conf; +} diff --git a/infrastructure/os2display/run.sh b/infrastructure/os2display/run.sh new file mode 100755 index 00000000..ae23d67b --- /dev/null +++ b/infrastructure/os2display/run.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +set -eux + +APP_VERSION=develop + +docker pull nginxinc/nginx-unprivileged:alpine + +docker build --pull --no-cache --build-arg APP_VERSION=${APP_VERSION} --tag=os2display/display-api-service:${APP_VERSION} --file="display-api-service/Dockerfile" display-api-service +docker build --no-cache --build-arg VERSION=${APP_VERSION} --tag=os2display/display-api-service-nginx:${APP_VERSION} --file="nginx/Dockerfile" nginx + +# docker push os2display/display-api-service:${APP_VERSION} +# docker push os2display/display-api-service-nginx:${APP_VERSION} diff --git a/psalm.xml b/psalm.xml index 981db69a..3e925d24 100644 --- a/psalm.xml +++ b/psalm.xml @@ -21,7 +21,7 @@ - + diff --git a/public/api-spec-v1.json b/public/api-spec-v1.json index bbf8535c..d6fa1161 100755 --- a/public/api-spec-v1.json +++ b/public/api-spec-v1.json @@ -8809,10 +8809,6 @@ "description": "The hashed password", "type": "string" }, - "activeTenant": { - "type": "string", - "format": "iri-reference" - }, "userRoleTenants": { "type": "array", "items": { @@ -8822,6 +8818,10 @@ "provider": { "type": "string" }, + "activeTenant": { + "type": "string", + "format": "iri-reference" + }, "userIdentifier": { "readOnly": true, "description": "A visual identifier that represents this user.", @@ -8934,10 +8934,6 @@ "description": "The hashed password", "type": "string" }, - "activeTenant": { - "type": "string", - "format": "iri-reference" - }, "userRoleTenants": { "type": "array", "items": { @@ -8947,6 +8943,10 @@ "provider": { "type": "string" }, + "activeTenant": { + "type": "string", + "format": "iri-reference" + }, "userIdentifier": { "readOnly": true, "description": "A visual identifier that represents this user.", diff --git a/public/api-spec-v1.yaml b/public/api-spec-v1.yaml index 38d6ac9b..bc110a67 100755 --- a/public/api-spec-v1.yaml +++ b/public/api-spec-v1.yaml @@ -6218,15 +6218,15 @@ components: password: description: 'The hashed password' type: string - activeTenant: - type: string - format: iri-reference userRoleTenants: type: array items: $ref: '#/components/schemas/UserRoleTenant' provider: type: string + activeTenant: + type: string + format: iri-reference userIdentifier: readOnly: true description: 'A visual identifier that represents this user.' @@ -6309,15 +6309,15 @@ components: password: description: 'The hashed password' type: string - activeTenant: - type: string - format: iri-reference userRoleTenants: type: array items: $ref: '#/components/schemas/UserRoleTenant.jsonld' provider: type: string + activeTenant: + type: string + format: iri-reference userIdentifier: readOnly: true description: 'A visual identifier that represents this user.' diff --git a/src/Command/CreateFeedSourceCommand.php b/src/Command/Feed/CreateFeedSourceCommand.php similarity index 94% rename from src/Command/CreateFeedSourceCommand.php rename to src/Command/Feed/CreateFeedSourceCommand.php index ec10a29b..511f0ad3 100644 --- a/src/Command/CreateFeedSourceCommand.php +++ b/src/Command/Feed/CreateFeedSourceCommand.php @@ -1,6 +1,6 @@ getArgument('ulid'); - - if ($ulid) { + if (!is_null($ulid)) { $io->writeln("Overriding FeedSource with ULID: $ulid"); } + // Ask user for feed type base on available types. $feedTypes = $this->feedService->getFeedTypes(); - $question = new Question('Select feed type (autocompletes)'); $question->setAutocompleterValues($feedTypes); $feedTypeClassname = $io->askQuestion($question); - if (!$feedTypeClassname) { $io->error('Feed type must be set.'); @@ -61,9 +60,9 @@ final protected function execute(InputInterface $input, OutputInterface $output) $io->info("Selected feed type: $feedTypeClassname"); $feedType = $this->feedService->getFeedType($feedTypeClassname); - $tenants = $this->tenantRepository->findAll(); + // Ask user for which tenant to use. $question = new Question('Which tenant should the feed source be added to?'); $question->setAutocompleterValues(array_reduce($tenants, function (array $carry, Tenant $tenant) { $carry[$tenant->getTenantKey()] = $tenant->getTenantKey(); @@ -71,25 +70,20 @@ final protected function execute(InputInterface $input, OutputInterface $output) return $carry; }, [])); $tenantSelected = $io->askQuestion($question); - if (empty($tenantSelected)) { $io->error('No tenant selected. Aborting.'); return Command::INVALID; } - $tenant = $this->tenantRepository->findOneBy(['tenantKey' => $tenantSelected]); - if (null == $tenant) { $io->error('Tenant not found.'); return Command::INVALID; } - $io->info("Feed source will be added to $tenantSelected tenant."); $title = $io->ask('Enter title for feed source'); - if (!$title) { $io->error('Title must be set.'); @@ -99,11 +93,8 @@ final protected function execute(InputInterface $input, OutputInterface $output) $description = $io->ask('Describe feed source'); $secrets = []; - $io->info('Set required secrets.'); - $requiredSecrets = $feedType->getRequiredSecrets(); - foreach ($requiredSecrets as $requiredSecret) { $value = null; do { @@ -139,7 +130,7 @@ final protected function execute(InputInterface $input, OutputInterface $output) $feedSource->setDescription($description); $feedSource->setFeedType($feedTypeClassname); $feedSource->setSecrets($secrets); - $feedSource->setSupportedFeedOutputType($feedType->getsupportedFeedOutputType()); + $feedSource->setSupportedFeedOutputType($feedType->getSupportedFeedOutputType()); $feedSource->setTenant($tenant); $secretsString = implode(array_map(function ($key) use ($secrets) { @@ -162,6 +153,7 @@ final protected function execute(InputInterface $input, OutputInterface $output) return Command::FAILURE; } + // Persist new feed source to the database. $this->entityManager->persist($feedSource); $this->entityManager->flush(); diff --git a/src/Command/GetFeedTypesCommand.php b/src/Command/Feed/GetFeedTypesCommand.php similarity index 97% rename from src/Command/GetFeedTypesCommand.php rename to src/Command/Feed/GetFeedTypesCommand.php index 4389a96f..be477931 100644 --- a/src/Command/GetFeedTypesCommand.php +++ b/src/Command/Feed/GetFeedTypesCommand.php @@ -1,6 +1,6 @@ confirm("Are you sure you want to remove the feed source. $feedsCount feeds will be removed as well."); foreach ($feeds as $feed) { - $feed->getSlide()->setFeed(null); + $feed->getSlide()?->setFeed(null); } $this->entityManager->remove($feedSource); diff --git a/src/Command/LoadScreenLayoutsCommand.php b/src/Command/Screen/LoadScreenLayoutsCommand.php similarity index 99% rename from src/Command/LoadScreenLayoutsCommand.php rename to src/Command/Screen/LoadScreenLayoutsCommand.php index d7f42758..3a1ff09c 100644 --- a/src/Command/LoadScreenLayoutsCommand.php +++ b/src/Command/Screen/LoadScreenLayoutsCommand.php @@ -1,6 +1,6 @@ getArgument('title') ?? ''; $description = $input->getArgument('description') ?? ''; - // make sure to validate the user data is correct + // Make sure to validate the user data is correct. + if (null == $tenantKey) { + throw new RuntimeException('Tenant key should not be null'); + } $this->validateTenantData($tenantKey); - // create the user and hash its password + // Create the user and hash its password. $tenant = new Tenant(); $tenant->setTenantKey($tenantKey); $tenant->setTitle($title); @@ -175,7 +178,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $event = $stopwatch->stop('add-tenant-command'); if ($output->isVerbose()) { - $this->io->comment(sprintf('New tenant database id: %d / Elapsed time: %.2f ms / Consumed memory: %.2f MB', $tenant->getId(), $event->getDuration(), $event->getMemory() / (1024 ** 2))); + $id = $tenant->getId()?->jsonSerialize(); + $this->io->comment(sprintf('New tenant database id: %d / Elapsed time: %.2f ms / Consumed memory: %.2f MB', $id ?? '0', $event->getDuration(), $event->getMemory() / (1024 ** 2))); } return Command::SUCCESS; @@ -183,21 +187,21 @@ protected function execute(InputInterface $input, OutputInterface $output): int private function validateTenantData(string $tenantKey): void { - // first check if a user with the same username already exists. + // First check if a user with the same username already exists. $existingTenant = $this->tenants->findOneBy(['tenantKey' => $tenantKey]); if (null !== $existingTenant) { throw new RuntimeException(sprintf('There is already a tenant registered with the "%s" key.', $tenantKey)); } - // validate tenant key if is not this input means interactive. + // Validate tenant key if is not this input means interactive. $this->validator->validateTenantKey($tenantKey); } /** - * The command help is usually included in the configure() method, but when - * it's too long, it's better to define a separate method to maintain the - * code readability. + * The command help is usually included in the configure() method. + * + * But when it's too long, it's better to define a separate method to maintain the code readability. */ private function getCommandHelp(): string { diff --git a/src/Command/ConfigureTenantCommand.php b/src/Command/Tenant/ConfigureTenantCommand.php similarity index 98% rename from src/Command/ConfigureTenantCommand.php rename to src/Command/Tenant/ConfigureTenantCommand.php index d3e78ce8..a14b2b2e 100644 --- a/src/Command/ConfigureTenantCommand.php +++ b/src/Command/Tenant/ConfigureTenantCommand.php @@ -1,6 +1,6 @@ addArgument('email', InputArgument::OPTIONAL, 'The email of the new user') ->addArgument('password', InputArgument::OPTIONAL, 'The plain password of the new user') ->addArgument('full-name', InputArgument::OPTIONAL, 'The full name of the new user') - ->addOption('admin', null, InputOption::VALUE_NONE, 'If set, the user is created as an administrator') + ->addArgument('role', InputArgument::OPTIONAL, 'The role of the user [editor|admin]') + ->addArgument('tenant-keys', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'The keys of the tenants the user should belong to (separate multiple keys with a space)') ; } /** - * This optional method is the first one executed for a command after configure() - * and is useful to initialize properties based on the input arguments and options. + * This optional method is the first one executed for a command after configure(). + * + * It is useful to initialize properties based on the input arguments and options. */ protected function initialize(InputInterface $input, OutputInterface $output): void { @@ -108,7 +111,12 @@ protected function initialize(InputInterface $input, OutputInterface $output): v */ protected function interact(InputInterface $input, OutputInterface $output): void { - if (null !== $input->getArgument('email') && null !== $input->getArgument('password') && null !== $input->getArgument('full-name')) { + if (null !== $input->getArgument('email') && + null !== $input->getArgument('password') && + null !== $input->getArgument('full-name') && + null !== $input->getArgument('role') && + null !== $input->getArgument('tenant-keys') + ) { return; } @@ -148,6 +156,39 @@ protected function interact(InputInterface $input, OutputInterface $output): voi $fullName = $this->io->ask('Full Name', null, [$this->validator, 'validateFullName']); $input->setArgument('full-name', $fullName); } + + $helper = $this->getHelper('question'); + + // Ask for the role if it's not defined + $role = $input->getArgument('role'); + if (null !== $role) { + $this->io->text(' > Role: '.$role); + } else { + $question = new ChoiceQuestion( + 'Please select the user\'s role (defaults to editor)', + CommandInputValidator::ALLOWED_USER_ROLES, + 0 + ); + $question->setErrorMessage('Role %s is invalid.'); + + $role = $helper->ask($input, $output, $question); + $output->writeln('You have just selected: '.$role); + } + + // Ask for the tenant keys if it's not defined + $tenantKeys = $input->getArgument('tenant-keys'); + if (0 < \count($tenantKeys)) { + $this->io->text(' > Tenant Keys: '.$tenantKeys); + } else { + $question = new ChoiceQuestion( + 'Please select the tenant(s) the user should belong to (to select multiple answer with a list. E.g: "key1, key3")', + $this->getTenantsChoiceList(), + ); + $question->setMultiselect(true); + + $tenantKeys = $helper->ask($input, $output, $question); + $output->writeln('You have just selected: '.implode(', ', $tenantKeys)); + } } /** @@ -162,10 +203,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int $email = $input->getArgument('email'); $plainPassword = $input->getArgument('password'); $fullName = $input->getArgument('full-name'); - $isAdmin = $input->getOption('admin'); + $role = $input->getArgument('role'); + $tenantKeys = $input->getArgument('tenant-keys'); // make sure to validate the user data is correct - $this->validateUserData($email, $plainPassword, $fullName); + $this->validateUserData($email, $plainPassword, $fullName, $role, $tenantKeys); // create the user and hash its password $user = new User(); @@ -178,19 +220,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int $hashedPassword = $this->passwordHasher->hashPassword($user, $plainPassword); $user->setPassword($hashedPassword); - // @TODO Make it possible to only select specific Tenants - $tenants = $this->tenants->findAll(); - foreach ($tenants as $tenant) { + foreach ($tenantKeys as $tenantKey) { + $tenant = $this->tenantRepository->findOneBy(['tenantKey' => $tenantKey]); $userRoleTenant = new UserRoleTenant(); $userRoleTenant->setTenant($tenant); - $userRoleTenant->setRoles([$isAdmin ? 'ROLE_ADMIN' : 'ROLE_EDITOR']); + $userRoleTenant->setRoles(['ROLE_'.strtoupper($role)]); $user->addUserRoleTenant($userRoleTenant); } $this->entityManager->persist($user); $this->entityManager->flush(); - $this->io->success(sprintf('%s was successfully created: %s', $isAdmin ? 'Administrator user' : 'User', $user->getUserIdentifier())); + $this->io->success(sprintf('%s was successfully created: %s', ucfirst($role), $user->getUserIdentifier())); $event = $stopwatch->stop('add-user-command'); if ($output->isVerbose()) { @@ -200,7 +241,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return Command::SUCCESS; } - private function validateUserData($email, $plainPassword, $fullName): void + private function validateUserData($email, $plainPassword, $fullName, $role, $tenantKeys): void { // first check if a user with the same username already exists. $existingUser = $this->users->findOneBy(['email' => $email]); @@ -213,6 +254,19 @@ private function validateUserData($email, $plainPassword, $fullName): void $this->validator->validatePassword($plainPassword); $this->validator->validateEmail($email); $this->validator->validateFullName($fullName); + $this->validator->validateRole($role); + $this->validator->validateTenantKeys($tenantKeys); + } + + private function getTenantsChoiceList(): array + { + $tenants = []; + /** @var Tenant $tenant */ + foreach ($this->tenantRepository->findBy([], ['tenantKey' => 'ASC']) as $tenant) { + $tenants[$tenant->getTenantKey()] = $tenant->getDescription(); + } + + return $tenants; } /** @@ -225,17 +279,12 @@ private function getCommandHelp(): string return <<<'HELP' The %command.name% command creates new users and saves them in the database: - php %command.full_name% email password - -By default the command creates regular users. To create administrator users, -add the --admin option: - - php %command.full_name% email password --admin + php %command.full_name% email password fullname role tenants -If you omit any of the two required arguments, the command will ask you to +If you omit any of the required arguments, the command will ask you to provide the missing values: - # command will ask you for the password + # command will ask you for the password etc. php %command.full_name% email # command will ask you for all arguments diff --git a/src/Controller/FeedSourceConfigGetController.php b/src/Controller/FeedSourceConfigGetController.php index c7157eca..eb8c6154 100644 --- a/src/Controller/FeedSourceConfigGetController.php +++ b/src/Controller/FeedSourceConfigGetController.php @@ -28,6 +28,11 @@ public function __invoke(Request $request, string $id, string $name): JsonRespon return new JsonResponse([], 404); } - return new JsonResponse($this->feedService->getConfigOptions($request, $feedSource, $name), 200); + $config = $this->feedService->getConfigOptions($request, $feedSource, $name); + if (is_null($config)) { + return new JsonResponse($config, 404); + } + + return new JsonResponse($config, 200); } } diff --git a/src/DataProvider/CampaignScreenCollectionDataProvider.php b/src/DataProvider/CampaignScreenCollectionDataProvider.php index faddb894..7a913472 100644 --- a/src/DataProvider/CampaignScreenCollectionDataProvider.php +++ b/src/DataProvider/CampaignScreenCollectionDataProvider.php @@ -11,12 +11,10 @@ use App\Utils\ValidationUtils; use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Security\Core\Security; final class CampaignScreenCollectionDataProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface { public function __construct( - private Security $security, private RequestStack $requestStack, private ScreenCampaignRepository $screenCampaignRepository, private ValidationUtils $validationUtils, @@ -30,26 +28,26 @@ public function supports(string $resourceClass, string $operationName = null, ar public function getCollection(string $resourceClass, string $operationName = null, array $context = []): Paginator { - $itemsPerPage = (int) $this->requestStack->getCurrentRequest()->query->get('itemsPerPage', '10'); - $page = (int) $this->requestStack->getCurrentRequest()->query->get('page', '1'); - $id = $this->requestStack->getCurrentRequest()->attributes->get('id'); + $currentRequest = $this->requestStack->getCurrentRequest(); + $itemsPerPage = $currentRequest->query?->get('itemsPerPage') ?? 10; + $page = $currentRequest->query?->get('page') ?? 1; + $id = $currentRequest->attributes?->get('id') ?? ''; + $queryNameGenerator = new QueryNameGenerator(); $campaignId = $this->validationUtils->validateUlid($id); // Get playlist to check shared-with-tenants $queryBuilder = $this->screenCampaignRepository->getScreensBasedOnCampaign($campaignId); + // Filter the query-builder with tenant extension. foreach ($this->collectionExtensions as $extension) { $extension->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName, $context); - if ($extension instanceof QueryResultItemExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) { - return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context); - } } - $firstResult = ($page - 1) * $itemsPerPage; + $firstResult = ((int) $page - 1) * (int) $itemsPerPage; $query = $queryBuilder->getQuery() ->setFirstResult($firstResult) - ->setMaxResults($itemsPerPage); + ->setMaxResults((int) $itemsPerPage); $doctrinePaginator = new DoctrinePaginator($query); diff --git a/src/DataProvider/CampaignScreenGroupCollectionDataProvider.php b/src/DataProvider/CampaignScreenGroupCollectionDataProvider.php index 66a3d4a6..7f17a2ba 100644 --- a/src/DataProvider/CampaignScreenGroupCollectionDataProvider.php +++ b/src/DataProvider/CampaignScreenGroupCollectionDataProvider.php @@ -11,12 +11,10 @@ use App\Utils\ValidationUtils; use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Security\Core\Security; final class CampaignScreenGroupCollectionDataProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface { public function __construct( - private Security $security, private RequestStack $requestStack, private ScreenGroupCampaignRepository $screenGroupCampaignRepository, private ValidationUtils $validationUtils, @@ -30,25 +28,23 @@ public function supports(string $resourceClass, string $operationName = null, ar public function getCollection(string $resourceClass, string $operationName = null, array $context = []): Paginator { - $itemsPerPage = (int) $this->requestStack->getCurrentRequest()->query->get('itemsPerPage', '10'); - $page = (int) $this->requestStack->getCurrentRequest()->query->get('page', '1'); - $id = $this->requestStack->getCurrentRequest()->attributes->get('id'); + $itemsPerPage = $this->requestStack->getCurrentRequest()->query?->get('itemsPerPage') ?? 10; + $page = $this->requestStack->getCurrentRequest()?->query->get('page') ?? 1; + $id = $this->requestStack->getCurrentRequest()?->attributes->get('id') ?? ''; $queryNameGenerator = new QueryNameGenerator(); $campaignUlid = $this->validationUtils->validateUlid($id); $queryBuilder = $this->screenGroupCampaignRepository->getScreenGroupsFromCampaignId($campaignUlid); + // Filter the query-builder with tenant extension. foreach ($this->collectionExtensions as $extension) { $extension->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName, $context); - if ($extension instanceof QueryResultItemExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) { - return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context); - } } - $firstResult = ($page - 1) * $itemsPerPage; + $firstResult = ((int) $page - 1) * (int) $itemsPerPage; $query = $queryBuilder->getQuery() ->setFirstResult($firstResult) - ->setMaxResults($itemsPerPage); + ->setMaxResults((int) $itemsPerPage); $doctrinePaginator = new DoctrinePaginator($query); diff --git a/src/DataProvider/FeedDataProvider.php b/src/DataProvider/FeedDataProvider.php index c02530e4..f7fc1ed5 100644 --- a/src/DataProvider/FeedDataProvider.php +++ b/src/DataProvider/FeedDataProvider.php @@ -6,23 +6,29 @@ use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface; use App\Entity\Tenant\Feed; +use App\Entity\User; +use App\Exceptions\MissingFeedConfigurationException; use App\Repository\FeedRepository; use App\Repository\PlaylistSlideRepository; -use App\Repository\SlideRepository; use App\Service\FeedService; -use App\Utils\ValidationUtils; +use Doctrine\ORM\NonUniqueResultException; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Security\Core\Security; +use Symfony\Component\Uid\Ulid; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; final class FeedDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface { public function __construct( private Security $security, - private SlideRepository $slideRepository, private PlaylistSlideRepository $playlistSlideRepository, private FeedRepository $feedRepository, private FeedService $feedService, - private ValidationUtils $validationUtils, + private LoggerInterface $logger, private iterable $itemExtensions = [] ) {} @@ -31,45 +37,70 @@ public function supports(string $resourceClass, string $operationName = null, ar return Feed::class === $resourceClass; } - public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): JsonResponse|Feed|null + public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): ?JsonResponse { + if (!$id instanceof Ulid) { + return null; + } + $queryNameGenerator = new QueryNameGenerator(); - $user = $this->security->getUser(); - $tenant = $user->getActiveTenant(); - $feedUlid = $this->validationUtils->validateUlid($id); - // Create a querybuilder, as the tenant filter works on querybuilders. - $queryBuilder = $this->feedRepository->getById($feedUlid); + // Create a query builder, as the tenant filter works on query builders. + $queryBuilder = $this->feedRepository->getById($id); + + $identifiers = ['id' => $id]; - // Filter the querybuilder with tenantextension + // Filter the query builder with tenant extension. foreach ($this->itemExtensions as $extension) { - $identifiers = ['id' => $id]; $extension->applyToItem($queryBuilder, $queryNameGenerator, $resourceClass, $identifiers, $operationName, $context); - if ($extension instanceof QueryResultItemExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) { - return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context); - } } // Get result. If there is a result this is returned. - $feed = $queryBuilder->getQuery()->getOneOrNullResult(); + try { + $feed = $queryBuilder->getQuery()->getOneOrNullResult(); + } catch (NonUniqueResultException $exception) { + return null; + } // If there is not a result, shared playlists should be checked. if (is_null($feed)) { - $notAccessibleFeed = $this->feedRepository->find($feedUlid); - $slide = $notAccessibleFeed->getSlide(); - $playlists = $this->playlistSlideRepository->getPlaylistsFromSlideId($slide->getId())->getQuery()->getResult(); - foreach ($playlists as $ps) { - if (in_array($tenant, $ps->getPlaylist()->getTenants()->toArray())) { - $feed = $notAccessibleFeed; - break; + $user = $this->security->getUser(); + if (!is_null($user)) { + /** @var User $user */ + $tenant = $user->getActiveTenant(); + + $notAccessibleFeed = $this->feedRepository->find($id); + if (!is_null($notAccessibleFeed)) { + $slide = $notAccessibleFeed->getSlide(); + $slideId = $slide?->getId(); + if (!is_null($slideId)) { + $playlists = $this->playlistSlideRepository->getPlaylistsFromSlideId($slideId)->getQuery()->getResult(); + foreach ($playlists as $playlist) { + if (in_array($tenant, $playlist->getPlaylist()->getTenants()->toArray())) { + $feed = $notAccessibleFeed; + break; + } + } + } } } } - if ('get' === $operationName || is_null($feed)) { - return $feed; - } elseif ('get_feed_data' === $operationName) { - return new JsonResponse($this->feedService->getData($feed), 200); + if (!is_null($feed)) { + try { + if ('get' === $operationName || 'get_feed_data' === $operationName) { + return new JsonResponse($this->feedService->getData($feed), 200); + } + } catch (MissingFeedConfigurationException $e) { + $this->logger->error(sprintf('Missing configuration for feed with id "%s" with message "%"', $feed->getId()->jsonSerialize(), $e->getMessage())); + } catch (\JsonException $e) { + $this->logger->error(sprintf('JSON decode for feed with id "%s" with error "%s"', $feed->getId()->jsonSerialize(), $e->getMessage())); + } catch (ClientExceptionInterface|RedirectionExceptionInterface|ServerExceptionInterface|TransportExceptionInterface $e) { + $this->logger->error(sprintf('Communication error "%s"', $e->getMessage())); + } } + + // Null returned for data provider will result in a 404 response from API platform. + return null; } } diff --git a/src/DataProvider/MediaItemDataProvider.php b/src/DataProvider/MediaItemDataProvider.php index d4faad42..fc3254b4 100644 --- a/src/DataProvider/MediaItemDataProvider.php +++ b/src/DataProvider/MediaItemDataProvider.php @@ -6,6 +6,7 @@ use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface; use App\Entity\Tenant\Media; +use App\Entity\User; use App\Repository\MediaRepository; use App\Repository\PlaylistSlideRepository; use App\Repository\SlideRepository; @@ -30,8 +31,14 @@ public function supports(string $resourceClass, string $operationName = null, ar public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): ?Media { - $queryNameGenerator = new QueryNameGenerator(); $user = $this->security->getUser(); + if (is_null($user)) { + return null; + } + + $queryNameGenerator = new QueryNameGenerator(); + + /** @var User $user */ $tenant = $user->getActiveTenant(); $mediaUlid = $this->validationUtils->validateUlid($id); @@ -42,9 +49,6 @@ public function getItem(string $resourceClass, $id, string $operationName = null foreach ($this->itemExtensions as $extension) { $identifiers = ['id' => $id]; $extension->applyToItem($queryBuilder, $queryNameGenerator, $resourceClass, $identifiers, $operationName, $context); - if ($extension instanceof QueryResultItemExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) { - return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context); - } } // Get result. If there is a result this is returned. @@ -57,7 +61,7 @@ public function getItem(string $resourceClass, $id, string $operationName = null // If there is not a result, shared playlists should be checked. if (is_null($media)) { - $connectedSlides = $this->slideRepository->getSlidesByMedia($id)->getQuery()->getResult(); + $connectedSlides = $this->slideRepository->getSlidesByMedia($mediaUlid)->getQuery()->getResult(); foreach ($connectedSlides as $slide) { $playlists = $this->playlistSlideRepository->getPlaylistsFromSlideId($slide->getId())->getQuery()->getResult(); foreach ($playlists as $playlist) { diff --git a/src/DataProvider/PlaylistScreenRegionCollectionDataProvider.php b/src/DataProvider/PlaylistScreenRegionCollectionDataProvider.php index f3cc2dc9..b3fe5d27 100644 --- a/src/DataProvider/PlaylistScreenRegionCollectionDataProvider.php +++ b/src/DataProvider/PlaylistScreenRegionCollectionDataProvider.php @@ -11,12 +11,10 @@ use App\Utils\ValidationUtils; use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Security\Core\Security; final class PlaylistScreenRegionCollectionDataProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface { public function __construct( - private Security $security, private RequestStack $requestStack, private PlaylistScreenRegionRepository $playlistScreenRegionRepository, private ValidationUtils $validationUtils, @@ -30,10 +28,10 @@ public function supports(string $resourceClass, string $operationName = null, ar public function getCollection(string $resourceClass, string $operationName = null, array $context = []): Paginator { - $itemsPerPage = (int) $this->requestStack->getCurrentRequest()->query->get('itemsPerPage', '10'); - $page = (int) $this->requestStack->getCurrentRequest()->query->get('page', '1'); - $id = $this->requestStack->getCurrentRequest()->attributes->get('id'); - $regionId = $this->requestStack->getCurrentRequest()->attributes->get('regionId'); + $itemsPerPage = $this->requestStack->getCurrentRequest()->query?->get('itemsPerPage') ?? 10; + $page = $this->requestStack->getCurrentRequest()->query?->get('page') ?? 1; + $id = $this->requestStack->getCurrentRequest()->attributes?->get('id') ?? ''; + $regionId = $this->requestStack->getCurrentRequest()->attributes?->get('regionId') ?? ''; $queryNameGenerator = new QueryNameGenerator(); $screenUlid = $this->validationUtils->validateUlid($id); @@ -41,17 +39,15 @@ public function getCollection(string $resourceClass, string $operationName = nul $queryBuilder = $this->playlistScreenRegionRepository->getPlaylistsByScreenRegion($screenUlid, $regionUlid); + // Filter the query-builder with tenant extension. foreach ($this->collectionExtensions as $extension) { $extension->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName, $context); - if ($extension instanceof QueryResultItemExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) { - return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context); - } } - $firstResult = ($page - 1) * $itemsPerPage; + $firstResult = ((int) $page - 1) * (int) $itemsPerPage; $query = $queryBuilder->getQuery() ->setFirstResult($firstResult) - ->setMaxResults($itemsPerPage); + ->setMaxResults((int) $itemsPerPage); $doctrinePaginator = new DoctrinePaginator($query); diff --git a/src/DataProvider/PlaylistSlideCollectionDataProvider.php b/src/DataProvider/PlaylistSlideCollectionDataProvider.php index 97a72349..0fcc97bc 100644 --- a/src/DataProvider/PlaylistSlideCollectionDataProvider.php +++ b/src/DataProvider/PlaylistSlideCollectionDataProvider.php @@ -7,6 +7,7 @@ use ApiPlatform\Core\DataProvider\ContextAwareCollectionDataProviderInterface; use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface; use App\Entity\Tenant\PlaylistSlide; +use App\Entity\User; use App\Repository\PlaylistRepository; use App\Repository\PlaylistSlideRepository; use App\Utils\ValidationUtils; @@ -32,32 +33,31 @@ public function supports(string $resourceClass, string $operationName = null, ar public function getCollection(string $resourceClass, string $operationName = null, array $context = []): Paginator { - $itemsPerPage = (int) $this->requestStack->getCurrentRequest()->query->get('itemsPerPage', '10'); - $page = (int) $this->requestStack->getCurrentRequest()->query->get('page', '1'); - $id = $this->requestStack->getCurrentRequest()->attributes->get('id'); + $itemsPerPage = $this->requestStack->getCurrentRequest()->query?->get('itemsPerPage') ?? 10; + $page = $this->requestStack->getCurrentRequest()->query?->get('page') ?? 1; + $id = $this->requestStack->getCurrentRequest()->attributes?->get('id') ?? ''; $queryNameGenerator = new QueryNameGenerator(); + /** @var User $user */ $user = $this->security->getUser(); $tenant = $user->getActiveTenant(); $playlistUlid = $this->validationUtils->validateUlid($id); // Get playlist to check shared-with-tenants $playlist = $this->playlistRepository->findOneBy(['id' => $playlistUlid]); - $playlistSharedWithTenant = in_array($tenant, $playlist->getTenants()->toArray()); + $playlistSharedWithTenant = in_array($tenant, $playlist?->getTenants()->toArray()); $queryBuilder = $this->playlistSlideRepository->getPlaylistSlideRelationsFromPlaylistId($playlistUlid); if (!$playlistSharedWithTenant) { + // Filter the query-builder with tenant extension. foreach ($this->collectionExtensions as $extension) { $extension->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName, $context); - if ($extension instanceof QueryResultItemExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) { - return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context); - } } } - $firstResult = ($page - 1) * $itemsPerPage; + $firstResult = ((int) $page - 1) * (int) $itemsPerPage; $query = $queryBuilder->getQuery() ->setFirstResult($firstResult) - ->setMaxResults($itemsPerPage); + ->setMaxResults((int) $itemsPerPage); $doctrinePaginator = new DoctrinePaginator($query); diff --git a/src/DataProvider/ScreenCampaignCollectionDataProvider.php b/src/DataProvider/ScreenCampaignCollectionDataProvider.php index cede8d53..c4372b97 100644 --- a/src/DataProvider/ScreenCampaignCollectionDataProvider.php +++ b/src/DataProvider/ScreenCampaignCollectionDataProvider.php @@ -11,12 +11,10 @@ use App\Utils\ValidationUtils; use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Security\Core\Security; final class ScreenCampaignCollectionDataProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface { public function __construct( - private Security $security, private RequestStack $requestStack, private ScreenCampaignRepository $screenCampaignRepository, private ValidationUtils $validationUtils, @@ -30,26 +28,24 @@ public function supports(string $resourceClass, string $operationName = null, ar public function getCollection(string $resourceClass, string $operationName = null, array $context = []): Paginator { - $itemsPerPage = (int) $this->requestStack->getCurrentRequest()->query->get('itemsPerPage', '10'); - $page = (int) $this->requestStack->getCurrentRequest()->query->get('page', '1'); - $id = $this->requestStack->getCurrentRequest()->attributes->get('id'); + $itemsPerPage = $this->requestStack->getCurrentRequest()->query?->get('itemsPerPage') ?? 10; + $page = $this->requestStack->getCurrentRequest()->query?->get('page') ?? 1; + $id = $this->requestStack->getCurrentRequest()->attributes?->get('id') ?? ''; $queryNameGenerator = new QueryNameGenerator(); $screenUlid = $this->validationUtils->validateUlid($id); // Get playlist to check shared-with-tenants $queryBuilder = $this->screenCampaignRepository->getScreenCampaignsBasedOnScreen($screenUlid); + // Filter the query-builder with tenant extension. foreach ($this->collectionExtensions as $extension) { $extension->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName, $context); - if ($extension instanceof QueryResultItemExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) { - return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context); - } } - $firstResult = ($page - 1) * $itemsPerPage; + $firstResult = ((int) $page - 1) * (int) $itemsPerPage; $query = $queryBuilder->getQuery() ->setFirstResult($firstResult) - ->setMaxResults($itemsPerPage); + ->setMaxResults((int) $itemsPerPage); $doctrinePaginator = new DoctrinePaginator($query); diff --git a/src/DataProvider/ScreenGroupCampaignCollectionDataProvider.php b/src/DataProvider/ScreenGroupCampaignCollectionDataProvider.php index 2ada22f4..f9e95eb9 100644 --- a/src/DataProvider/ScreenGroupCampaignCollectionDataProvider.php +++ b/src/DataProvider/ScreenGroupCampaignCollectionDataProvider.php @@ -11,12 +11,10 @@ use App\Utils\ValidationUtils; use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Security\Core\Security; final class ScreenGroupCampaignCollectionDataProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface { public function __construct( - private Security $security, private RequestStack $requestStack, private ScreenGroupCampaignRepository $screenGroupCampaignRepository, private ValidationUtils $validationUtils, @@ -30,25 +28,23 @@ public function supports(string $resourceClass, string $operationName = null, ar public function getCollection(string $resourceClass, string $operationName = null, array $context = []): Paginator { - $itemsPerPage = (int) $this->requestStack->getCurrentRequest()->query->get('itemsPerPage', '10'); - $page = (int) $this->requestStack->getCurrentRequest()->query->get('page', '1'); - $id = $this->requestStack->getCurrentRequest()->attributes->get('id'); + $itemsPerPage = $this->requestStack->getCurrentRequest()->query?->get('itemsPerPage') ?? 10; + $page = $this->requestStack->getCurrentRequest()->query?->get('page') ?? 1; + $id = $this->requestStack->getCurrentRequest()->attributes?->get('id') ?? ''; $queryNameGenerator = new QueryNameGenerator(); $screenGroupUlid = $this->validationUtils->validateUlid($id); $queryBuilder = $this->screenGroupCampaignRepository->getCampaignsFromScreenGroupId($screenGroupUlid); + // Filter the query-builder with tenant extension. foreach ($this->collectionExtensions as $extension) { $extension->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName, $context); - if ($extension instanceof QueryResultItemExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) { - return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context); - } } - $firstResult = ($page - 1) * $itemsPerPage; + $firstResult = ((int) $page - 1) * (int) $itemsPerPage; $query = $queryBuilder->getQuery() ->setFirstResult($firstResult) - ->setMaxResults($itemsPerPage); + ->setMaxResults((int) $itemsPerPage); $doctrinePaginator = new DoctrinePaginator($query); diff --git a/src/DataProvider/ScreenGroupsScreensCollectionDataProvider.php b/src/DataProvider/ScreenGroupsScreensCollectionDataProvider.php index 03781fd6..d082aa98 100644 --- a/src/DataProvider/ScreenGroupsScreensCollectionDataProvider.php +++ b/src/DataProvider/ScreenGroupsScreensCollectionDataProvider.php @@ -11,12 +11,10 @@ use App\Utils\ValidationUtils; use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Security\Core\Security; final class ScreenGroupsScreensCollectionDataProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface { public function __construct( - private Security $security, private RequestStack $requestStack, private ScreenGroupRepository $screenGroupRepository, private ValidationUtils $validationUtils, @@ -30,25 +28,23 @@ public function supports(string $resourceClass, string $operationName = null, ar public function getCollection(string $resourceClass, string $operationName = null, array $context = []): Paginator { - $itemsPerPage = (int) $this->requestStack->getCurrentRequest()->query->get('itemsPerPage', '10'); - $page = (int) $this->requestStack->getCurrentRequest()->query->get('page', '1'); - $id = $this->requestStack->getCurrentRequest()->attributes->get('id'); + $itemsPerPage = $this->requestStack->getCurrentRequest()->query?->get('itemsPerPage') ?? 10; + $page = $this->requestStack->getCurrentRequest()->query?->get('page') ?? 1; + $id = $this->requestStack->getCurrentRequest()->attributes?->get('id') ?? ''; $queryNameGenerator = new QueryNameGenerator(); $screenUlid = $this->validationUtils->validateUlid($id); $queryBuilder = $this->screenGroupRepository->getScreenGroupsByScreenId($screenUlid); + // Filter the query-builder with tenant extension. foreach ($this->collectionExtensions as $extension) { $extension->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName, $context); - if ($extension instanceof QueryResultItemExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) { - return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context); - } } - $firstResult = ($page - 1) * $itemsPerPage; + $firstResult = ((int) $page - 1) * (int) $itemsPerPage; $query = $queryBuilder->getQuery() ->setFirstResult($firstResult) - ->setMaxResults($itemsPerPage); + ->setMaxResults((int) $itemsPerPage); $doctrinePaginator = new DoctrinePaginator($query); diff --git a/src/DataProvider/ScreenScreenGroupsCollectionDataProvider.php b/src/DataProvider/ScreenScreenGroupsCollectionDataProvider.php index 7780df5e..c7ecc4ba 100644 --- a/src/DataProvider/ScreenScreenGroupsCollectionDataProvider.php +++ b/src/DataProvider/ScreenScreenGroupsCollectionDataProvider.php @@ -11,12 +11,10 @@ use App\Utils\ValidationUtils; use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Security\Core\Security; final class ScreenScreenGroupsCollectionDataProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface { public function __construct( - private Security $security, private RequestStack $requestStack, private ScreenRepository $screenRepository, private ValidationUtils $validationUtils, @@ -30,25 +28,23 @@ public function supports(string $resourceClass, string $operationName = null, ar public function getCollection(string $resourceClass, string $operationName = null, array $context = []): Paginator { - $itemsPerPage = (int) $this->requestStack->getCurrentRequest()->query->get('itemsPerPage', '10'); - $page = (int) $this->requestStack->getCurrentRequest()->query->get('page', '1'); - $id = $this->requestStack->getCurrentRequest()->attributes->get('id'); + $itemsPerPage = $this->requestStack->getCurrentRequest()->query?->get('itemsPerPage') ?? 10; + $page = $this->requestStack->getCurrentRequest()->query?->get('page') ?? 1; + $id = $this->requestStack->getCurrentRequest()->attributes?->get('id') ?? ''; $queryNameGenerator = new QueryNameGenerator(); $groupUlid = $this->validationUtils->validateUlid($id); $queryBuilder = $this->screenRepository->getScreensByScreenGroupId($groupUlid); + // Filter the query-builder with tenant extension. foreach ($this->collectionExtensions as $extension) { $extension->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName, $context); - if ($extension instanceof QueryResultItemExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) { - return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context); - } } - $firstResult = ($page - 1) * $itemsPerPage; + $firstResult = ((int) $page - 1) * (int) $itemsPerPage; $query = $queryBuilder->getQuery() ->setFirstResult($firstResult) - ->setMaxResults($itemsPerPage); + ->setMaxResults((int) $itemsPerPage); $doctrinePaginator = new DoctrinePaginator($query); diff --git a/src/DataProvider/SlidePlaylistCollectionDataProvider.php b/src/DataProvider/SlidePlaylistCollectionDataProvider.php index 3246989a..b6911998 100644 --- a/src/DataProvider/SlidePlaylistCollectionDataProvider.php +++ b/src/DataProvider/SlidePlaylistCollectionDataProvider.php @@ -8,19 +8,15 @@ use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface; use App\Entity\Tenant\PlaylistSlide; use App\Repository\PlaylistSlideRepository; -use App\Repository\SlideRepository; use App\Utils\ValidationUtils; use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Security\Core\Security; final class SlidePlaylistCollectionDataProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface { public function __construct( - private Security $security, private RequestStack $requestStack, private PlaylistSlideRepository $playlistSlideRepository, - private SlideRepository $slideRepository, private ValidationUtils $validationUtils, private iterable $collectionExtensions ) {} @@ -32,26 +28,24 @@ public function supports(string $resourceClass, string $operationName = null, ar public function getCollection(string $resourceClass, string $operationName = null, array $context = []): Paginator { - $itemsPerPage = (int) $this->requestStack->getCurrentRequest()->query->get('itemsPerPage', '10'); - $page = (int) $this->requestStack->getCurrentRequest()->query->get('page', '1'); - $id = $this->requestStack->getCurrentRequest()->attributes->get('id'); + $itemsPerPage = $this->requestStack->getCurrentRequest()->query?->get('itemsPerPage') ?? 10; + $page = $this->requestStack->getCurrentRequest()->query?->get('page') ?? 1; + $id = $this->requestStack->getCurrentRequest()->attributes?->get('id') ?? ''; $queryNameGenerator = new QueryNameGenerator(); $slideUlid = $this->validationUtils->validateUlid($id); // Get playlist to check shared-with-tenants $queryBuilder = $this->playlistSlideRepository->getPlaylistSlideRelationsFromSlideId($slideUlid); + // Filter the query-builder with tenant extension. foreach ($this->collectionExtensions as $extension) { $extension->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName, $context); - if ($extension instanceof QueryResultItemExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) { - return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context); - } } - $firstResult = ($page - 1) * $itemsPerPage; + $firstResult = ((int) $page - 1) * (int) $itemsPerPage; $query = $queryBuilder->getQuery() ->setFirstResult($firstResult) - ->setMaxResults($itemsPerPage); + ->setMaxResults((int) $itemsPerPage); $doctrinePaginator = new DoctrinePaginator($query); diff --git a/src/DataProvider/ThemeItemDataProvider.php b/src/DataProvider/ThemeItemDataProvider.php index 7d135800..a575774b 100644 --- a/src/DataProvider/ThemeItemDataProvider.php +++ b/src/DataProvider/ThemeItemDataProvider.php @@ -6,9 +6,11 @@ use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface; use App\Entity\Tenant\Theme; +use App\Entity\User; use App\Repository\SlideRepository; use App\Repository\ThemeRepository; use App\Utils\ValidationUtils; +use Doctrine\ORM\NonUniqueResultException; use Symfony\Component\Security\Core\Security; final class ThemeItemDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface @@ -28,25 +30,32 @@ public function supports(string $resourceClass, string $operationName = null, ar public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): ?Theme { - $queryNameGenerator = new QueryNameGenerator(); $user = $this->security->getUser(); + if (is_null($user)) { + return null; + } + + $queryNameGenerator = new QueryNameGenerator(); + + /** @var User $user */ $tenant = $user->getActiveTenant(); $themeUlid = $this->validationUtils->validateUlid($id); // Create a query-builder, as the tenant filter works on query-builders. $queryBuilder = $this->themeRepository->getById($themeUlid); - // Filter the query-builder with tenant extension + // Filter the query-builder with tenant extension. foreach ($this->itemExtensions as $extension) { $identifiers = ['id' => $id]; $extension->applyToItem($queryBuilder, $queryNameGenerator, $resourceClass, $identifiers, $operationName, $context); - if ($extension instanceof QueryResultItemExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) { - return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context); - } } // Get result. If there is a result this is returned. - $theme = $queryBuilder->getQuery()->getOneOrNullResult(); + try { + $theme = $queryBuilder->getQuery()->getOneOrNullResult(); + } catch (NonUniqueResultException $e) { + $theme = null; + } // If there is not a result, shared playlists should be checked. if (is_null($theme)) { diff --git a/src/DataTransformer/FeedSourceOutputDataTransformer.php b/src/DataTransformer/FeedSourceOutputDataTransformer.php index bbbbeb2e..6045a0ca 100644 --- a/src/DataTransformer/FeedSourceOutputDataTransformer.php +++ b/src/DataTransformer/FeedSourceOutputDataTransformer.php @@ -19,24 +19,24 @@ public function __construct( /** * {@inheritdoc} */ - public function transform($feedSource, string $to, array $context = []): FeedSourceDTO + public function transform($object, string $to, array $context = []): FeedSourceDTO { - /** @var FeedSource $feedSource */ + /** @var FeedSource $object */ $output = new FeedSourceDTO(); - $output->title = $feedSource->getTitle(); - $output->description = $feedSource->getDescription(); - $output->created = $feedSource->getCreatedAt(); - $output->modified = $feedSource->getModifiedAt(); - $output->createdBy = $feedSource->getCreatedBy(); - $output->modifiedBy = $feedSource->getModifiedBy(); - $output->feedType = $feedSource->getFeedType(); - $output->supportedFeedOutputType = $feedSource->getSupportedFeedOutputType(); - - $output->feeds = $feedSource->getFeeds()->map(function (Feed $feed) { + $output->title = $object->getTitle(); + $output->description = $object->getDescription(); + $output->created = $object->getCreatedAt(); + $output->modified = $object->getModifiedAt(); + $output->createdBy = $object->getCreatedBy(); + $output->modifiedBy = $object->getModifiedBy(); + $output->feedType = $object->getFeedType(); + $output->supportedFeedOutputType = $object->getSupportedFeedOutputType(); + + $output->feeds = $object->getFeeds()->map(function (Feed $feed) { return $this->iriConverter->getIriFromItem($feed); })->toArray(); - $output->admin = $this->feedService->getAdminFormOptions($feedSource); + $output->admin = $this->feedService->getAdminFormOptions($object); // Do not expose secrets. diff --git a/src/Entity/ScreenLayout.php b/src/Entity/ScreenLayout.php index 40332da7..d2afafcc 100644 --- a/src/Entity/ScreenLayout.php +++ b/src/Entity/ScreenLayout.php @@ -74,9 +74,9 @@ public function setGridColumns(int $gridColumns): self } /** - * @return Collection|Screen[] + * @return Collection */ - public function getScreens(): ArrayCollection + public function getScreens(): Collection { return $this->screens; } @@ -118,7 +118,7 @@ public function removeAllScreen(): self } /** - * @return Collection|ScreenLayoutRegions[] + * @return Collection */ public function getRegions(): Collection { diff --git a/src/Entity/ScreenLayoutRegions.php b/src/Entity/ScreenLayoutRegions.php index 2aafcf97..86b594f4 100644 --- a/src/Entity/ScreenLayoutRegions.php +++ b/src/Entity/ScreenLayoutRegions.php @@ -42,14 +42,14 @@ class ScreenLayoutRegions extends AbstractBaseEntity implements MultiTenantInter /** * @ORM\ManyToOne(targetEntity=ScreenLayout::class, inversedBy="regions") */ - private ScreenLayout $screenLayout; + private ?ScreenLayout $screenLayout = null; /** * @ORM\Column(type="string", length=255, nullable=true) * * @Groups({"read"}) */ - private $type; + private ?string $type = null; public function __construct() { @@ -82,7 +82,7 @@ public function setGridArea(array $gridArea): self } /** - * @return Collection|PlaylistScreenRegion[] + * @return Collection */ public function getPlaylistScreenRegions(): Collection { diff --git a/src/Entity/Template.php b/src/Entity/Template.php index c6763df4..0f468eb3 100644 --- a/src/Entity/Template.php +++ b/src/Entity/Template.php @@ -68,9 +68,9 @@ public function setResources(array $resources): self } /** - * @return ArrayCollection|Slide[] + * @return Collection */ - public function getSlides(): ArrayCollection + public function getSlides(): Collection { return $this->slides; } diff --git a/src/Entity/Tenant.php b/src/Entity/Tenant.php index 3233bc0d..41d04477 100644 --- a/src/Entity/Tenant.php +++ b/src/Entity/Tenant.php @@ -20,7 +20,7 @@ class Tenant extends AbstractBaseEntity implements \JsonSerializable /** * @ORM\Column(type="string", length=25, unique=true) */ - private string $tenantKey; + private string $tenantKey = ''; /** * @ORM\OneToMany(targetEntity=UserRoleTenant::class, mappedBy="tenant", orphanRemoval=true) @@ -30,7 +30,7 @@ class Tenant extends AbstractBaseEntity implements \JsonSerializable /** * @ORM\Column(type="string", nullable="true") */ - private ?string $fallbackImageUrl; + private ?string $fallbackImageUrl = null; public function __construct() { @@ -38,7 +38,7 @@ public function __construct() } /** - * @return Collection|UserRoleTenant[] + * @return Collection */ public function getUserRoleTenants(): Collection { diff --git a/src/Entity/Tenant/Feed.php b/src/Entity/Tenant/Feed.php index d608b8d1..e4475715 100644 --- a/src/Entity/Tenant/Feed.php +++ b/src/Entity/Tenant/Feed.php @@ -17,17 +17,17 @@ class Feed extends AbstractTenantScopedEntity * * @ORM\JoinColumn(nullable=false) */ - private ?FeedSource $feedSource; + private ?FeedSource $feedSource = null; /** * @ORM\Column(type="json", nullable=true) */ - private array $configuration = []; + private ?array $configuration = []; /** * @ORM\OneToOne(targetEntity=Slide::class, mappedBy="feed")) */ - private ?Slide $slide; + private ?Slide $slide = null; public function getFeedSource(): ?FeedSource { diff --git a/src/Entity/Tenant/FeedSource.php b/src/Entity/Tenant/FeedSource.php index 552cf6c2..41b770c6 100644 --- a/src/Entity/Tenant/FeedSource.php +++ b/src/Entity/Tenant/FeedSource.php @@ -20,12 +20,12 @@ class FeedSource extends AbstractTenantScopedEntity /** * @ORM\Column(type="string", length=255) */ - private string $feedType; + private string $feedType = ''; /** * @ORM\Column(type="json", nullable=true) */ - private array $secrets = []; + private ?array $secrets = []; /** * @ORM\OneToMany(targetEntity=Feed::class, mappedBy="feedSource", orphanRemoval=true) @@ -35,7 +35,7 @@ class FeedSource extends AbstractTenantScopedEntity /** * @ORM\Column(type="string", length=255) */ - private string $supportedFeedOutputType; + private string $supportedFeedOutputType = ''; public function __construct() { @@ -67,7 +67,7 @@ public function setSecrets(?array $secrets): self } /** - * @return Collection|Feed[] + * @return Collection */ public function getFeeds(): Collection { diff --git a/src/Entity/Tenant/Media.php b/src/Entity/Tenant/Media.php index a83a8d14..9dc1f2a1 100644 --- a/src/Entity/Tenant/Media.php +++ b/src/Entity/Tenant/Media.php @@ -175,7 +175,7 @@ public function setLicense(string $license): self } /** - * @return Collection|Slide[] + * @return Collection */ public function getSlides(): Collection { diff --git a/src/Entity/Tenant/Playlist.php b/src/Entity/Tenant/Playlist.php index 14e06567..9f423196 100644 --- a/src/Entity/Tenant/Playlist.php +++ b/src/Entity/Tenant/Playlist.php @@ -75,7 +75,7 @@ public function setIsCampaign(bool $isCampaign): self } /** - * @return Collection|PlaylistScreenRegion[] + * @return Collection */ public function getPlaylistScreenRegions(): Collection { @@ -149,7 +149,7 @@ public function removePlaylistSlide(PlaylistSlide $playlistSlide): self } /** - * @return Collection|Schedule[] + * @return Collection */ public function getSchedules(): Collection { diff --git a/src/Entity/Tenant/PlaylistScreenRegion.php b/src/Entity/Tenant/PlaylistScreenRegion.php index 84d689ab..896d62d3 100644 --- a/src/Entity/Tenant/PlaylistScreenRegion.php +++ b/src/Entity/Tenant/PlaylistScreenRegion.php @@ -23,21 +23,21 @@ class PlaylistScreenRegion extends AbstractTenantScopedEntity * * @ORM\JoinColumn(nullable=false) */ - private ?Playlist $playlist; + private ?Playlist $playlist = null; /** * @ORM\ManyToOne(targetEntity=Screen::class, inversedBy="playlistScreenRegions") * * @ORM\JoinColumn(nullable=false) */ - private ?Screen $screen; + private ?Screen $screen = null; /** * @ORM\ManyToOne(targetEntity=ScreenLayoutRegions::class, inversedBy="playlistScreenRegions") * * @ORM\JoinColumn(nullable=false) */ - private ?ScreenLayoutRegions $region; + private ?ScreenLayoutRegions $region = null; /** * @ORM\Column(type="integer", options={"default": 0}) diff --git a/src/Entity/Tenant/Schedule.php b/src/Entity/Tenant/Schedule.php index 893b4051..d8a7924e 100644 --- a/src/Entity/Tenant/Schedule.php +++ b/src/Entity/Tenant/Schedule.php @@ -19,14 +19,14 @@ class Schedule extends AbstractTenantScopedEntity /** * @ORM\Column(type="integer") */ - private int $duration; + private int $duration = 0; /** * @ORM\ManyToOne(targetEntity=Playlist::class, inversedBy="schedules") * * @ORM\JoinColumn(nullable=false) */ - private ?Playlist $playlist; + private ?Playlist $playlist = null; public function getRrule(): RRule { @@ -52,7 +52,7 @@ public function setDuration(int $duration): self return $this; } - public function getPlaylist(): Playlist + public function getPlaylist(): ?Playlist { return $this->playlist; } diff --git a/src/Entity/Tenant/Screen.php b/src/Entity/Tenant/Screen.php index 8b661cd8..ff7c763a 100644 --- a/src/Entity/Tenant/Screen.php +++ b/src/Entity/Tenant/Screen.php @@ -59,17 +59,17 @@ class Screen extends AbstractTenantScopedEntity /** * @ORM\ManyToMany(targetEntity=ScreenGroup::class, mappedBy="screens") */ - private $screenGroups; + private Collection $screenGroups; /** * @ORM\OneToOne(targetEntity=ScreenUser::class, mappedBy="screen", orphanRemoval="true") */ - private $screenUser; + private ?ScreenUser $screenUser = null; /** * @ORM\Column(type="boolean", nullable=true) */ - private $enableColorSchemeChange; + private ?bool $enableColorSchemeChange = null; public function __construct() { @@ -139,7 +139,7 @@ public function setLocation(string $location): self } /** - * @return ArrayCollection|PlaylistScreenRegion[] + * @return Collection */ public function getPlaylistScreenRegions(): Collection { @@ -183,7 +183,7 @@ public function removeAllPlaylistScreenRegions(): self } /** - * @return Collection|ScreenGroup[] + * @return Collection */ public function getScreenGroups(): Collection { diff --git a/src/Entity/Tenant/Slide.php b/src/Entity/Tenant/Slide.php index bccd376d..4d22b326 100644 --- a/src/Entity/Tenant/Slide.php +++ b/src/Entity/Tenant/Slide.php @@ -60,7 +60,7 @@ class Slide extends AbstractTenantScopedEntity /** * @ORM\OneToOne(targetEntity=Feed::class, cascade={"persist", "remove"}, orphanRemoval=true, inversedBy="slide") */ - private ?Feed $feed; + private ?Feed $feed = null; public function __construct() { diff --git a/src/Entity/Tenant/Theme.php b/src/Entity/Tenant/Theme.php index 8f075cd1..c2a7e4bd 100644 --- a/src/Entity/Tenant/Theme.php +++ b/src/Entity/Tenant/Theme.php @@ -25,7 +25,7 @@ class Theme extends AbstractTenantScopedEntity /** * @ORM\OneToOne(targetEntity=Media::class) */ - private ?Media $logo; + private ?Media $logo = null; /** * @ORM\OneToMany(targetEntity=Slide::class, mappedBy="theme") diff --git a/src/Entity/User.php b/src/Entity/User.php index a71dab34..7a7247d1 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -35,8 +35,6 @@ class User extends AbstractBaseEntity implements UserInterface, PasswordAuthenti */ private string $password = ''; - private Tenant $activeTenant; - /** * @ORM\OneToMany(targetEntity=UserRoleTenant::class, mappedBy="user", cascade={"persist", "remove"}, orphanRemoval=true) */ @@ -45,7 +43,9 @@ class User extends AbstractBaseEntity implements UserInterface, PasswordAuthenti /** * @ORM\Column(type="string") */ - private $provider; + private ?string $provider = null; + + private ?Tenant $activeTenant = null; public function __construct() { @@ -162,7 +162,7 @@ public function getSalt(): ?string /** * @see UserInterface */ - public function eraseCredentials() + public function eraseCredentials(): void { // If you store any temporary, sensitive data on the user, clear it here // $this->plainPassword = null; diff --git a/src/Entity/UserRoleTenant.php b/src/Entity/UserRoleTenant.php index 086095ba..94f25d1e 100644 --- a/src/Entity/UserRoleTenant.php +++ b/src/Entity/UserRoleTenant.php @@ -23,14 +23,14 @@ class UserRoleTenant extends AbstractBaseEntity implements \JsonSerializable * * @ORM\JoinColumn(nullable=false) */ - private User $user; + private ?User $user = null; /** * @ORM\ManyToOne(targetEntity=Tenant::class, inversedBy="userRoleTenants") * * @ORM\JoinColumn(nullable=false) */ - private Tenant $tenant; + private ?Tenant $tenant = null; /** * @ORM\Column(type="array") @@ -76,9 +76,9 @@ public function setRoles(array $roles): self public function jsonSerialize(): array { return [ - 'tenantKey' => $this->getTenant()->getTenantKey(), - 'title' => $this->getTenant()->getTitle(), - 'description' => $this->getTenant()->getDescription(), + 'tenantKey' => $this->getTenant()?->getTenantKey(), + 'title' => $this->getTenant()?->getTitle(), + 'description' => $this->getTenant()?->getDescription(), 'roles' => $this->getRoles(), ]; } diff --git a/src/Exceptions/MissingFeedConfigurationException.php b/src/Exceptions/MissingFeedConfigurationException.php new file mode 100644 index 00000000..e93f6371 --- /dev/null +++ b/src/Exceptions/MissingFeedConfigurationException.php @@ -0,0 +1,7 @@ +getFeedSource(); - $secrets = $feedSource->getSecrets(); + $secrets = $feedSource?->getSecrets(); $configuration = $feed->getConfiguration(); if (!isset($secrets['host'])) { - return []; + throw new MissingFeedConfigurationException('Missing host'); } $host = $secrets['host']; @@ -41,17 +54,12 @@ public function getData(Feed $feed): array|\stdClass|null $tags = $configuration['subscriptionTagValue'] ?? null; $numberOfItems = $configuration['subscriptionNumberValue'] ?? 5; - $queryParams = [ + $queryParams = array_filter([ 'items_per_page' => $numberOfItems, 'occurrences.place.id' => $places, 'organizer.id' => $organizers, 'tags' => $tags, - ]; - - $places && $queryParams['occurrences.place.id'] = $places; - $organizers && $queryParams['organizer.id'] = $organizers; - $tags && $queryParams['tags'] = $tags; - $numberOfItems && $queryParams['items_per_page'] = $numberOfItems; + ]); $response = $this->client->request( 'GET', @@ -63,11 +71,10 @@ public function getData(Feed $feed): array|\stdClass|null ); $content = $response->getContent(); - $decoded = json_decode($content); + $decoded = json_decode($content, false, 512, JSON_THROW_ON_ERROR); - $members = $decoded->{'hydra:member'}; + return $decoded->{'hydra:member'}; - return $members; case 'single': if ($configuration['singleSelectedOccurrence']) { $occurrenceId = $configuration['singleSelectedOccurrence']; @@ -113,15 +120,16 @@ public function getData(Feed $feed): array|\stdClass|null return [$eventOccurrence]; } - // no break - default: } } return []; } - public function getAdminFormOptions(FeedSource $feedSource): ?array + /** + * {@inheritDoc} + */ + public function getAdminFormOptions(FeedSource $feedSource): array { $searchEndpoint = $this->feedService->getFeedSourceConfigUrl($feedSource, 'search'); $endpointEntity = $this->feedService->getFeedSourceConfigUrl($feedSource, 'entity'); @@ -141,7 +149,10 @@ public function getAdminFormOptions(FeedSource $feedSource): ?array ]; } - public function getConfigOptions(Request $request, FeedSource $feedSource, string $name): array|\stdClass|null + /** + * {@inheritDoc} + */ + public function getConfigOptions(Request $request, FeedSource $feedSource, string $name): ?array { $secrets = $feedSource->getSecrets(); @@ -162,7 +173,7 @@ public function getConfigOptions(Request $request, FeedSource $feedSource, strin ); $content = $response->getContent(); - $decoded = json_decode($content); + $decoded = json_decode($content, true, 512, JSON_THROW_ON_ERROR); return $decoded; } elseif ('search' === $name) { @@ -196,7 +207,7 @@ public function getConfigOptions(Request $request, FeedSource $feedSource, strin } } - $queryParams['occurrences.startDate'] = ['after' => date('Y-m-d')]; + $queryParams['occurrences.endDate'] = ['after' => date('Y-m-d')]; !isset($queryParams['items_per_page']) && $queryParams['items_per_page'] = 10; @@ -239,17 +250,26 @@ public function getConfigOptions(Request $request, FeedSource $feedSource, strin return null; } + /** + * {@inheritDoc} + */ public function getRequiredSecrets(): array { return ['host']; } + /** + * {@inheritDoc} + */ public function getRequiredConfiguration(): array { return []; } - public function getsupportedFeedOutputType(): string + /** + * {@inheritDoc} + */ + public function getSupportedFeedOutputType(): string { return self::SUPPORTED_FEED_TYPE; } diff --git a/src/Feed/FeedTypeInterface.php b/src/Feed/FeedTypeInterface.php index 3cfb0937..a92906c4 100644 --- a/src/Feed/FeedTypeInterface.php +++ b/src/Feed/FeedTypeInterface.php @@ -4,7 +4,12 @@ use App\Entity\Tenant\Feed; use App\Entity\Tenant\FeedSource; +use App\Exceptions\MissingFeedConfigurationException; use Symfony\Component\HttpFoundation\Request; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; /** * Interface that feed types must implement. @@ -16,18 +21,27 @@ interface FeedTypeInterface * * @param FeedSource $feedSource the feed source * - * @return array|null array of admin options + * @return array + * Array of admin options */ - public function getAdminFormOptions(FeedSource $feedSource): ?array; + public function getAdminFormOptions(FeedSource $feedSource): array; /** * Get feed data for the given feed. * * @param Feed $feed the feed * - * @return array|\stdClass|null array or stdClass of data or null + * @return array + * Array of data + * + * @throws ClientExceptionInterface + * @throws MissingFeedConfigurationException + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportExceptionInterface + * @throws \JsonException */ - public function getData(Feed $feed): array|\stdClass|null; + public function getData(Feed $feed): array; /** * Get config options for $name from $feedSource. @@ -38,7 +52,7 @@ public function getData(Feed $feed): array|\stdClass|null; * * @return array|null */ - public function getConfigOptions(Request $request, FeedSource $feedSource, string $name): array|\stdClass|null; + public function getConfigOptions(Request $request, FeedSource $feedSource, string $name): ?array; /** * Get list of required secrets. @@ -59,5 +73,5 @@ public function getRequiredConfiguration(): array; * * @return string */ - public function getsupportedFeedOutputType(): string; + public function getSupportedFeedOutputType(): string; } diff --git a/src/Feed/KobaFeedType.php b/src/Feed/KobaFeedType.php index ddec1d99..3e61d01f 100644 --- a/src/Feed/KobaFeedType.php +++ b/src/Feed/KobaFeedType.php @@ -4,6 +4,7 @@ use App\Entity\Tenant\Feed; use App\Entity\Tenant\FeedSource; +use App\Exceptions\MissingFeedConfigurationException; use App\Service\FeedService; use Exception; use Psr\Log\LoggerInterface; @@ -26,48 +27,53 @@ public function __construct( private LoggerInterface $logger ) {} - public function getData(Feed $feed): array|\stdClass|null + /** + * @param Feed $feed + * + * @return array + * + * @throws MissingFeedConfigurationException + */ + public function getData(Feed $feed): array { + $results = []; + $feedSource = $feed->getFeedSource(); - $secrets = $feedSource->getSecrets(); + $secrets = $feedSource?->getSecrets(); $configuration = $feed->getConfiguration(); if (!isset($secrets['kobaHost']) || !isset($secrets['kobaApiKey'])) { - $this->logger->error('KobaFeedType: Feed source not configured.'); + $this->logger->error('KobaFeedType: "Host" and "ApiKey" not configured.'); - return []; + throw new MissingFeedConfigurationException('Koba feed "Host" and "ApiKey" not configured'); } $kobaHost = $secrets['kobaHost']; $kobaApiKey = $secrets['kobaApiKey']; $kobaGroup = $secrets['kobaGroup'] ?? 'default'; - $filterList = $configuration['filterList'] ?? false; $rewriteBookedTitles = $configuration['rewriteBookedTitles'] ?? false; if (!isset($configuration['resources'])) { $this->logger->error('KobaFeedType: Resources not set.'); - return []; + throw new MissingFeedConfigurationException('resources not configured'); } $resources = $configuration['resources']; - $now = time(); - // Round down to the nearest hour. - $from = time() - ($now % 3600); + $from = time() - (time() % 3600); // Get bookings for the coming week. // @TODO: Support for configuring interest period. $to = $from + 7 * 24 * 60 * 60; - $results = []; - foreach ($resources as $resource) { try { $bookings = $this->getBookingsFromResource($kobaHost, $kobaApiKey, $resource, $kobaGroup, $from, $to); } catch (Exception) { + $this->logger->error('KobaFeedType: Get bookings from resources failed.'); continue; } @@ -110,7 +116,10 @@ public function getData(Feed $feed): array|\stdClass|null return $results; } - public function getAdminFormOptions(FeedSource $feedSource): ?array + /** + * {@inheritDoc} + */ + public function getAdminFormOptions(FeedSource $feedSource): array { $endpoint = $this->feedService->getFeedSourceConfigUrl($feedSource, 'resources'); @@ -144,7 +153,16 @@ public function getAdminFormOptions(FeedSource $feedSource): ?array ]; } - public function getConfigOptions(Request $request, FeedSource $feedSource, string $name): array|\stdClass|null + /** + * {@inheritDoc} + * + * @throws ClientExceptionInterface + * @throws DecodingExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportExceptionInterface + */ + public function getConfigOptions(Request $request, FeedSource $feedSource, string $name): ?array { if ('resources' === $name) { $secrets = $feedSource->getSecrets(); @@ -209,15 +227,28 @@ public function getRequiredConfiguration(): array return ['resources']; } - public function getsupportedFeedOutputType(): string + public function getSupportedFeedOutputType(): string { return self::SUPPORTED_FEED_TYPE; } /** - * @throws \Exception + * @param string $host + * @param string $apikey + * @param string $resource + * @param string $group + * @param int $from + * @param int $to + * + * @return array + * + * @throws ClientExceptionInterface + * @throws DecodingExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportExceptionInterface */ - private function getBookingsFromResource($host, $apikey, $resource, $group, $from, $to): array + private function getBookingsFromResource(string $host, string $apikey, string $resource, string $group, int $from, int $to): array { try { $requestUrl = "$host/api/resources/$resource/group/$group/bookings/from/$from/to/$to"; @@ -232,7 +263,7 @@ private function getBookingsFromResource($host, $apikey, $resource, $group, $fro } catch (ClientExceptionInterface|DecodingExceptionInterface|RedirectionExceptionInterface|ServerExceptionInterface|TransportExceptionInterface $e) { $this->logger->error('Error building koba data. CODE: '.$e->getCode().', MESSAGE: '.$e->getMessage()); - throw new \Exception($e->getMessage(), $e->getCode()); + throw $e; } } } diff --git a/src/Feed/RssFeedType.php b/src/Feed/RssFeedType.php index c87fee38..d50eab38 100644 --- a/src/Feed/RssFeedType.php +++ b/src/Feed/RssFeedType.php @@ -4,6 +4,7 @@ use App\Entity\Tenant\Feed; use App\Entity\Tenant\FeedSource; +use App\Exceptions\MissingFeedConfigurationException; use FeedIo\Factory; use FeedIo\Feed\Item; use FeedIo\FeedIo; @@ -12,7 +13,6 @@ class RssFeedType implements FeedTypeInterface { public const SUPPORTED_FEED_TYPE = 'rss'; - private FeedIo $feedIo; public function __construct() @@ -20,13 +20,28 @@ public function __construct() $this->feedIo = Factory::create()->getFeedIo(); } - public function getData(Feed $feed): array|\stdClass|null + /** + * Get data from the feed-. + * + * @param feed $feed + * Feed object + * + * @return array + * Array with title and feed entities + * + * @throws MissingFeedConfigurationException + */ + public function getData(Feed $feed): array { $configuration = $feed->getConfiguration(); $numberOfEntries = $configuration['numberOfEntries'] ?? null; + $url = $configuration['url'] ?? null; - $feedResult = $this->feedIo->read($configuration['url']); + if (!isset($url)) { + throw new MissingFeedConfigurationException('URL not configured'); + } + $feedResult = $this->feedIo->read($url); $result = [ 'title' => $feedResult->getFeed()->getTitle(), 'entries' => [], @@ -44,7 +59,10 @@ public function getData(Feed $feed): array|\stdClass|null return $result; } - public function getAdminFormOptions(FeedSource $feedSource): ?array + /** + * {@inheritDoc} + */ + public function getAdminFormOptions(FeedSource $feedSource): array { // @TODO: Translation. return [ @@ -78,22 +96,34 @@ public function getAdminFormOptions(FeedSource $feedSource): ?array ]; } - public function getConfigOptions(Request $request, FeedSource $feedSource, string $name): array|\stdClass|null + /** + * {@inheritDoc} + */ + public function getConfigOptions(Request $request, FeedSource $feedSource, string $name): ?array { return null; } + /** + * {@inheritDoc} + */ public function getRequiredSecrets(): array { return []; } + /** + * {@inheritDoc} + */ public function getRequiredConfiguration(): array { return ['url']; } - public function getsupportedFeedOutputType(): string + /** + * {@inheritDoc} + */ + public function getSupportedFeedOutputType(): string { return self::SUPPORTED_FEED_TYPE; } diff --git a/src/Feed/SparkleIOFeedType.php b/src/Feed/SparkleIOFeedType.php index c3c8a189..2d119c47 100644 --- a/src/Feed/SparkleIOFeedType.php +++ b/src/Feed/SparkleIOFeedType.php @@ -4,11 +4,16 @@ use App\Entity\Tenant\Feed; use App\Entity\Tenant\FeedSource; +use App\Exceptions\MissingFeedConfigurationException; use App\Service\FeedService; use Psr\Cache\CacheItemInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Uid\Ulid; use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; class SparkleIOFeedType implements FeedTypeInterface @@ -22,34 +27,26 @@ public function __construct( private CacheInterface $feedsCache ) {} - public function getAdminFormOptions(FeedSource $feedSource): ?array + /** + * @param Feed $feed + * + * @return array + * + * @throws ClientExceptionInterface + * @throws MissingFeedConfigurationException + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportExceptionInterface + * @throws \JsonException + */ + public function getData(Feed $feed): array { - $endpoint = $this->feedService->getFeedSourceConfigUrl($feedSource, 'feeds'); - - // @TODO: Translation. - return [ - [ - 'key' => 'sparkle-io-selector', - 'input' => 'multiselect-from-endpoint', - 'endpoint' => $endpoint, - 'name' => 'feeds', - 'label' => 'Vælg feed', - 'helpText' => 'Her vælger du hvilket feed der skal hentes indgange fra.', - 'formGroupClasses' => 'col-md-6 mb-3', - ], - ]; - } - - public function getData(Feed $feed): array|\stdClass|null - { - $secrets = $feed->getFeedSource()->getSecrets(); - + $secrets = $feed->getFeedSource()?->getSecrets(); if (!isset($secrets['baseUrl']) || !isset($secrets['clientId']) || !isset($secrets['clientSecret'])) { - throw new \Exception('baseUrl, clientId and clientSecret secrets should be set'); + throw new MissingFeedConfigurationException('baseUrl, clientId and clientSecret secrets should be set'); } $configuration = $feed->getConfiguration(); - if (!isset($configuration['feeds']) || 0 === count($configuration['feeds'])) { return []; } @@ -57,7 +54,6 @@ public function getData(Feed $feed): array|\stdClass|null $baseUrl = $secrets['baseUrl']; $clientId = $secrets['clientId']; $clientSecret = $secrets['clientSecret']; - $token = $this->getToken($baseUrl, $clientId, $clientSecret); $res = $this->client->request( @@ -72,19 +68,47 @@ public function getData(Feed $feed): array|\stdClass|null ); $contents = $res->getContent(); - - $arr = json_decode($contents); + $data = json_decode($contents, false, 512, JSON_THROW_ON_ERROR); $res = []; - - foreach ($arr->items as $item) { + foreach ($data->items as $item) { $res[] = $this->getFeedItemObject($item); } return $res; } - public function getConfigOptions(Request $request, FeedSource $feedSource, string $name): array|\stdClass|null + /** + * {@inheritDoc} + */ + public function getAdminFormOptions(FeedSource $feedSource): array + { + $endpoint = $this->feedService->getFeedSourceConfigUrl($feedSource, 'feeds'); + + // @TODO: Translation. + return [ + [ + 'key' => 'sparkle-io-selector', + 'input' => 'multiselect-from-endpoint', + 'endpoint' => $endpoint, + 'name' => 'feeds', + 'label' => 'Vælg feed', + 'helpText' => 'Her vælger du hvilket feed der skal hentes indgange fra.', + 'formGroupClasses' => 'col-md-6 mb-3', + ], + ]; + } + + /** + * {@inheritDoc} + * + * @throws ClientExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportExceptionInterface + * @throws \JsonException + */ + public function getConfigOptions(Request $request, FeedSource $feedSource, string $name): ?array { if ('feeds' === $name) { $secrets = $feedSource->getSecrets(); @@ -130,13 +154,53 @@ public function getConfigOptions(Request $request, FeedSource $feedSource, strin return null; } - private function getToken($baseUrl, $clientId, $clientSecret) + /** + * {@inheritDoc} + */ + public function getRequiredSecrets(): array + { + return ['baseUrl', 'clientId', 'clientSecret']; + } + + /** + * {@inheritDoc} + */ + public function getRequiredConfiguration(): array + { + return ['feeds']; + } + + /** + * {@inheritDoc} + */ + public function getSupportedFeedOutputType(): string + { + return self::SUPPORTED_FEED_TYPE; + } + + /** + * Get oAuth token. + * + * @param string $baseUrl + * @param string $clientId + * @param string $clientSecret + * + * @return string + * + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportExceptionInterface + * @throws ClientExceptionInterface + * @throws \JsonException + */ + private function getToken(string $baseUrl, string $clientId, string $clientSecret): string { /** @var CacheItemInterface $cacheItem */ $cacheItem = $this->feedsCache->getItem('sparkleio-token'); if ($cacheItem->isHit()) { - return $cacheItem->get(); + /** @var string $token */ + $token = $cacheItem->get(); } else { $response = $this->client->request( 'POST', @@ -151,21 +215,30 @@ private function getToken($baseUrl, $clientId, $clientSecret) 'client_id' => urlencode($clientId), 'client_secret' => urlencode($clientSecret), ], - ]); + ] + ); $content = $response->getContent(); - $contentDecoded = json_decode($content); + $contentDecoded = json_decode($content, false, 512, JSON_THROW_ON_ERROR); + $token = $contentDecoded->access_token; $expireSeconds = intval($contentDecoded->expires_in / 1000 - 30); $cacheItem->set($token); $cacheItem->expiresAfter($expireSeconds); - - return $token; } + + return $token; } - private function getFeedItemObject($item): object + /** + * Parse feed item into object. + * + * @param object $item + * + * @return object + */ + private function getFeedItemObject(object $item): object { return (object) [ 'text' => $item->text, @@ -177,6 +250,11 @@ private function getFeedItemObject($item): object ]; } + /** + * @param string $input + * + * @return string + */ private function wrapTags(string $input): string { $text = trim($input); @@ -208,19 +286,4 @@ private function wrapTags(string $input): string return $text; } - - public function getRequiredSecrets(): array - { - return ['baseUrl', 'clientId', 'clientSecret']; - } - - public function getRequiredConfiguration(): array - { - return ['feeds']; - } - - public function getsupportedFeedOutputType(): string - { - return self::SUPPORTED_FEED_TYPE; - } } diff --git a/src/Filter/PublishedFilter.php b/src/Filter/PublishedFilter.php index 9063608d..d4de42ec 100644 --- a/src/Filter/PublishedFilter.php +++ b/src/Filter/PublishedFilter.php @@ -30,6 +30,14 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB // Validate that the properties on the entity is datetime fields. $properties = $this->getProperties(); + if (is_null($properties)) { + $this->getLogger()->notice('Invalid filter ignored', [ + 'exception' => new InvalidArgumentException('Properties not defined.'), + ]); + + return; + } + foreach ($properties as $property => $type) { if (!$this->isDateField($property, $resourceClass)) { $this->getLogger()->notice('Invalid filter ignored', [ diff --git a/src/Filter/SharedWithMe.php b/src/Filter/SharedWithMe.php index d3299432..a4b75a3c 100644 --- a/src/Filter/SharedWithMe.php +++ b/src/Filter/SharedWithMe.php @@ -5,6 +5,7 @@ use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractContextAwareFilter; use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Core\Exception\InvalidArgumentException; +use App\Entity\User; use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ManagerRegistry; use Psr\Log\LoggerInterface; @@ -33,10 +34,12 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB return; } - if (null === $user = $this->security->getUser()) { + $user = $this->security->getUser(); + if (is_null($user)) { return; } + /** @var User $user */ $tenant = $user->getActiveTenant(); $isSharedWithMe = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); if (is_null($isSharedWithMe)) { @@ -45,10 +48,10 @@ protected function filterProperty(string $property, $value, QueryBuilder $queryB $rootAlias = $queryBuilder->getRootAliases()[0]; if ($isSharedWithMe) { $queryBuilder->andWhere(sprintf(':tenant MEMBER OF %s.tenants', $rootAlias)) - ->setParameter('tenant', $tenant->getId()->toBinary()); + ->setParameter('tenant', $tenant->getId()?->toBinary()); } else { $queryBuilder->andWhere(sprintf('%s.tenant = :tenant', $rootAlias)) - ->setParameter('tenant', $tenant->getId()->toBinary()); + ->setParameter('tenant', $tenant->getId()?->toBinary()); } } diff --git a/src/Filter/TenantExtension.php b/src/Filter/TenantExtension.php index 857f8123..bb577204 100644 --- a/src/Filter/TenantExtension.php +++ b/src/Filter/TenantExtension.php @@ -5,6 +5,8 @@ use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface; use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface; use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface; +use App\Entity\Interfaces\MultiTenantInterface; +use App\Entity\Interfaces\TenantScopedEntityInterface; use App\Entity\Interfaces\TenantScopedUserInterface; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; @@ -36,15 +38,15 @@ private function addWhereCollection(QueryBuilder $queryBuilder, string $resource $tenant = $user->getActiveTenant(); $rootAlias = $queryBuilder->getRootAliases()[0]; $targetEntity = $this->entityManager->getClassMetaData($resourceClass); - if ($targetEntity->getReflectionClass()->implementsInterface('App\Entity\Interfaces\TenantScopedEntityInterface') && $targetEntity->getReflectionClass()->implementsInterface('App\Entity\Interfaces\MultiTenantInterface')) { + if ($targetEntity->getReflectionClass()->implementsInterface(TenantScopedEntityInterface::class) && $targetEntity->getReflectionClass()->implementsInterface(MultiTenantInterface::class)) { $queryBuilder->andWhere(sprintf('%s.tenant = :tenant OR :tenant MEMBER OF %s.tenants', $rootAlias, $rootAlias)) - ->setParameter('tenant', $tenant->getId()->toBinary()); - } elseif ($targetEntity->getReflectionClass()->implementsInterface('App\Entity\Interfaces\TenantScopedEntityInterface')) { + ->setParameter('tenant', $tenant->getId()?->toBinary()); + } elseif ($targetEntity->getReflectionClass()->implementsInterface(TenantScopedEntityInterface::class)) { $queryBuilder->andWhere(sprintf('%s.tenant = :tenant', $rootAlias)) - ->setParameter('tenant', $tenant->getId()->toBinary()); - } elseif ($targetEntity->getReflectionClass()->implementsInterface('App\Entity\Interfaces\MultiTenantInterface')) { + ->setParameter('tenant', $tenant->getId()?->toBinary()); + } elseif ($targetEntity->getReflectionClass()->implementsInterface(MultiTenantInterface::class)) { $queryBuilder->andWhere(sprintf(':tenant MEMBER OF %s.tenants', $rootAlias)) - ->setParameter('tenant', $tenant->getId()->toBinary()); + ->setParameter('tenant', $tenant->getId()?->toBinary()); } } @@ -58,12 +60,12 @@ private function addWhereItem(QueryBuilder $queryBuilder, string $resourceClass) $rootAlias = $queryBuilder->getRootAliases()[0]; $targetEntity = $this->entityManager->getClassMetaData($resourceClass); - if ($targetEntity->getReflectionClass()->implementsInterface('App\Entity\Interfaces\TenantScopedEntityInterface')) { + if ($targetEntity->getReflectionClass()->implementsInterface(TenantScopedEntityInterface::class)) { $queryBuilder->andWhere(sprintf('%s.tenant = :tenant', $rootAlias)) - ->setParameter('tenant', $tenant->getId()->toBinary()); - } elseif ($targetEntity->getReflectionClass()->implementsInterface('App\Entity\Interfaces\MultiTenantInterface')) { + ->setParameter('tenant', $tenant->getId()?->toBinary()); + } elseif ($targetEntity->getReflectionClass()->implementsInterface(MultiTenantInterface::class)) { $queryBuilder->andWhere(sprintf(':tenant MEMBER OF %s.tenants', $rootAlias)) - ->setParameter('tenant', $tenant->getId()->toBinary()); + ->setParameter('tenant', $tenant->getId()?->toBinary()); } } } diff --git a/src/OpenApi/OpenApiFactory.php b/src/OpenApi/OpenApiFactory.php index 31f31012..77d480db 100644 --- a/src/OpenApi/OpenApiFactory.php +++ b/src/OpenApi/OpenApiFactory.php @@ -19,7 +19,7 @@ public function __invoke(array $context = []): OpenApi { $openApi = $this->decorated->__invoke($context); - $securitySchemes = $openApi->getComponents()->getSecuritySchemes(); + $securitySchemes = $openApi->getComponents()->getSecuritySchemes() ?? []; $securitySchemes['bearerAuth'] = new \ArrayObject([ 'type' => 'http', 'scheme' => 'bearer', @@ -35,7 +35,7 @@ public function __invoke(array $context = []): OpenApi $openApi = $openApi->withSecurity($security); // Add auth endpoint - $schemas = $openApi->getComponents()->getSchemas(); + $schemas = $openApi->getComponents()->getSchemas() ?? []; $schemas['Token'] = new \ArrayObject([ 'type' => 'object', diff --git a/src/Service/FeedService.php b/src/Service/FeedService.php index de300b67..dff811fc 100644 --- a/src/Service/FeedService.php +++ b/src/Service/FeedService.php @@ -6,11 +6,17 @@ use ApiPlatform\Core\Bridge\Symfony\Routing\RouteNameGenerator; use App\Entity\Tenant\Feed; use App\Entity\Tenant\FeedSource; +use App\Exceptions\MissingFeedConfigurationException; +use App\Exceptions\UnknownFeedTypeException; use App\Feed\FeedTypeInterface; use Psr\Cache\CacheItemInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; class FeedService { @@ -20,6 +26,11 @@ public function __construct( private UrlGeneratorInterface $urlGenerator ) {} + /** + * @param FeedSource $feedSource + * + * @return array|null + */ public function getAdminFormOptions(FeedSource $feedSource): ?array { /** @var FeedTypeInterface $feedType */ @@ -32,17 +43,12 @@ public function getAdminFormOptions(FeedSource $feedSource): ?array return []; } - public function getFeedType(string $className): ?FeedTypeInterface - { - foreach ($this->feedTypes as $feedType) { - if ($className == $feedType::class) { - return $feedType; - } - } - - return null; - } - + /** + * Get class names for defined feed types in the system. + * + * @return array + * Array with feed type class names + */ public function getFeedTypes(): array { $res = []; @@ -54,6 +60,13 @@ public function getFeedTypes(): array return $res; } + /** + * Get remote feed url. + * + * @param Feed $feed + * + * @return string + */ public function getRemoteFeedUrl(Feed $feed): string { // @TODO: Find solution without depending on @internal RouteNameGenerator for generating route name. @@ -62,7 +75,15 @@ public function getRemoteFeedUrl(Feed $feed): string return $this->urlGenerator->generate($routeName, ['id' => $feed->getId()]); } - public function getFeedSourceConfigUrl(FeedSource $feedSource, $name): string + /** + * Get feed source url. + * + * @param FeedSource $feedSource + * @param string $name + * + * @return string + */ + public function getFeedSourceConfigUrl(FeedSource $feedSource, string $name): string { // @TODO: Find solution without depending on @internal RouteNameGenerator for generating route name. $routeName = RouteNameGenerator::generate('feed_source_config', 'FeedSource', OperationType::ITEM); @@ -70,42 +91,97 @@ public function getFeedSourceConfigUrl(FeedSource $feedSource, $name): string return $this->urlGenerator->generate($routeName, ['id' => $feedSource->getId(), 'name' => $name], UrlGeneratorInterface::ABSOLUTE_URL); } - public function getData(Feed $feed): array|\stdClass|null + /** + * Get feed data (feed items). + * + * @param feed $feed + * The feed to fetch data for + * + * @return array|null + * Array with feed data + * + * @throws MissingFeedConfigurationException + * @throws \JsonException + * @throws ClientExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportExceptionInterface + */ + public function getData(Feed $feed): ?array { + // Get feed id. + $feedId = $feed->getId()?->jsonSerialize(); + if (is_null($feedId)) { + throw new MissingFeedConfigurationException('Missing feed ID'); + } + /** @var CacheItemInterface $cacheItem */ - $cacheItem = $this->feedsCache->getItem($feed->getId()->jsonSerialize()); + $cacheItem = $this->feedsCache->getItem($feedId); if ($cacheItem->isHit()) { - return $cacheItem->get(); + /** @var array $data */ + $data = $cacheItem->get(); } else { $feedSource = $feed->getFeedSource(); - $feedTypeClassName = $feedSource->getFeedType(); + $feedTypeClassName = $feedSource?->getFeedType(); $feedConfiguration = $feed->getConfiguration(); + /** @var FeedTypeInterface $feedType */ foreach ($this->feedTypes as $feedType) { if ($feedType::class === $feedTypeClassName) { $data = $feedType->getData($feed); $cacheItem->set($data); - if (isset($feedConfiguration['cache_expire'])) { $cacheItem->expiresAfter($feedConfiguration['cache_expire']); } - $this->feedsCache->save($cacheItem); return $data; } } + // If feed type was not known in the system return null. API platform will convert this to 404 not found. return null; } + + return $data; + } + + /** + * Get feed type based on class name. + * + * @param string $className + * + * @return FeedTypeInterface + * + * @throws UnknownFeedTypeException + */ + public function getFeedType(string $className): FeedTypeInterface + { + foreach ($this->feedTypes as $feedType) { + if ($className == $feedType::class) { + return $feedType; + } + } + + throw new UnknownFeedTypeException(sprintf('Unknown feed type from "%s" class', $className)); } - public function getConfigOptions(Request $request, FeedSource $feedSource, string $name): array|\stdClass|null + /** + * Get configuration options based on feed source. + * + * @param Request $request + * @param FeedSource $feedSource + * @param string $name + * + * @return array|null + */ + public function getConfigOptions(Request $request, FeedSource $feedSource, string $name): ?array { $feedTypeClassName = $feedSource->getFeedType(); + /** @var FeedTypeInterface $feedType */ foreach ($this->feedTypes as $feedType) { if ($feedType::class === $feedTypeClassName) { return $feedType->getConfigOptions($request, $feedSource, $name); diff --git a/src/Service/MediaUploadTenantDirectoryNamer.php b/src/Service/MediaUploadTenantDirectoryNamer.php index 1e7f5abd..9aa26fa1 100644 --- a/src/Service/MediaUploadTenantDirectoryNamer.php +++ b/src/Service/MediaUploadTenantDirectoryNamer.php @@ -3,7 +3,6 @@ namespace App\Service; use App\Entity\Tenant\Media; -use Symfony\Component\Security\Core\Security; use Symfony\Component\String\Slugger\SluggerInterface; use Vich\UploaderBundle\Mapping\PropertyMapping; use Vich\UploaderBundle\Naming\DirectoryNamerInterface; @@ -14,7 +13,6 @@ class MediaUploadTenantDirectoryNamer implements DirectoryNamerInterface private const SEPARATOR = '-'; public function __construct( - private Security $security, private SluggerInterface $slugger ) {} @@ -23,7 +21,7 @@ public function directoryName($object, PropertyMapping $mapping): string if ($object instanceof Media) { $key = $object->getTenant()->getTenantKey(); - return \strtolower($this->slugger->slug($key, self::SEPARATOR)); + return \strtolower($this->slugger->slug($key, self::SEPARATOR)->toString()); } return self::DEFAULT; diff --git a/src/Utils/CommandInputValidator.php b/src/Utils/CommandInputValidator.php index 339e309d..8cbc0e38 100644 --- a/src/Utils/CommandInputValidator.php +++ b/src/Utils/CommandInputValidator.php @@ -11,6 +11,7 @@ namespace App\Utils; +use App\Repository\TenantRepository; use Symfony\Component\Console\Exception\InvalidArgumentException; use function Symfony\Component\String\u; @@ -23,6 +24,12 @@ */ class CommandInputValidator { + public const ALLOWED_USER_ROLES = ['editor', 'admin']; + + public function __construct( + private TenantRepository $tenantRepository, + ) {} + public function validateUsername(?string $username): string { if (empty($username)) { @@ -83,4 +90,38 @@ public function validateFullName(?string $fullName): string return $fullName; } + + public function validateRole(?string $role): string + { + if (empty($role)) { + throw new InvalidArgumentException('The role can not be empty.'); + } + + if (!in_array($role, self::ALLOWED_USER_ROLES)) { + throw new InvalidArgumentException('Unknown role: '.$role); + } + + return $role; + } + + public function validateTenantKeys(?array $tenantKeys): array + { + if (empty($tenantKeys)) { + throw new InvalidArgumentException('The user must belong to at least one tenant.'); + } + + $unknownKeys = []; + foreach ($tenantKeys as $tenantKey) { + $tenant = $this->tenantRepository->findOneBy(['tenantKey' => $tenantKey]); + if (null === $tenant) { + $unknownKeys[] = $tenantKey; + } + } + + if (0 !== \count($unknownKeys)) { + throw new InvalidArgumentException(sprintf('Unknown tenant keys: %s.', implode(', ', $unknownKeys))); + } + + return $tenantKeys; + } } diff --git a/symfony.lock b/symfony.lock index e7201d14..107a5e52 100644 --- a/symfony.lock +++ b/symfony.lock @@ -267,9 +267,6 @@ "nikic/php-parser": { "version": "v4.10.5" }, - "openlss/lib-array2xml": { - "version": "1.0.0" - }, "paragonie/random_compat": { "version": "v9.99.100" }, @@ -761,9 +758,6 @@ "webmozart/assert": { "version": "1.10.0" }, - "webmozart/path-util": { - "version": "2.3.0" - }, "weirdan/doctrine-psalm-plugin": { "version": "1.1.0" },