From e74fbfe17095a4ccd51de5dfca2b7623fa0855a7 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 24 Oct 2024 15:04:06 +0200 Subject: [PATCH 01/15] #2 Update README. Add docs, CHANGELOG & CONTRIBUTING. --- .gitignore | 7 +++++ CHANGELOG.md | 20 ++++++++++++ CONTRIBUTING.md | 52 +++++++++++++++++++++++++++++++ LICENSE | 2 +- README.md | 20 +++++++++++- docs/index.md | 27 ++++++++++++++++ docs/reference/tasks/_template.md | 44 ++++++++++++++++++++++++++ 7 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 docs/index.md create mode 100644 docs/reference/tasks/_template.md diff --git a/.gitignore b/.gitignore index ff72e2d..ca08796 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,9 @@ /composer.lock /vendor +.env +.idea +/phpunit.xml +.phpunit.result.cache +.phpunit.cache +.php-cs-fixer.cache +coverage-report diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..575e40e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ +v2.0 +------ + +## BC breaks + +### Changes + +### Fixes + +v1.0.1 +------ + +### Changes + +* Fixed dependencies after removing sidus/base-bundle from the base process bundle + +v1.0.0 +------ + +* Initial release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..9fb4f0a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,52 @@ +Contributing +============ + +First of all, **thank you** for contributing, **you are awesome**! + +Here are a few rules to follow in order to ease code reviews, and discussions before +maintainers accept and merge your work. + +You MUST run the quality & test suites. + +You SHOULD write (or update) unit tests. + +You SHOULD write documentation. + +Please, write [commit messages that make sense](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), +and [rebase your branch](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) before submitting your Pull Request. + +One may ask you to [squash your commits](https://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) +too. This is used to "clean" your Pull Request before merging it (we don't want +commits such as `fix tests`, `fix 2`, `fix 3`, etc.). + +Thank you! + +## Running the quality & test suites + +Tests suite uses Docker environments in order to be idempotent to OS's. More than this +PHP version is written inside the Dockerfile; this assures to test the bundle with +the same resources. No need to have PHP installed. + +You only need Docker set it up. + +To allow testing environments more smooth we implemented **Makefile**. +You have two commands available: + +```bash +make quality +``` + +```bash +make tests +``` + +## Deprecations notices + +When a feature should be deprecated, or when you have a breaking change for a future version, please : +* [Fill an issue](https://github.com/cleverage/soap-process-bundle/issues/new) +* Add TODO comments with the following format: `@TODO deprecated v2.0` +* Trigger a deprecation error: `@trigger_error('This feature will be deprecated in v2.0', E_USER_DEPRECATED);` + +You can check which deprecation notice is triggered in tests +* `make bash` +* `SYMFONY_DEPRECATIONS_HELPER=0 ./vendor/bin/phpunit` diff --git a/LICENSE b/LICENSE index fdc6131..045d824 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2015-2019 Clever-Age +Copyright (c) Clever-Age Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 7f8bd11..3e84b12 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,22 @@ CleverAge/SoapProcessBundle ======================= -See process bundle documentation +This bundle is a part of the [CleverAge/ProcessBundle](https://github.com/cleverage/process-bundle) project. +It provides [Soap](https://fr.wikipedia.org/wiki/SOAP) integration on Process bundle. + +Compatible with [Symfony stable version and latest Long-Term Support (LTS) release](https://symfony.com/releases). + +## Documentation + +For usage documentation, see: +[docs/index.md](doc/index.md) + +## Support & Contribution + +For general support and questions, please use [Github](https://github.com/cleverage/rest-process-bundle/issues). +If you think you found a bug or you have a feature idea to propose, feel free to open an issue after looking at the [contributing](CONTRIBUTING.md) guide. + +## License + +This bundle is under the MIT license. +For the whole copyright, see the [LICENSE](LICENSE) file distributed with this source code. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..24dee03 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,27 @@ +## Prerequisite + +CleverAge/ProcessBundle must be [installed](https://github.com/cleverage/process-bundle/blob/main/docs/01-quick_start.md#installation. + +## Installation + +Make sure Composer is installed globally, as explained in the [installation chapter](https://getcomposer.org/doc/00-intro.md) +of the Composer documentation. + +Open a command console, enter your project directory and install it using composer: + +```bash +composer require cleverage/soap-process-bundle +``` + +Remember to add the following line to config/bundles.php (not required if Symfony Flex is used) + +```php +CleverAge\SoapProcessBundle\CleverAgeSoapProcessBundle::class => ['all' => true], +``` + +## Reference + +- Tasks + - [RequestTask] +- Transformers + - [RequestTransformer] diff --git a/docs/reference/tasks/_template.md b/docs/reference/tasks/_template.md new file mode 100644 index 0000000..ed1d4a5 --- /dev/null +++ b/docs/reference/tasks/_template.md @@ -0,0 +1,44 @@ +TaskName +======== + +_Describe main goal an use cases of the task_ + +Task reference +-------------- + +* **Service**: `ClassName` + +Accepted inputs +--------------- + +_Description of allowed types_ + +Possible outputs +---------------- + +_Description of possible types_ + +Options +------- + +| Code | Type | Required | Default | Description | +| ---- | ---- | :------: | ------- | ----------- | +| `code` | `type` | **X** _or nothing_ | `default value` _if available_ | _description_ | + +Examples +-------- + +_YAML samples and explanations_ + +* Example 1 + - details + - details + +```yaml +# Task configuration level +code: + service: '@service_ref' + options: + a: 1 + b: 2 +``` From 4315f50836f3495e9338c3e6a58a816dfef147ea Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 24 Oct 2024 15:17:37 +0200 Subject: [PATCH 02/15] #2 Add Makefile & .docker for local standalone usage. Add rector, phpstan & php-cs-fixer configurations --- .docker/compose.yaml | 14 ++++++++++ .docker/php/Dockerfile | 30 +++++++++++++++++++++ .docker/php/conf.d/dev.ini | 5 ++++ .php-cs-fixer.dist.php | 46 ++++++++++++++++++++++++++++++++ Makefile | 54 ++++++++++++++++++++++++++++++++++++++ composer.json | 25 ++++++++++++++++-- phpstan.neon | 18 +++++++++++++ phpunit.xml.dist | 27 +++++++++++++++++++ rector.php | 30 +++++++++++++++++++++ tests/.gitkeep | 0 10 files changed, 247 insertions(+), 2 deletions(-) create mode 100644 .docker/compose.yaml create mode 100644 .docker/php/Dockerfile create mode 100644 .docker/php/conf.d/dev.ini create mode 100644 .php-cs-fixer.dist.php create mode 100644 Makefile create mode 100644 phpstan.neon create mode 100644 phpunit.xml.dist create mode 100644 rector.php create mode 100644 tests/.gitkeep diff --git a/.docker/compose.yaml b/.docker/compose.yaml new file mode 100644 index 0000000..436a718 --- /dev/null +++ b/.docker/compose.yaml @@ -0,0 +1,14 @@ +x-build-args: &build-args + UID: "${UID:-1000}" + GID: "${GID:-1000}" + +name: cleverage-soap-process-bundle + +services: + php: + build: + context: php + args: + <<: *build-args + volumes: + - ../:/var/www diff --git a/.docker/php/Dockerfile b/.docker/php/Dockerfile new file mode 100644 index 0000000..c812151 --- /dev/null +++ b/.docker/php/Dockerfile @@ -0,0 +1,30 @@ +FROM php:8.2-fpm-alpine + +ARG UID +ARG GID + +RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" +COPY /conf.d/ "$PHP_INI_DIR/conf.d/" + +RUN apk update && apk add \ + tzdata \ + shadow \ + nano \ + bash \ + icu-dev \ + libxml2-dev \ + && docker-php-ext-configure intl \ + && docker-php-ext-install intl soap opcache \ + && docker-php-ext-enable soap opcache + +RUN ln -s /usr/share/zoneinfo/Europe/Paris /etc/localtime \ + && sed -i "s/^;date.timezone =.*/date.timezone = Europe\/Paris/" $PHP_INI_DIR/php.ini + +COPY --from=composer:2 /usr/bin/composer /usr/bin/composer + +RUN usermod -u $UID www-data \ + && groupmod -g $GID www-data + +USER www-data:www-data + +WORKDIR /var/www diff --git a/.docker/php/conf.d/dev.ini b/.docker/php/conf.d/dev.ini new file mode 100644 index 0000000..2a141be --- /dev/null +++ b/.docker/php/conf.d/dev.ini @@ -0,0 +1,5 @@ +display_errors = 1 +error_reporting = E_ALL + +opcache.validate_timestamps = 1 +opcache.revalidate_freq = 0 diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..0de9bbb --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,46 @@ +setRules([ + '@PHP71Migration' => true, + '@PHP82Migration' => true, + '@PHPUnit75Migration:risky' => true, + '@Symfony' => true, + '@Symfony:risky' => true, + 'protected_to_private' => false, + 'native_constant_invocation' => ['strict' => false], + 'header_comment' => ['header' => $fileHeaderComment], + 'modernize_strpos' => true, + 'get_class_to_class_keyword' => true, + ]) + ->setRiskyAllowed(true) + ->setFinder( + (new PhpCsFixer\Finder()) + ->in(__DIR__.'/src') + ->in(__DIR__.'/tests') + ->append([__FILE__]) + ) + ->setCacheFile('.php-cs-fixer.cache') +; diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0a58e32 --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +.ONESHELL: +SHELL := /bin/bash + +DOCKER_RUN_PHP = docker compose -f .docker/compose.yaml run --rm php "bash" "-c" +DOCKER_COMPOSE = docker compose -f .docker/compose.yaml + +start: upd #[Global] Start application + +src/vendor: #[Composer] install dependencies + $(DOCKER_RUN_PHP) "composer install --no-interaction" + +upd: #[Docker] Start containers detached + touch .docker/.env + make src/vendor + $(DOCKER_COMPOSE) up --remove-orphans --detach + +up: #[Docker] Start containers + touch .docker/.env + make src/vendor + $(DOCKER_COMPOSE) up --remove-orphans + +stop: #[Docker] Down containers + $(DOCKER_COMPOSE) stop + +down: #[Docker] Down containers + $(DOCKER_COMPOSE) down + +build: #[Docker] Build containers + $(DOCKER_COMPOSE) build + +ps: # [Docker] Show running containers + $(DOCKER_COMPOSE) ps + +bash: #[Docker] Connect to php container with current host user + $(DOCKER_COMPOSE) exec php bash + +logs: #[Docker] Show logs + $(DOCKER_COMPOSE) logs -f + +quality: phpstan php-cs-fixer rector #[Quality] Run all quality checks + +phpstan: #[Quality] Run PHPStan + $(DOCKER_RUN_PHP) "vendor/bin/phpstan --no-progress --memory-limit=1G analyse" + +php-cs-fixer: #[Quality] Run PHP-CS-Fixer + $(DOCKER_RUN_PHP) "vendor/bin/php-cs-fixer fix --diff --verbose" + +rector: #[Quality] Run Rector + $(DOCKER_RUN_PHP) "vendor/bin/rector" + +tests: phpunit #[Tests] Run all tests + +phpunit: #[Tests] Run PHPUnit + $(DOCKER_RUN_PHP) "vendor/bin/phpunit" diff --git a/composer.json b/composer.json index 2582944..27984d1 100644 --- a/composer.json +++ b/composer.json @@ -37,12 +37,33 @@ "CleverAge\\SoapProcessBundle\\": "" } }, + "autoload-dev": { + "psr-4": { + "CleverAge\\SoapProcessBundle\\Tests\\": "tests/" + } + }, "require": { - "cleverage/process-bundle": "3.*|dev-v3.0-dev", + "php": ">=8.1", + "cleverage/process-bundle": "dev-prepare-release", "ext-soap": "*", "sidus/base-bundle": "~1.0" }, "require-dev": { - "phpunit/phpunit": "~6.4" + "friendsofphp/php-cs-fixer": "*", + "phpstan/extension-installer": "*", + "phpstan/phpstan": "*", + "phpstan/phpstan-symfony": "*", + "phpunit/phpunit": "*", + "rector/rector": "*", + "roave/security-advisories": "dev-latest", + "symfony/test-pack": "^1.1" + }, + "config": { + "allow-plugins": { + "phpstan/extension-installer": true, + "symfony/flex": true, + "symfony/runtime": true + }, + "sort-packages": true } } diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..30e9572 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,18 @@ +parameters: + level: 6 + paths: + - src + - tests + ignoreErrors: + - '#type has no value type specified in iterable type#' + - '#has parameter .* with no value type specified in iterable type#' + - '#has no value type specified in iterable type array#' + - '#configureOptions\(\) has no return type specified.#' + - '#configure\(\) has no return type specified#' + - '#process\(\) has no return type specified#' + - '#should return Iterator but returns Traversable#' + - '#Negated boolean expression is always false#' + checkGenericClassInNonGenericObjectType: false + reportUnmatchedIgnoredErrors: false + inferPrivatePropertyTypeFromConstructor: true + treatPhpDocTypesAsCertain: false diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..766495c --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,27 @@ + + + + + tests + + + + + + src + + + diff --git a/rector.php b/rector.php new file mode 100644 index 0000000..72a2408 --- /dev/null +++ b/rector.php @@ -0,0 +1,30 @@ +withPhpVersion(PhpVersion::PHP_82) + ->withPaths([ + __DIR__.'/src', + __DIR__.'/tests', + ]) + ->withPhpSets(php82: true) + // here we can define, what prepared sets of rules will be applied + ->withPreparedSets( + deadCode: true, + codeQuality: true + ) + ->withSets([ + LevelSetList::UP_TO_PHP_82, + SymfonySetList::SYMFONY_64, + SymfonySetList::SYMFONY_71, + SymfonySetList::SYMFONY_CODE_QUALITY, + SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION, + SymfonySetList::ANNOTATIONS_TO_ATTRIBUTES, + ]) +; diff --git a/tests/.gitkeep b/tests/.gitkeep new file mode 100644 index 0000000..e69de29 From d7e7490b332510ab110f18b288a94916c725a28e Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 24 Oct 2024 15:19:00 +0200 Subject: [PATCH 03/15] #2 Add notifications, quality & test github workflows --- .github/ISSUE_TEMPLATE.md | 14 ++++++ .github/PULL_REQUEST_TEMPLATE.md | 14 ++++++ .github/workflows/notifications.yml | 23 +++++++++ .github/workflows/quality.yml | 62 ++++++++++++++++++++++++ .github/workflows/test.yml | 74 +++++++++++++++++++++++++++++ 5 files changed, 187 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/notifications.yml create mode 100644 .github/workflows/quality.yml create mode 100644 .github/workflows/test.yml diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..7711713 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,14 @@ +## Description + + + +## Requirements + +* Documentation updates + - [ ] Reference + - [ ] Changelog +* [ ] Unit tests + +## Breaking changes + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..58db37d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,14 @@ +## Description + + + +## Requirements + +* Documentation updates + - [ ] Reference + - [ ] Changelog +* [ ] Unit tests + +## Breaking changes + + diff --git a/.github/workflows/notifications.yml b/.github/workflows/notifications.yml new file mode 100644 index 0000000..0840f58 --- /dev/null +++ b/.github/workflows/notifications.yml @@ -0,0 +1,23 @@ +name: Rocket chat notifications + +# Controls when the action will run. +on: + push: + tags: + - '*' + +jobs: + notification: + runs-on: ubuntu-latest + + steps: + - name: Get the tag short reference + id: get_tag + run: echo "TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT + + - name: Rocket.Chat Notification + uses: madalozzo/Rocket.Chat.GitHub.Action.Notification@master + with: + type: success + job_name: "[cleverage/soap-process-bundle](https://github.com/cleverage/soap-process-bundle) : ${{ steps.get_tag.outputs.TAG }} has been released" + url: ${{ secrets.CLEVER_AGE_ROCKET_CHAT_WEBOOK_URL }} diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml new file mode 100644 index 0000000..9f1580f --- /dev/null +++ b/.github/workflows/quality.yml @@ -0,0 +1,62 @@ +name: Quality + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +jobs: + phpstan: + name: PHPStan + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + coverage: none + tools: composer:v2 + - name: Install Composer dependencies (locked) + uses: ramsey/composer-install@v3 + - name: PHPStan + run: vendor/bin/phpstan --no-progress --memory-limit=1G analyse --error-format=github + + php-cs-fixer: + name: PHP-CS-Fixer + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + coverage: none + tools: composer:v2 + - name: Install Composer dependencies (locked) + uses: ramsey/composer-install@v3 + - name: PHP-CS-Fixer + run: vendor/bin/php-cs-fixer fix --diff --dry-run --show-progress=none + + rector: + name: Rector + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + coverage: none + tools: composer:v2 + - name: Install Composer dependencies (locked) + uses: ramsey/composer-install@v3 + - name: Rector + run: vendor/bin/rector --no-progress-bar --dry-run diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..2d7e7a4 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,74 @@ +name: Test + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +jobs: + test: + name: PHP ${{ matrix.php-version }} + ${{ matrix.dependencies }} + ${{ matrix.variant }} + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.allowed-to-fail }} + env: + SYMFONY_REQUIRE: ${{matrix.symfony-require}} + + strategy: + matrix: + php-version: + - '8.2' + - '8.3' + dependencies: [highest] + allowed-to-fail: [false] + symfony-require: [''] + variant: [normal] + include: + - php-version: '8.2' + dependencies: highest + allowed-to-fail: false + symfony-require: 6.4.* + variant: symfony/symfony:"6.4.*" + - php-version: '8.2' + dependencies: highest + allowed-to-fail: false + symfony-require: 7.1.* + variant: symfony/symfony:"7.1.*" + - php-version: '8.3' + dependencies: highest + allowed-to-fail: false + symfony-require: 6.4.* + variant: symfony/symfony:"6.4.*" + - php-version: '8.3' + dependencies: highest + allowed-to-fail: false + symfony-require: 7.1.* + variant: symfony/symfony:"7.1.*" + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + coverage: pcov + tools: composer:v2, flex + - name: Add PHPUnit matcher + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + - name: Install variant + if: matrix.variant != 'normal' && !startsWith(matrix.variant, 'symfony/symfony') + run: composer require ${{ matrix.variant }} --no-update + - name: Install Composer dependencies (${{ matrix.dependencies }}) + uses: ramsey/composer-install@v3 + with: + dependency-versions: ${{ matrix.dependencies }} + - name: Run Tests with coverage + run: vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover build/logs/clover.xml + #- name: Send coverage to Codecov + # uses: codecov/codecov-action@v4 + # with: + # files: build/logs/clover.xml From 5aa263bfcafa42bf581a94e30958c0397d5ed5c9 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 24 Oct 2024 15:25:30 +0200 Subject: [PATCH 04/15] #2 Update directory structure with code on /src --- .../CleverAgeSoapProcessExtension.php | 26 ----------- composer.json | 2 +- .../CleverAgeSoapProcessBundle.php | 0 {Client => src/Client}/Client.php | 0 {Client => src/Client}/ClientInterface.php | 0 .../CleverAgeSoapProcessExtension.php | 44 +++++++++++++++++++ .../Exception}/MissingClientException.php | 0 {Registry => src/Registry}/ClientRegistry.php | 0 .../Resources/config/services/registry.yaml | 0 .../Resources/config/services/task.yaml | 0 .../config/services/transformer.yaml | 0 {Task => src/Task}/RequestTask.php | 0 .../Transformer}/RequestTransformer.php | 2 +- 13 files changed, 46 insertions(+), 28 deletions(-) delete mode 100644 DependencyInjection/CleverAgeSoapProcessExtension.php rename CleverAgeSoapProcessBundle.php => src/CleverAgeSoapProcessBundle.php (100%) rename {Client => src/Client}/Client.php (100%) rename {Client => src/Client}/ClientInterface.php (100%) create mode 100644 src/DependencyInjection/CleverAgeSoapProcessExtension.php rename {Exception => src/Exception}/MissingClientException.php (100%) rename {Registry => src/Registry}/ClientRegistry.php (100%) rename Resources/config/services/registry.yml => src/Resources/config/services/registry.yaml (100%) rename Resources/config/services/task.yml => src/Resources/config/services/task.yaml (100%) rename Resources/config/services/transformer.yml => src/Resources/config/services/transformer.yaml (100%) rename {Task => src/Task}/RequestTask.php (100%) rename {Transformer => src/Transformer}/RequestTransformer.php (100%) diff --git a/DependencyInjection/CleverAgeSoapProcessExtension.php b/DependencyInjection/CleverAgeSoapProcessExtension.php deleted file mode 100644 index bdd54e9..0000000 --- a/DependencyInjection/CleverAgeSoapProcessExtension.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @author Vincent Chalnot - * @author Madeline Veyrenc - */ -class CleverAgeSoapProcessExtension extends SidusBaseExtension -{ -} diff --git a/composer.json b/composer.json index 27984d1..570506b 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ ], "autoload": { "psr-4": { - "CleverAge\\SoapProcessBundle\\": "" + "CleverAge\\SoapProcessBundle\\": "src/" } }, "autoload-dev": { diff --git a/CleverAgeSoapProcessBundle.php b/src/CleverAgeSoapProcessBundle.php similarity index 100% rename from CleverAgeSoapProcessBundle.php rename to src/CleverAgeSoapProcessBundle.php diff --git a/Client/Client.php b/src/Client/Client.php similarity index 100% rename from Client/Client.php rename to src/Client/Client.php diff --git a/Client/ClientInterface.php b/src/Client/ClientInterface.php similarity index 100% rename from Client/ClientInterface.php rename to src/Client/ClientInterface.php diff --git a/src/DependencyInjection/CleverAgeSoapProcessExtension.php b/src/DependencyInjection/CleverAgeSoapProcessExtension.php new file mode 100644 index 0000000..879fbd4 --- /dev/null +++ b/src/DependencyInjection/CleverAgeSoapProcessExtension.php @@ -0,0 +1,44 @@ +findServices($container, __DIR__.'/../Resources/config/services'); + } + + /** + * Recursively import config files into container. + */ + protected function findServices(ContainerBuilder $container, string $path, string $extension = 'yaml'): void + { + $finder = new Finder(); + $finder->in($path) + ->name('*.'.$extension)->files(); + $loader = new YamlFileLoader($container, new FileLocator($path)); + foreach ($finder as $file) { + $loader->load($file->getFilename()); + } + } +} diff --git a/Exception/MissingClientException.php b/src/Exception/MissingClientException.php similarity index 100% rename from Exception/MissingClientException.php rename to src/Exception/MissingClientException.php diff --git a/Registry/ClientRegistry.php b/src/Registry/ClientRegistry.php similarity index 100% rename from Registry/ClientRegistry.php rename to src/Registry/ClientRegistry.php diff --git a/Resources/config/services/registry.yml b/src/Resources/config/services/registry.yaml similarity index 100% rename from Resources/config/services/registry.yml rename to src/Resources/config/services/registry.yaml diff --git a/Resources/config/services/task.yml b/src/Resources/config/services/task.yaml similarity index 100% rename from Resources/config/services/task.yml rename to src/Resources/config/services/task.yaml diff --git a/Resources/config/services/transformer.yml b/src/Resources/config/services/transformer.yaml similarity index 100% rename from Resources/config/services/transformer.yml rename to src/Resources/config/services/transformer.yaml diff --git a/Task/RequestTask.php b/src/Task/RequestTask.php similarity index 100% rename from Task/RequestTask.php rename to src/Task/RequestTask.php diff --git a/Transformer/RequestTransformer.php b/src/Transformer/RequestTransformer.php similarity index 100% rename from Transformer/RequestTransformer.php rename to src/Transformer/RequestTransformer.php index f66e067..361a380 100644 --- a/Transformer/RequestTransformer.php +++ b/src/Transformer/RequestTransformer.php @@ -10,8 +10,8 @@ namespace CleverAge\SoapProcessBundle\Transformer; -use CleverAge\SoapProcessBundle\Registry\ClientRegistry; use CleverAge\ProcessBundle\Transformer\ConfigurableTransformerInterface; +use CleverAge\SoapProcessBundle\Registry\ClientRegistry; use Symfony\Component\OptionsResolver\OptionsResolver; /** From 8681dadbdd801d0efe2c4f783e518f080d3454cf Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 24 Oct 2024 15:29:21 +0200 Subject: [PATCH 05/15] #3 Remove `sidus/base-bundle` dependency --- CHANGELOG.md | 4 ++++ composer.json | 3 +-- src/DependencyInjection/CleverAgeSoapProcessExtension.php | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 575e40e..2ce9659 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ v2.0 ### Changes +* [#2](https://github.com/cleverage/soap-process-bundle/issues/2) Add Makefile & .docker for local standalone usage +* [#2](https://github.com/cleverage/soap-process-bundle/issues/2) Add rector, phpstan & php-cs-fixer configurations & apply it +* [#3](https://github.com/cleverage/soap-process-bundle/issues/3) Remove `sidus/base-bundle` dependency + ### Fixes v1.0.1 diff --git a/composer.json b/composer.json index 570506b..7625004 100644 --- a/composer.json +++ b/composer.json @@ -44,9 +44,8 @@ }, "require": { "php": ">=8.1", - "cleverage/process-bundle": "dev-prepare-release", "ext-soap": "*", - "sidus/base-bundle": "~1.0" + "cleverage/process-bundle": "dev-prepare-release" }, "require-dev": { "friendsofphp/php-cs-fixer": "*", diff --git a/src/DependencyInjection/CleverAgeSoapProcessExtension.php b/src/DependencyInjection/CleverAgeSoapProcessExtension.php index 879fbd4..f40716c 100644 --- a/src/DependencyInjection/CleverAgeSoapProcessExtension.php +++ b/src/DependencyInjection/CleverAgeSoapProcessExtension.php @@ -10,9 +10,9 @@ namespace CleverAge\SoapProcessBundle\DependencyInjection; -use Sidus\BaseBundle\DependencyInjection\SidusBaseExtension; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\Finder\Finder; @@ -21,7 +21,7 @@ * * @see http://symfony.com/doc/current/cookbook/bundles/extension.html */ -class CleverAgeSoapProcessExtension extends SidusBaseExtension +class CleverAgeSoapProcessExtension extends Extension { public function load(array $configs, ContainerBuilder $container): void { From 654f7dedf7b83dd14e0f46f6798f51da6f8ad1aa Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 24 Oct 2024 15:37:03 +0200 Subject: [PATCH 06/15] #2 Apply phpstan, php-cs-fixer & rector rules --- src/CleverAgeSoapProcessBundle.php | 15 +- src/Client/Client.php | 132 ++++-------------- src/Client/ClientInterface.php | 75 +++------- .../CleverAgeSoapProcessExtension.php | 9 +- src/Exception/MissingClientException.php | 15 +- src/Registry/ClientRegistry.php | 35 ++--- src/Task/RequestTask.php | 47 ++----- src/Transformer/RequestTransformer.php | 40 ++---- 8 files changed, 101 insertions(+), 267 deletions(-) diff --git a/src/CleverAgeSoapProcessBundle.php b/src/CleverAgeSoapProcessBundle.php index 01fd46d..4fff13d 100644 --- a/src/CleverAgeSoapProcessBundle.php +++ b/src/CleverAgeSoapProcessBundle.php @@ -1,8 +1,11 @@ - * @author Vincent Chalnot @@ -25,9 +28,7 @@ class CleverAgeSoapProcessBundle extends Bundle { /** - * Adding compiler passes to inject services into registry - * - * @param ContainerBuilder $container + * Adding compiler passes to inject services into registry. */ public function build(ContainerBuilder $container): void { diff --git a/src/Client/Client.php b/src/Client/Client.php index b70227c..1c81465 100644 --- a/src/Client/Client.php +++ b/src/Client/Client.php @@ -1,8 +1,11 @@ - */ class Client implements ClientInterface { - /** @var string */ - private $code; - - /** @var string|null */ - private $wsdl; - - /** @var array */ - private $options; - /** @var array */ private $soapOptions; - /** @var null|\SoapHeader[] */ + /** @var \SoapHeader[]|null */ private $soapHeaders; - /** @var LoggerInterface */ - private $logger; - /** @var \SoapClient */ private $soapClient; @@ -54,85 +45,54 @@ class Client implements ClientInterface /** * Client constructor. - * - * @param LoggerInterface $logger - * @param string $code - * @param string|null $wsdl - * @param array $options */ - public function __construct(LoggerInterface $logger, string $code, ?string $wsdl, array $options) + public function __construct(private readonly LoggerInterface $logger, private readonly string $code, private ?string $wsdl, private array $options) { - $this->logger = $logger; - $this->code = $code; - $this->wsdl = $wsdl; - $this->options = $options; } - /** - * @return LoggerInterface - */ public function getLogger(): LoggerInterface { return $this->logger; } /** - * {@inheritdoc} * @throws \UnexpectedValueException */ public function getCode(): string { - if (!$this->code) { + if ('' === $this->code || '0' === $this->code) { throw new \UnexpectedValueException('Client code is not defined'); } return $this->code; } - /** - * {@inheritdoc} - */ public function getWsdl(): ?string { return $this->wsdl; } - /** - * {@inheritdoc} - */ public function setWsdl(?string $wsdl): void { $this->wsdl = $wsdl; } - /** - * {@inheritdoc} - */ public function getOptions(): array { return $this->options; } - /** - * {@inheritdoc} - */ public function setOptions(array $options): void { $this->options = $options; } - /** - * @return array|null - */ public function getSoapOptions(): ?array { return $this->soapOptions; } - /** - * @param array|null $soapOptions - */ - public function setSoapOptions(array $soapOptions = null): void + public function setSoapOptions(?array $soapOptions = null): void { $this->soapOptions = $soapOptions; } @@ -148,127 +108,94 @@ public function getSoapHeaders(): ?array /** * @param \SoapHeader[]|null $soapHeaders */ - public function setSoapHeaders(array $soapHeaders = null): void + public function setSoapHeaders(?array $soapHeaders = null): void { $this->soapHeaders = $soapHeaders; } - /** - * @return \SoapClient|null - */ public function getSoapClient(): ?\SoapClient { return $this->soapClient; } - /** - * @param \SoapClient $soapClient - */ public function setSoapClient(\SoapClient $soapClient): void { $this->soapClient = $soapClient; } - /** - * @return string - */ public function getLastRequest(): ?string { return $this->lastRequest; } - /** - * @param string $lastRequest - */ public function setLastRequest(?string $lastRequest): void { $this->lastRequest = $lastRequest; } - /** - * @return string - */ public function getLastRequestHeaders(): ?string { return $this->lastRequestHeaders; } - /** - * @param string $lastRequestHeaders - */ public function setLastRequestHeaders(?string $lastRequestHeaders): void { $this->lastRequestHeaders = $lastRequestHeaders; } - /** - * @return string - */ public function getLastResponse(): ?string { return $this->lastResponse; } - /** - * @param string $lastResponse - */ public function setLastResponse(?string $lastResponse): void { $this->lastResponse = $lastResponse; } - /** - * @return string - */ public function getLastResponseHeaders(): ?string { return $this->lastResponseHeaders; } - /** - * @param string $lastResponseHeaders - */ public function setLastResponseHeaders(?string $lastResponseHeaders): void { $this->lastResponseHeaders = $lastResponseHeaders; } /** - * {@inheritdoc} + * @return bool|mixed */ - public function call(string $method, array $input = []) + public function call(string $method, array $input = []): mixed { $this->initializeSoapClient(); - $callMethod = sprintf('soapCall%s', ucfirst($method)); + $callMethod = \sprintf('soapCall%s', ucfirst($method)); if (method_exists($this, $callMethod)) { return $this->$callMethod($input); } $this->getLogger()->notice( - sprintf("Soap call '%s' on '%s'", $method, $this->getWsdl()) + \sprintf("Soap call '%s' on '%s'", $method, $this->getWsdl()) ); return $this->doSoapCall($method, $input); } /** - * @param string $method - * @param array $input - * * @return bool|mixed */ - protected function doSoapCall(string $method, array $input = []) + protected function doSoapCall(string $method, array $input = []): mixed { - if (!$this->getSoapClient()) { + if (!$this->getSoapClient() instanceof \SoapClient) { throw new \InvalidArgumentException('Soap client is not initialized'); } try { $result = $this->getSoapClient()->__soapCall($method, $input, $this->getSoapOptions(), $this->getSoapHeaders()); - } /** @noinspection PhpRedundantCatchClauseInspection */ catch (\SoapFault $e) { + } /* @noinspection PhpRedundantCatchClauseInspection */ catch (\SoapFault $e) { $this->getLastRequestTrace(); $this->getLogger()->alert( - sprintf("Soap call '%s' on '%s' failed : %s", $method, $this->getWsdl(), $e->getMessage()), + \sprintf("Soap call '%s' on '%s' failed : %s", $method, $this->getWsdl(), $e->getMessage()), $this->getLastRequestTraceArray() ); @@ -277,9 +204,9 @@ protected function doSoapCall(string $method, array $input = []) $this->getLastRequestTrace(); - if (array_key_exists('trace', $this->getOptions()) && $this->getOptions()['trace']) { + if (\array_key_exists('trace', $this->getOptions()) && $this->getOptions()['trace']) { $this->getLogger()->debug( - sprintf("Trace of soap call '%s' on '%s'", $method, $this->getWsdl()), + \sprintf("Trace of soap call '%s' on '%s'", $method, $this->getWsdl()), $this->getLastRequestTraceArray() ); } @@ -288,23 +215,19 @@ protected function doSoapCall(string $method, array $input = []) } /** - * Initialize \SoapClient object - * - * @return void + * Initialize \SoapClient object. */ protected function initializeSoapClient(): void { - if (!$this->getSoapClient()) { + if (!$this->getSoapClient() instanceof \SoapClient) { $options = array_merge($this->getOptions(), ['trace' => true]); $this->setSoapClient(new \SoapClient($this->getWsdl(), $options)); } } - /** - */ protected function getLastRequestTrace(): void { - if ($this->getSoapClient()) { + if ($this->getSoapClient() instanceof \SoapClient) { $this->setLastRequest($this->getSoapClient()->__getLastRequest()); $this->setLastRequestHeaders($this->getSoapClient()->__getLastRequestHeaders()); $this->setLastResponse($this->getSoapClient()->__getLastResponse()); @@ -312,9 +235,6 @@ protected function getLastRequestTrace(): void } } - /** - * @return array - */ protected function getLastRequestTraceArray(): array { return [ diff --git a/src/Client/ClientInterface.php b/src/Client/ClientInterface.php index e584068..0ba3ced 100644 --- a/src/Client/ClientInterface.php +++ b/src/Client/ClientInterface.php @@ -1,8 +1,11 @@ - - */ interface ClientInterface { /** * Return the code of the client used in client registry. - * - * @return string */ public function getCode(): string; /** * Return the URI of the WSDL file or NULL if working in non-WSDL mode. - * - * @return string */ public function getWsdl(): ?string; /** * Set the URI of the WSDL file or NULL if working in non-WSDL mode. - * - * @param string $wsdl - * - * @return void */ public function setWsdl(?string $wsdl): void; /** - * Return the Soap client options + * Return the Soap client options. * * @see http://php.net/manual/en/soapclient.soapclient.php - * - * @return array */ public function getOptions(): array; /** - * Set the Soap client options + * Set the Soap client options. * * @see http://php.net/manual/en/soapclient.soapclient.php - * - * @param array $options - * - * @return void */ public function setOptions(array $options): void; /** - * Return the Soap call options + * Return the Soap call options. * * @see https://www.php.net/manual/en/soapclient.soapcall.php - * - * @return array|null */ public function getSoapOptions(): ?array; /** - * Set the Soap call options + * Set the Soap call options. * * @see https://www.php.net/manual/en/soapclient.soapcall.php - * - * @param array|null $options - * - * @return void */ - public function setSoapOptions(array $options = null): void; + public function setSoapOptions(?array $options = null): void; /** - * Return the Soap call headers + * Return the Soap call headers. * * @see https://www.php.net/manual/en/soapclient.soapcall.php * @@ -90,43 +68,26 @@ public function setSoapOptions(array $options = null): void; public function getSoapHeaders(): ?array; /** - * Set the Soap call headers + * Set the Soap call headers. * * @see https://www.php.net/manual/en/soapclient.soapcall.php * * @param \SoapHeader[]|null $headers - * - * @return void */ - public function setSoapHeaders(array $headers = null): void; + public function setSoapHeaders(?array $headers = null): void; - /** - * @return string - */ public function getLastRequest(): ?string; - /** - * @return string - */ public function getLastRequestHeaders(): ?string; - /** - * @return string - */ public function getLastResponse(): ?string; - /** - * @return string - */ public function getLastResponseHeaders(): ?string; /** - * Call Soap method - * - * @param string $method - * @param array $input + * Call Soap method. * - * @return mixed + * @return bool|mixed */ - public function call(string $method, array $input = []); + public function call(string $method, array $input = []): mixed; } diff --git a/src/DependencyInjection/CleverAgeSoapProcessExtension.php b/src/DependencyInjection/CleverAgeSoapProcessExtension.php index f40716c..08461da 100644 --- a/src/DependencyInjection/CleverAgeSoapProcessExtension.php +++ b/src/DependencyInjection/CleverAgeSoapProcessExtension.php @@ -1,8 +1,11 @@ - */ @@ -21,8 +24,6 @@ class MissingClientException extends \UnexpectedValueException implements Proces { /** * @param string $code - * - * @return MissingClientException */ public static function create($code): self { diff --git a/src/Registry/ClientRegistry.php b/src/Registry/ClientRegistry.php index c7a92e0..479da20 100644 --- a/src/Registry/ClientRegistry.php +++ b/src/Registry/ClientRegistry.php @@ -1,8 +1,11 @@ - */ class ClientRegistry { /** @var ClientInterface[] */ - private $clients = []; + private array $clients = []; - /** - * @param ClientInterface $client - */ public function addClient(ClientInterface $client): void { - if (array_key_exists($client->getCode(), $this->getClients())) { + if (\array_key_exists($client->getCode(), $this->getClients())) { throw new \UnexpectedValueException("Client {$client->getCode()} is already defined"); } $this->clients[$client->getCode()] = $client; @@ -43,13 +43,9 @@ public function getClients(): array } /** - * @param string $code - * * @throws MissingClientException - * - * @return ClientInterface */ - public function getClient($code): ClientInterface + public function getClient(string $code): ClientInterface { if (!$this->hasClient($code)) { throw MissingClientException::create($code); @@ -58,13 +54,8 @@ public function getClient($code): ClientInterface return $this->getClients()[$code]; } - /** - * @param string $code - * - * @return bool - */ - public function hasClient($code): bool + public function hasClient(string $code): bool { - return array_key_exists($code, $this->getClients()); + return \array_key_exists($code, $this->getClients()); } } diff --git a/src/Task/RequestTask.php b/src/Task/RequestTask.php index 8e0200e..8cd38ea 100644 --- a/src/Task/RequestTask.php +++ b/src/Task/RequestTask.php @@ -1,8 +1,11 @@ - - */ class RequestTask extends AbstractConfigurableTask { - - /** @var LoggerInterface */ - protected $logger; - - /** @var ClientRegistry */ - protected $registry; - - /** - * SoapClientTask constructor. - * - * @param LoggerInterface $logger - * @param ClientRegistry $registry - */ - public function __construct(LoggerInterface $logger, ClientRegistry $registry) + public function __construct(protected LoggerInterface $logger, protected ClientRegistry $registry) { - $this->logger = $logger; - $this->registry = $registry; } - /** - * {@inheritdoc} - */ public function execute(ProcessState $state): void { $options = $this->getOptions($state); @@ -74,9 +54,9 @@ public function execute(ProcessState $state): void $this->logger->error('Empty resultset for query', $logContext); - if ($state->getTaskConfiguration()->getErrorStrategy() === TaskConfiguration::STRATEGY_SKIP) { + if (TaskConfiguration::STRATEGY_SKIP === $state->getTaskConfiguration()->getErrorStrategy()) { $state->setSkipped(true); - } elseif ($state->getTaskConfiguration()->getErrorStrategy() === TaskConfiguration::STRATEGY_STOP) { + } elseif (TaskConfiguration::STRATEGY_STOP === $state->getTaskConfiguration()->getErrorStrategy()) { $state->setStopped(true); } } @@ -84,9 +64,6 @@ public function execute(ProcessState $state): void $state->setOutput($result); } - /** - * {@inheritdoc} - */ protected function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired( @@ -107,7 +84,7 @@ protected function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('soap_call_headers', ['array', 'null']); $resolver->setNormalizer('soap_call_headers', function (Options $options, $headers) { - if ($headers === null) { + if (null === $headers) { return null; } @@ -124,7 +101,7 @@ protected function configureOptions(OptionsResolver $resolver): void }); } - protected function configureSoapCallHeaderOption(OptionsResolver $resolver) + protected function configureSoapCallHeaderOption(OptionsResolver $resolver): void { $resolver->setRequired('namespace'); $resolver->setRequired('data'); diff --git a/src/Transformer/RequestTransformer.php b/src/Transformer/RequestTransformer.php index 361a380..b939624 100644 --- a/src/Transformer/RequestTransformer.php +++ b/src/Transformer/RequestTransformer.php @@ -1,8 +1,11 @@ - - */ class RequestTransformer implements ConfigurableTransformerInterface { - /** @var ClientRegistry */ - protected $registry; - - /** - * RequestTransformer constructor. - * - * @param ClientRegistry $registry - */ - public function __construct(ClientRegistry $registry) + public function __construct(protected ClientRegistry $registry) { - $this->registry = $registry; } - - /** - * {@inheritdoc} - */ - public function transform($value, array $options = []) + public function transform(mixed $value, array $options = []): mixed { $resolver = new OptionsResolver(); $this->configureOptions($resolver); @@ -50,18 +35,13 @@ public function transform($value, array $options = []) } /** - * Returns the unique code to identify the transformer - * - * @return string + * Returns the unique code to identify the transformer. */ public function getCode(): string { return 'soap_request'; } - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver): void { $resolver->setRequired( From 23ab648d6485ac9b1af5cfd71bb56f77d2827ce0 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 24 Oct 2024 15:44:32 +0200 Subject: [PATCH 07/15] #4 Update services according to Symfony best practices. Services should not use autowiring or autoconfiguration. Instead, all services should be defined explicitly. Services must be prefixed with the bundle alias instead of using fully qualified class names => `cleverage_soap_process` --- CHANGELOG.md | 5 +++++ config/services/registry.yaml | 4 ++++ config/services/task.yaml | 9 +++++++++ config/services/transformer.yaml | 9 +++++++++ src/CleverAgeSoapProcessBundle.php | 12 +++++------- .../CleverAgeSoapProcessExtension.php | 2 +- src/Resources/config/services/registry.yaml | 3 --- src/Resources/config/services/task.yaml | 8 -------- src/Resources/config/services/transformer.yaml | 8 -------- 9 files changed, 33 insertions(+), 27 deletions(-) create mode 100644 config/services/registry.yaml create mode 100644 config/services/task.yaml create mode 100644 config/services/transformer.yaml delete mode 100644 src/Resources/config/services/registry.yaml delete mode 100644 src/Resources/config/services/task.yaml delete mode 100644 src/Resources/config/services/transformer.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ce9659..453466d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ v2.0 ## BC breaks +* [#4](https://github.com/cleverage/soap-process-bundle/issues/4) Update services according to Symfony best practices. +Services should not use autowiring or autoconfiguration. Instead, all services should be defined explicitly. +Services must be prefixed with the bundle alias instead of using fully qualified class names => `cleverage_soap_process` + + ### Changes * [#2](https://github.com/cleverage/soap-process-bundle/issues/2) Add Makefile & .docker for local standalone usage diff --git a/config/services/registry.yaml b/config/services/registry.yaml new file mode 100644 index 0000000..80986ba --- /dev/null +++ b/config/services/registry.yaml @@ -0,0 +1,4 @@ +services: + cleverage_soap_process.registry.client: + class: CleverAge\SoapProcessBundle\Registry\ClientRegistry + public: false diff --git a/config/services/task.yaml b/config/services/task.yaml new file mode 100644 index 0000000..b1c68ae --- /dev/null +++ b/config/services/task.yaml @@ -0,0 +1,9 @@ +services: + cleverage_soap_process.task.request: + class: CleverAge\SoapProcessBundle\Task\RequestTask + public: false + arguments: + - '@monolog.logger' + - '@cleverage_soap_process.registry.client' + tags: + - { name: monolog.logger, channel: cleverage_process_task } diff --git a/config/services/transformer.yaml b/config/services/transformer.yaml new file mode 100644 index 0000000..12c401d --- /dev/null +++ b/config/services/transformer.yaml @@ -0,0 +1,9 @@ +services: + cleverage_soap_process.transformer.request: + class: CleverAge\SoapProcessBundle\Transformer\RequestTransformer + public: false + arguments: + - '@cleverage_soap_process.registry.client' + tags: + - { name: cleverage.transformer } + - { name: monolog.logger, channel: cleverage_process_transformer } diff --git a/src/CleverAgeSoapProcessBundle.php b/src/CleverAgeSoapProcessBundle.php index 4fff13d..84ed891 100644 --- a/src/CleverAgeSoapProcessBundle.php +++ b/src/CleverAgeSoapProcessBundle.php @@ -18,13 +18,6 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; -/** - * Class CleverAgeSoapProcessBundle. - * - * @author Valentin Clavreul - * @author Vincent Chalnot - * @author Madeline Veyrenc - */ class CleverAgeSoapProcessBundle extends Bundle { /** @@ -40,4 +33,9 @@ public function build(ContainerBuilder $container): void ) ); } + + public function getPath(): string + { + return \dirname(__DIR__); + } } diff --git a/src/DependencyInjection/CleverAgeSoapProcessExtension.php b/src/DependencyInjection/CleverAgeSoapProcessExtension.php index 08461da..2114981 100644 --- a/src/DependencyInjection/CleverAgeSoapProcessExtension.php +++ b/src/DependencyInjection/CleverAgeSoapProcessExtension.php @@ -28,7 +28,7 @@ class CleverAgeSoapProcessExtension extends Extension { public function load(array $configs, ContainerBuilder $container): void { - $this->findServices($container, __DIR__.'/../Resources/config/services'); + $this->findServices($container, __DIR__.'/../../config/services'); } /** diff --git a/src/Resources/config/services/registry.yaml b/src/Resources/config/services/registry.yaml deleted file mode 100644 index ad1a6cf..0000000 --- a/src/Resources/config/services/registry.yaml +++ /dev/null @@ -1,3 +0,0 @@ -services: - CleverAge\SoapProcessBundle\Registry\ClientRegistry: - public: false diff --git a/src/Resources/config/services/task.yaml b/src/Resources/config/services/task.yaml deleted file mode 100644 index 559188f..0000000 --- a/src/Resources/config/services/task.yaml +++ /dev/null @@ -1,8 +0,0 @@ -services: - CleverAge\SoapProcessBundle\Task\: - resource: '../../../Task/*' - autowire: true - public: true - shared: false - tags: - - { name: monolog.logger, channel: cleverage_process_task } diff --git a/src/Resources/config/services/transformer.yaml b/src/Resources/config/services/transformer.yaml deleted file mode 100644 index 1b82991..0000000 --- a/src/Resources/config/services/transformer.yaml +++ /dev/null @@ -1,8 +0,0 @@ -services: - CleverAge\SoapProcessBundle\Transformer\: - resource: '../../../Transformer/*' - autowire: true - public: false - tags: - - { name: cleverage.transformer } - - { name: monolog.logger, channel: cleverage_process_transformer } From 69528d6ea9ff647ecf2484757263f735567c23d2 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Thu, 24 Oct 2024 16:02:43 +0200 Subject: [PATCH 08/15] Minor README fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e84b12..b9f3384 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Compatible with [Symfony stable version and latest Long-Term Support (LTS) relea ## Documentation For usage documentation, see: -[docs/index.md](doc/index.md) +[docs/index.md](docs/index.md) ## Support & Contribution From aed3d6fa6d7ae98235bd3b63bef99303ea21b094 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 29 Oct 2024 17:03:09 +0100 Subject: [PATCH 09/15] #2 Apply <10.0 restriction on phpunit/phpunit since configuration file is not compatible with 10.0+ --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7625004..88cd17a 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,7 @@ "phpstan/extension-installer": "*", "phpstan/phpstan": "*", "phpstan/phpstan-symfony": "*", - "phpunit/phpunit": "*", + "phpunit/phpunit": "<10.0", "rector/rector": "*", "roave/security-advisories": "dev-latest", "symfony/test-pack": "^1.1" From ecc47150df254cd1d39eb31c1d4b350879a54259 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Fri, 22 Nov 2024 09:53:48 +0100 Subject: [PATCH 10/15] #7 Aliasing Transformers & Tasks with FQCN to maintain old release configuration compatibility. --- config/services/task.yaml | 2 ++ config/services/transformer.yaml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/config/services/task.yaml b/config/services/task.yaml index b1c68ae..7650d8e 100644 --- a/config/services/task.yaml +++ b/config/services/task.yaml @@ -7,3 +7,5 @@ services: - '@cleverage_soap_process.registry.client' tags: - { name: monolog.logger, channel: cleverage_process_task } + CleverAge\SoapProcessBundle\Task\RequestTask: + alias: cleverage_soap_process.task.request diff --git a/config/services/transformer.yaml b/config/services/transformer.yaml index 12c401d..c84d641 100644 --- a/config/services/transformer.yaml +++ b/config/services/transformer.yaml @@ -7,3 +7,5 @@ services: tags: - { name: cleverage.transformer } - { name: monolog.logger, channel: cleverage_process_transformer } + CleverAge\SoapProcessBundle\Transformer\RequestTransformer: + alias: cleverage_soap_process.transformer.request From 7e984563cd4fd54875237ba9ef28b28cae895f76 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Wed, 27 Nov 2024 15:38:09 +0100 Subject: [PATCH 11/15] Set as public RequestTask. Fix RegistryCompilerPass using service name instead of class FQCN. --- config/services/task.yaml | 1 + src/CleverAgeSoapProcessBundle.php | 3 +-- src/Client/Client.php | 8 ++++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/config/services/task.yaml b/config/services/task.yaml index 7650d8e..f6f1983 100644 --- a/config/services/task.yaml +++ b/config/services/task.yaml @@ -9,3 +9,4 @@ services: - { name: monolog.logger, channel: cleverage_process_task } CleverAge\SoapProcessBundle\Task\RequestTask: alias: cleverage_soap_process.task.request + public: true diff --git a/src/CleverAgeSoapProcessBundle.php b/src/CleverAgeSoapProcessBundle.php index 84ed891..7a61aa5 100644 --- a/src/CleverAgeSoapProcessBundle.php +++ b/src/CleverAgeSoapProcessBundle.php @@ -14,7 +14,6 @@ namespace CleverAge\SoapProcessBundle; use CleverAge\ProcessBundle\DependencyInjection\Compiler\RegistryCompilerPass; -use CleverAge\SoapProcessBundle\Registry\ClientRegistry; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -27,7 +26,7 @@ public function build(ContainerBuilder $container): void { $container->addCompilerPass( new RegistryCompilerPass( - ClientRegistry::class, + 'cleverage_soap_process.registry.client', 'cleverage.soap.client', 'addClient' ) diff --git a/src/Client/Client.php b/src/Client/Client.php index 1c81465..edabfe1 100644 --- a/src/Client/Client.php +++ b/src/Client/Client.php @@ -46,8 +46,12 @@ class Client implements ClientInterface /** * Client constructor. */ - public function __construct(private readonly LoggerInterface $logger, private readonly string $code, private ?string $wsdl, private array $options) - { + public function __construct( + private readonly LoggerInterface $logger, + private readonly string $code, + private ?string $wsdl, + private array $options = [], + ) { } public function getLogger(): LoggerInterface From e219a3926d72ee586a20389da4c2e04d343a274a Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Fri, 29 Nov 2024 15:46:13 +0100 Subject: [PATCH 12/15] Add RequestTask doc --- docs/index.md | 2 +- docs/reference/tasks/request_task.md | 77 ++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 docs/reference/tasks/request_task.md diff --git a/docs/index.md b/docs/index.md index 24dee03..47d52d3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,6 +22,6 @@ CleverAge\SoapProcessBundle\CleverAgeSoapProcessBundle::class => ['all' => true] ## Reference - Tasks - - [RequestTask] + - [RequestTask](reference/tasks/request_task.md) - Transformers - [RequestTransformer] diff --git a/docs/reference/tasks/request_task.md b/docs/reference/tasks/request_task.md new file mode 100644 index 0000000..028cf06 --- /dev/null +++ b/docs/reference/tasks/request_task.md @@ -0,0 +1,77 @@ +RequestTask +=============== + +Call a SOAP Request and get result. + +Task reference +-------------- + +* **Client Service Interface**: `CleverAge\SoapProcessBundle\Client\ClientInterface` +* **Task Service**: `CleverAge\SoapProcessBundle\Task\RequestTask` + +Accepted inputs +--------------- + +`array`: list of of the arguments to pass as `$args` to the [SoapClient::__soapCall()](https://www.php.net/manual/en/soapclient.soapcall.php) method. + +Possible outputs +---------------- + +`false|stdClass|array`: the result of the soap call. + +Options +------- + +### For Client + +| Code | Type | Required | Default | Description | +|-----------------|------------------|:---------:|---------|-------------------------------------------------------------------------------| +| `code` | `string` | **X** | | Service identifier, used by Task client option | +| `wsdl` | `string or null` | | | URI of a WSDL file describing the service | +| `options` | `array` | | [] | An associative array specifying additional options for the SOAP client. | +| `options.trace` | `boolean` | | true | Captures request and response information. Add debug informations into logger | + +Calls setter methods in `CleverAge\SoapProcessBundle\Client\ClientInterface` to add more options. + +### For Task + +| Code | Type | Required | Default | Description | +|-------------------------------|-----------------------------------------------|:----------------------------------------:|---------|---------------------------------------------------------------------| +| `client` | `string` | **X** | | `ClientInterface` service identifier | +| `method` | `string` | **X** | | The name of the SOAP function to call. | +| `soap_call_options` | `array or null` | | null | An associative array of options to pass to the client. | +| `soap_call_headers` | `array or null` resolved as \SoapHeader array | | null | An array of headers to be sent along with the SOAP request. | +| `soap_call_headers.namespace` | `array or null` | **X** if `soap_call_headers` is not null | | The namespace of the SOAP header element. | +| `soap_call_headers.data` | `array or null` | **X** if `soap_call_headers` is not null | | A SOAP header's content. It can be a PHP value or a SoapVar object. | + +Examples +-------- + +### Client + +```yaml +services: + app.cleverage_soap_process.client.domain_sample: + class: CleverAge\SoapProcessBundle\Client\Client + bind: + $code: 'domain_sample' + $wsdl: 'https://domain/sample.wsdl' + $options: + trace: true + exceptions: true + calls: + - [ setSoapOptions, [ { features: SOAP_SINGLE_ELEMENT_ARRAYS} ] ] + tags: + - { name: cleverage.soap.client } +``` + +### Task + +```yaml +# Task configuration level +code: + service: '@CleverAge\SoapProcessBundle\Task\RequestTask' + options: + client: domain_sample + method: 'MethodToCall' +``` From 804317852cba4ab86d5e990ac081ce2808bc0594 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Fri, 13 Dec 2024 10:33:28 +0100 Subject: [PATCH 13/15] #8 Remove all phpstan ignoreErrors. Fix code. --- phpstan.neon | 13 ------------- src/Client/Client.php | 18 +++++++++++++----- src/Client/ClientInterface.php | 10 ++++++++++ src/Task/RequestTask.php | 1 + src/Transformer/RequestTransformer.php | 10 ++++++++++ 5 files changed, 34 insertions(+), 18 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 30e9572..63aadba 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3,16 +3,3 @@ parameters: paths: - src - tests - ignoreErrors: - - '#type has no value type specified in iterable type#' - - '#has parameter .* with no value type specified in iterable type#' - - '#has no value type specified in iterable type array#' - - '#configureOptions\(\) has no return type specified.#' - - '#configure\(\) has no return type specified#' - - '#process\(\) has no return type specified#' - - '#should return Iterator but returns Traversable#' - - '#Negated boolean expression is always false#' - checkGenericClassInNonGenericObjectType: false - reportUnmatchedIgnoredErrors: false - inferPrivatePropertyTypeFromConstructor: true - treatPhpDocTypesAsCertain: false diff --git a/src/Client/Client.php b/src/Client/Client.php index edabfe1..2d1eee7 100644 --- a/src/Client/Client.php +++ b/src/Client/Client.php @@ -22,7 +22,7 @@ */ class Client implements ClientInterface { - /** @var array */ + /** @var array|null */ private $soapOptions; /** @var \SoapHeader[]|null */ @@ -50,6 +50,7 @@ public function __construct( private readonly LoggerInterface $logger, private readonly string $code, private ?string $wsdl, + /** @var array */ private array $options = [], ) { } @@ -167,9 +168,6 @@ public function setLastResponseHeaders(?string $lastResponseHeaders): void $this->lastResponseHeaders = $lastResponseHeaders; } - /** - * @return bool|mixed - */ public function call(string $method, array $input = []): mixed { $this->initializeSoapClient(); @@ -187,6 +185,8 @@ public function call(string $method, array $input = []): mixed } /** + * @param array $input + * * @return bool|mixed */ protected function doSoapCall(string $method, array $input = []): mixed @@ -196,7 +196,7 @@ protected function doSoapCall(string $method, array $input = []): mixed } try { $result = $this->getSoapClient()->__soapCall($method, $input, $this->getSoapOptions(), $this->getSoapHeaders()); - } /* @noinspection PhpRedundantCatchClauseInspection */ catch (\SoapFault $e) { + } catch (\SoapFault $e) { $this->getLastRequestTrace(); $this->getLogger()->alert( \sprintf("Soap call '%s' on '%s' failed : %s", $method, $this->getWsdl(), $e->getMessage()), @@ -239,6 +239,14 @@ protected function getLastRequestTrace(): void } } + /** + * @return array{ + * 'LastRequest': ?string, + * 'LastRequestHeaders': ?string, + * 'LastResponse': ?string, + * 'LastResponseHeaders': ?string + * } + */ protected function getLastRequestTraceArray(): array { return [ diff --git a/src/Client/ClientInterface.php b/src/Client/ClientInterface.php index 0ba3ced..10fbd55 100644 --- a/src/Client/ClientInterface.php +++ b/src/Client/ClientInterface.php @@ -34,6 +34,8 @@ public function setWsdl(?string $wsdl): void; * Return the Soap client options. * * @see http://php.net/manual/en/soapclient.soapclient.php + * + * @return array */ public function getOptions(): array; @@ -41,6 +43,8 @@ public function getOptions(): array; * Set the Soap client options. * * @see http://php.net/manual/en/soapclient.soapclient.php + * + * @param array $options */ public function setOptions(array $options): void; @@ -48,6 +52,8 @@ public function setOptions(array $options): void; * Return the Soap call options. * * @see https://www.php.net/manual/en/soapclient.soapcall.php + * + * @return array|null */ public function getSoapOptions(): ?array; @@ -55,6 +61,8 @@ public function getSoapOptions(): ?array; * Set the Soap call options. * * @see https://www.php.net/manual/en/soapclient.soapcall.php + * + * @param array|null $options */ public function setSoapOptions(?array $options = null): void; @@ -87,6 +95,8 @@ public function getLastResponseHeaders(): ?string; /** * Call Soap method. * + * @param array $input + * * @return bool|mixed */ public function call(string $method, array $input = []): mixed; diff --git a/src/Task/RequestTask.php b/src/Task/RequestTask.php index 8cd38ea..84f7082 100644 --- a/src/Task/RequestTask.php +++ b/src/Task/RequestTask.php @@ -33,6 +33,7 @@ public function execute(ProcessState $state): void $client = $this->registry->getClient($options['client']); + /** @var array $input */ $input = $state->getInput() ?: []; $client->setSoapOptions($this->getOption($state, 'soap_call_options')); diff --git a/src/Transformer/RequestTransformer.php b/src/Transformer/RequestTransformer.php index b939624..3f97807 100644 --- a/src/Transformer/RequestTransformer.php +++ b/src/Transformer/RequestTransformer.php @@ -17,16 +17,26 @@ use CleverAge\SoapProcessBundle\Registry\ClientRegistry; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @phpstan-type Options array{ + * 'client': string, + * 'method': string, + * } + */ class RequestTransformer implements ConfigurableTransformerInterface { public function __construct(protected ClientRegistry $registry) { } + /** + * @param array $options + */ public function transform(mixed $value, array $options = []): mixed { $resolver = new OptionsResolver(); $this->configureOptions($resolver); + /** @var Options $options */ $options = $resolver->resolve($options); $client = $this->registry->getClient($options['client']); From 41809a18d8673290929f6020f70325f04603e286 Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Fri, 13 Dec 2024 11:03:44 +0100 Subject: [PATCH 14/15] #8 Apply phpstan level 10 --- phpstan.neon | 2 +- src/Client/Client.php | 30 +++++++++++--------------- src/Task/RequestTask.php | 19 ++++++++++++++-- src/Transformer/RequestTransformer.php | 8 +++++-- 4 files changed, 37 insertions(+), 22 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 63aadba..e9a9e7e 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,5 @@ parameters: - level: 6 + level: 10 paths: - src - tests diff --git a/src/Client/Client.php b/src/Client/Client.php index 2d1eee7..9d98faa 100644 --- a/src/Client/Client.php +++ b/src/Client/Client.php @@ -23,25 +23,20 @@ class Client implements ClientInterface { /** @var array|null */ - private $soapOptions; + private ?array $soapOptions = null; /** @var \SoapHeader[]|null */ - private $soapHeaders; + private ?array $soapHeaders = null; - /** @var \SoapClient */ - private $soapClient; + private ?\SoapClient $soapClient = null; - /** @var string */ - private $lastRequest; + private ?string $lastRequest = null; - /** @var string */ - private $lastRequestHeaders; + private ?string $lastRequestHeaders = null; - /** @var string */ - private $lastResponse; + private ?string $lastResponse = null; - /** @var string */ - private $lastResponseHeaders; + private ?string $lastResponseHeaders = null; /** * Client constructor. @@ -231,11 +226,12 @@ protected function initializeSoapClient(): void protected function getLastRequestTrace(): void { - if ($this->getSoapClient() instanceof \SoapClient) { - $this->setLastRequest($this->getSoapClient()->__getLastRequest()); - $this->setLastRequestHeaders($this->getSoapClient()->__getLastRequestHeaders()); - $this->setLastResponse($this->getSoapClient()->__getLastResponse()); - $this->setLastResponseHeaders($this->getSoapClient()->__getLastResponseHeaders()); + $soapClient = $this->getSoapClient(); + if ($soapClient instanceof \SoapClient) { + $this->setLastRequest($soapClient->__getLastRequest()); + $this->setLastRequestHeaders($soapClient->__getLastRequestHeaders()); + $this->setLastResponse($soapClient->__getLastResponse()); + $this->setLastResponseHeaders($soapClient->__getLastResponseHeaders()); } } diff --git a/src/Task/RequestTask.php b/src/Task/RequestTask.php index 84f7082..428e358 100644 --- a/src/Task/RequestTask.php +++ b/src/Task/RequestTask.php @@ -21,6 +21,14 @@ use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; +/** + * @phpstan-type RequestOptions array{ + * 'client': string, + * 'method': string, + * 'soap_call_options': array|null, + * 'soap_call_headers': array<\SoapHeader>|null, + * } + */ class RequestTask extends AbstractConfigurableTask { public function __construct(protected LoggerInterface $logger, protected ClientRegistry $registry) @@ -29,6 +37,7 @@ public function __construct(protected LoggerInterface $logger, protected ClientR public function execute(ProcessState $state): void { + /** @var RequestOptions $options */ $options = $this->getOptions($state); $client = $this->registry->getClient($options['client']); @@ -36,8 +45,12 @@ public function execute(ProcessState $state): void /** @var array $input */ $input = $state->getInput() ?: []; - $client->setSoapOptions($this->getOption($state, 'soap_call_options')); - $client->setSoapHeaders($this->getOption($state, 'soap_call_headers')); + /** @var array|null $soapCallOptions */ + $soapCallOptions = $this->getOption($state, 'soap_call_options'); + $client->setSoapOptions($soapCallOptions); + /** @var array<\SoapHeader>|null $soapCallHeaders */ + $soapCallHeaders = $this->getOption($state, 'soap_call_headers'); + $client->setSoapHeaders($soapCallHeaders); $result = $client->call($options['method'], $input); @@ -93,7 +106,9 @@ protected function configureOptions(OptionsResolver $resolver): void $this->configureSoapCallHeaderOption($headerResolver); $resolvedHeaders = []; + /** @var array> $headers */ foreach ($headers as $name => $header) { + /** @var array{'namespace': string, 'data': array} $resolvedHeader */ $resolvedHeader = $headerResolver->resolve($header); $resolvedHeaders[] = new \SoapHeader($resolvedHeader['namespace'], $name, $resolvedHeader['data']); } diff --git a/src/Transformer/RequestTransformer.php b/src/Transformer/RequestTransformer.php index 3f97807..3e3c2d5 100644 --- a/src/Transformer/RequestTransformer.php +++ b/src/Transformer/RequestTransformer.php @@ -18,7 +18,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** - * @phpstan-type Options array{ + * @phpstan-type TransformerOptions array{ * 'client': string, * 'method': string, * } @@ -34,9 +34,13 @@ public function __construct(protected ClientRegistry $registry) */ public function transform(mixed $value, array $options = []): mixed { + if (!\is_array($value)) { + throw new \UnexpectedValueException('Expecting an array of value'); + } + $resolver = new OptionsResolver(); $this->configureOptions($resolver); - /** @var Options $options */ + /** @var TransformerOptions $options */ $options = $resolver->resolve($options); $client = $this->registry->getClient($options['client']); From 69c7bcfd5729290c4619c30cfcb474f7addcdc9f Mon Sep 17 00:00:00 2001 From: Nicolas Joubert Date: Tue, 17 Dec 2024 15:39:29 +0100 Subject: [PATCH 15/15] #5 Bump dependency "cleverage/process-bundle": "^4.0" --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 88cd17a..ba7d745 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "require": { "php": ">=8.1", "ext-soap": "*", - "cleverage/process-bundle": "dev-prepare-release" + "cleverage/process-bundle": "^4.0.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "*",