diff --git a/.github/workflows/license-check.yml b/.github/workflows/license-check.yml index 9730755f..53d5a467 100644 --- a/.github/workflows/license-check.yml +++ b/.github/workflows/license-check.yml @@ -12,8 +12,8 @@ jobs: fail-fast: false matrix: php-version: - - "8.2" - "8.3" + - "8.4" dependencies: [ highest ] operating-system: [ ubuntu-latest] diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml index eb8cbc5f..e4cb0ba4 100644 --- a/.github/workflows/php-cs-fixer.yml +++ b/.github/workflows/php-cs-fixer.yml @@ -12,8 +12,8 @@ jobs: fail-fast: false matrix: php-version: - - "8.2" - "8.3" + - "8.4" dependencies: [ highest ] operating-system: [ ubuntu-latest] diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index f18b6af3..bd1391b5 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -12,8 +12,8 @@ jobs: fail-fast: false matrix: php-version: - - "8.2" - "8.3" + - "8.4" dependencies: [ highest ] operating-system: [ ubuntu-latest] diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 3b9be25a..c19de5e0 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -16,8 +16,8 @@ jobs: fail-fast: false matrix: php-version: - - "8.2" - "8.3" + - "8.4" dependencies: [ highest ] operating-system: [ ubuntu-latest, windows-2022] diff --git a/.github/workflows/rector.yml b/.github/workflows/rector.yml index 11c4f7d0..22f49f06 100644 --- a/.github/workflows/rector.yml +++ b/.github/workflows/rector.yml @@ -16,8 +16,8 @@ jobs: fail-fast: false matrix: php-version: - - "8.2" - "8.3" + - "8.4" dependencies: [ highest ] operating-system: [ ubuntu-latest] diff --git a/CHANGELOG.md b/CHANGELOG.md index 80e0afe9..589c5897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # b24-php-sdk change log -## 1.8.0 - 2025.11.01 (in progress) +## 1.8.0 - 2025.11.08 ### Added @@ -51,6 +51,20 @@ - `changeMobilePhone(?PhoneNumber $phoneNumber)` - removed second parameter `?bool $isMobilePhoneVerified`. Migration path: call `markMobilePhoneAsVerified()` separately after `changeMobilePhone()` if phone needs to be verified - Replaced `getUserAgent()`, `getUserAgentReferer()`, `getUserAgentIp()` methods with single `getUserAgentInfo(): UserAgentInfo` method that returns complete user agent information object. Migration path: use `$info->userAgent`, `$info->referrer`, `$info->ip` properties instead - Updated `RemoteEventsFactory::validate()` method signature from `validate(EventInterface $event, string $applicationToken)` to `validate(Bitrix24AccountInterface $bitrix24Account, EventInterface $event)`. Now uses `Bitrix24AccountInterface::isApplicationTokenValid()` for token validation instead of direct string comparison +- **Docker configuration updated to PHP 8.4** - Development environment now uses PHP 8.4.14 (docker/php-cli/Dockerfile): + - Upgraded from PHP 8.3 to PHP 8.4 base image (`php:8.4-cli-bookworm`) + - Updated Composer to version 2.8 + - Added PHP extension installer v2.4 from mlocati for easier extension management + - Added new PHP extensions: `amqp`, `excimer`, `opcache`, `pcntl`, `yaml`, `zip` + - Changed base OS from Alpine to Debian Bookworm for better compatibility + - Implemented multi-stage Docker build for optimized image size + - Added proper user/group ID mapping for www-data user (UID/GID 10001) + - Set proper working directory ownership and non-root user execution +- **PHP 8.4 compatibility improvements**: + - Rector configuration updated to use `LevelSetList::UP_TO_PHP_84` for PHP 8.4 feature detection + - PHPUnit configuration updated to PHPUnit 11.0 attribute set (`PHPUnitSetList::PHPUNIT_110`) + - Fixed all implicitly nullable parameter deprecation warnings (8 occurrences) + - Fixed PHPStan internal errors with `random_int()` range handling ### Fixed diff --git a/composer.json b/composer.json index 4b3a97ae..4947c47d 100644 --- a/composer.json +++ b/composer.json @@ -55,7 +55,7 @@ "monolog/monolog": "^3", "nyholm/psr7": "^1.8", "openai-php/client": "0.10.*", - "phpstan/phpstan": "1.11.7", + "phpstan/phpstan": "^1", "phpunit/phpunit": "^10 || ^11|| ^12", "rector/rector": "^1", "roave/security-advisories": "dev-master", diff --git a/docker/php-cli/Dockerfile b/docker/php-cli/Dockerfile index 2d6143a6..4d6f31f6 100644 --- a/docker/php-cli/Dockerfile +++ b/docker/php-cli/Dockerfile @@ -1,27 +1,53 @@ -#FROM php:8.3-cli-alpine # -#RUN apk add unzip libpq-dev git icu-dev \ -# && docker-php-ext-install bcmath intl \ -# && docker-php-ext-enable bcmath intl +# This file is part of the bitrix24-php-sdk package. # -#RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/bin --filename=composer --quiet +# © Maksim Mesilov # -#ENV COMPOSER_ALLOW_SUPERUSER 1 +# For the full copyright and license information, please view the MIT-LICENSE.txt +# file that was distributed with this source code. +# + +# Grab the PHP extension installer script from mlocati's image +# https://github.com/mlocati/docker-php-extension-installer#readme +FROM mlocati/php-extension-installer:2.4 AS php-extension-installer + +# Separate Composer stage to install PHP dependencies efficiently +# https://hub.docker.com/_/composer +FROM composer:2.8 AS composer + +# Using official PHP 8.3 CLI image based on Debian Bookworm for development purposes +FROM php:8.4-cli-bookworm AS dev-php + +# Copy Composer binary from the official Composer image +COPY --from=composer /usr/bin/composer /usr/bin/composer +# Copy PHP extension installer script from mlocati's image +COPY --from=php-extension-installer /usr/bin/install-php-extensions /usr/bin/install-php-extensions + +# Link to the source repository for this image (OCI standard label) +LABEL "org.opencontainers.image.source"="https://github.com/bitrix24/b24sdk-cli" + +ARG UID=10001 +ARG GID=10001 + +RUN <Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Core/Result/FieldsResult.php)| |`crm`|[crm.product.list](https://training.bitrix24.com/rest_help/crm/products/crm_product_list.php)|Get list of product items.|[`Bitrix24\SDK\Services\CRM\Product\Service\Product::list`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Product/Service/Product.php#L186-L199)
Return type
[`Bitrix24\SDK\Services\CRM\Product\Result\ProductsResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Product/Result/ProductsResult.php)

⚡️Batch methods:
| |`crm`|[crm.product.update](https://training.bitrix24.com/rest_help/crm/products/crm_product_update.php)|Updates the specified (existing) product.|[`Bitrix24\SDK\Services\CRM\Product\Service\Product::update`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Product/Service/Product.php#L240-L251)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Core/Result/UpdatedItemResult.php)| +|`crm`|[crm.type.fields](https://apidocs.bitrix24.com/api-reference/crm/universal/user-defined-object-types/crm-type-fields.html)|This method retrieves information about the custom fields of the smart process settings.|[`Bitrix24\SDK\Services\CRM\Type\Service\Type::fields`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Type/Service/Type.php#L47-L50)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Core/Result/FieldsResult.php)| +|`crm`|[crm.type.add](https://apidocs.bitrix24.com/api-reference/crm/universal/user-defined-object-types/crm-type-add.html)|This method creates a new SPA.|[`Bitrix24\SDK\Services\CRM\Type\Service\Type::add`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Type/Service/Type.php#L69-L79)
Return type
[`Bitrix24\SDK\Services\CRM\Type\Result\AddedTypeItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Type/Result/AddedTypeItemResult.php)| +|`crm`|[crm.type.update](https://apidocs.bitrix24.com/api-reference/crm/universal/user-defined-object-types/crm-type-update.html)|This method updates an existing SPA by its identifier id.|[`Bitrix24\SDK\Services\CRM\Type\Service\Type::update`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Type/Service/Type.php#L94-L100)
Return type
[`Bitrix24\SDK\Services\CRM\Type\Result\UpdatedTypeItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Type/Result/UpdatedTypeItemResult.php)| +|`crm`|[crm.type.get](https://apidocs.bitrix24.com/api-reference/crm/universal/user-defined-object-types/crm-type-get.html)|The method retrieves information about the SPA with the identifier id.|[`Bitrix24\SDK\Services\CRM\Type\Service\Type::get`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Type/Service/Type.php#L116-L119)
Return type
[`Bitrix24\SDK\Services\CRM\Type\Result\TypeResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Type/Result/TypeResult.php)| +|`crm`|[crm.type.getByEntityTypeId](https://apidocs.bitrix24.com/api-reference/crm/universal/user-defined-object-types/crm-type-get-by-entity-type-id.html)|The method retrieves information about the SPA with the smart process type identifier entityTypeId.|[`Bitrix24\SDK\Services\CRM\Type\Service\Type::getByEntityTypeId`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Type/Service/Type.php#L136-L139)
Return type
[`Bitrix24\SDK\Services\CRM\Type\Result\TypeResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Type/Result/TypeResult.php)| +|`crm`|[crm.type.list](https://apidocs.bitrix24.com/api-reference/crm/universal/user-defined-object-types/crm-type-list.html)|Get a list of custom types crm.type.list|[`Bitrix24\SDK\Services\CRM\Type\Service\Type::list`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Type/Service/Type.php#L158-L165)
Return type
[`Bitrix24\SDK\Services\CRM\Type\Result\TypesResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Type/Result/TypesResult.php)| +|`crm`|[crm.type.delete](https://apidocs.bitrix24.com/api-reference/crm/universal/user-defined-object-types/crm-type-delete.html)|This method deletes an existing smart process by the identifier id.|[`Bitrix24\SDK\Services\CRM\Type\Service\Type::delete`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Type/Service/Type.php#L182-L185)
Return type
[`Bitrix24\SDK\Services\CRM\Type\Result\DeletedItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Type/Result/DeletedItemResult.php)| |`crm`|[crm.lead.userfield.list](https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-list.html)|Returns list of user lead fields by filter.|[`Bitrix24\SDK\Services\CRM\Lead\Service\LeadUserfield::list`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Lead/Service/LeadUserfield.php#L95-L106)
Return type
[`Bitrix24\SDK\Services\CRM\Lead\Result\LeadUserfieldsResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Lead/Result/LeadUserfieldsResult.php)| |`crm`|[crm.lead.userfield.add](https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-add.html)|Created new user field for leads.|[`Bitrix24\SDK\Services\CRM\Lead\Service\LeadUserfield::add`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Lead/Service/LeadUserfield.php#L146-L158)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Core/Result/AddedItemResult.php)| |`crm`|[crm.lead.userfield.delete](https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-delete.html)|Deleted userfield for leads|[`Bitrix24\SDK\Services\CRM\Lead\Service\LeadUserfield::delete`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Lead/Service/LeadUserfield.php#L174-L184)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Core/Result/DeletedItemResult.php)| @@ -338,11 +345,11 @@ |`crm`|[crm.item.details.configuration.set](https://apidocs.bitrix24.com/api-reference/crm/universal/item-details-configuration/crm-item-details-configuration-set.html)|Set CRM Item Detail Card Configuration for all users|[`Bitrix24\SDK\Services\CRM\Item\Service\ItemDetailsConfiguration::setGeneral`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Service/ItemDetailsConfiguration.php#L166-L189)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Core/Result/UpdatedItemResult.php)| |`crm`|[crm.item.details.configuration.forceCommonScopeForAll](https://apidocs.bitrix24.com/api-reference/crm/deals/custom-form/crm-deal-details-configuration-force-common-scope-for-all.html)|Set Common Detail Form for All Users |[`Bitrix24\SDK\Services\CRM\Item\Service\ItemDetailsConfiguration::setForceCommonConfigForAll`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Service/ItemDetailsConfiguration.php#L203-L209)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Core/Result/UpdatedItemResult.php)| |`crm`|[crm.item.add](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_add.php)|Method creates new SPA item with entityTypeId.|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::add`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Service/Item.php#L52-L63)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\ItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Result/ItemResult.php)

⚡️Batch methods:
| -|`crm`|[crm.item.delete](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_delete.php)|Deletes item with id for SPA with entityTypeId.|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::delete`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Service/Item.php#L79-L87)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Core/Result/DeletedItemResult.php)| +|`crm`|[crm.item.delete](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_delete.php)|Deletes item with id for SPA with entityTypeId.|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::delete`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Service/Item.php#L79-L87)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\DeletedItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Result/DeletedItemResult.php)| |`crm`|[crm.item.fields](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_fields.php)|Returns the fields data with entityTypeId.|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::fields`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Service/Item.php#L102-L105)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Core/Result/FieldsResult.php)| |`crm`|[crm.item.get](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_get.php)|Returns item data with id for SPA with entityTypeId.|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::get`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Service/Item.php#L120-L123)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\ItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Result/ItemResult.php)| -|`crm`|[crm.item.list](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_list.php)|Returns array with SPA items with entityTypeId|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::list`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Service/Item.php#L138-L152)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\ItemsResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Result/ItemsResult.php)

⚡️Batch methods:
| -|`crm`|[crm.item.update](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_update.php)|Updates the specified (existing) item.|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::update`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Service/Item.php#L167-L179)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Core/Result/UpdatedItemResult.php)| +|`crm`|[crm.item.list](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_list.php)|Returns array with SPA items with entityTypeId|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::list`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Service/Item.php#L138-L156)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\ItemsResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Result/ItemsResult.php)

⚡️Batch methods:
| +|`crm`|[crm.item.update](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_update.php)|Updates the specified (existing) item.|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::update`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Service/Item.php#L171-L183)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\UpdatedItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Item/Result/UpdatedItemResult.php)| |`crm`|[crm.address.add](https://apidocs.bitrix24.com/api-reference/crm/requisites/addresses/crm-address-add.html)|Method adds new address|[`Bitrix24\SDK\Services\CRM\Address\Service\Address::add`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Address/Service/Address.php#L70-L80)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Core/Result/AddedItemResult.php)

⚡️Batch methods:
| |`crm`|[crm.address.delete](https://apidocs.bitrix24.com/api-reference/crm/requisites/addresses/crm-address-delete.html)|Deletes the specified address.|[`Bitrix24\SDK\Services\CRM\Address\Service\Address::delete`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Address/Service/Address.php#L96-L110)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Core/Result/DeletedItemResult.php)

⚡️Batch methods:
| |`crm`|[crm.address.fields](https://apidocs.bitrix24.com/api-reference/crm/requisites/addresses/crm-address-fields.html)|Returns the description of the address fields.|[`Bitrix24\SDK\Services\CRM\Address\Service\Address::fields`](https://github.com/bitrix24/b24phpsdk/dev/src/Services/CRM/Address/Service/Address.php#L125-L128)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/bitrix24/b24phpsdk/dev/src/Core/Result/FieldsResult.php)| diff --git a/examples/local-app-workflows/.gitignore b/examples/local-app-workflows/.gitignore deleted file mode 100644 index 377d10f2..00000000 --- a/examples/local-app-workflows/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -/.idea* -/var/* -vendor -config/auth.json -composer.phar -composer.lock -.phpunit.result.cache -*.log -.env.local \ No newline at end of file diff --git a/examples/local-app-workflows/LICENSE b/examples/local-app-workflows/LICENSE deleted file mode 100644 index 9fb0e64b..00000000 --- a/examples/local-app-workflows/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 Bitrix24 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/examples/local-app-workflows/Makefile b/examples/local-app-workflows/Makefile deleted file mode 100644 index fa76999f..00000000 --- a/examples/local-app-workflows/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# This file is part of the B24PhpSdk package. -# -# For the full copyright and license information, please view the MIT-LICENSE.txt -# file that was distributed with this source code. - -default: - @echo "make needs target:" - @egrep -e '^\S+' ./Makefile | grep -v default | sed -r 's/://' | sed -r 's/^/ - /' - -# linters -lint-phpstan: - vendor/bin/phpstan --memory-limit=1G analyse -lint-rector: - vendor/bin/rector process --dry-run -lint-rector-fix: - vendor/bin/rector process \ No newline at end of file diff --git a/examples/local-app-workflows/README.md b/examples/local-app-workflows/README.md deleted file mode 100644 index 447d9eb6..00000000 --- a/examples/local-app-workflows/README.md +++ /dev/null @@ -1,29 +0,0 @@ -## Local application with Workflows example - -Local application example for education purposes. - -### Example folder file structure - -``` -/bin - console.php - CLI script -/config - .env - example env file - .env.local - non commited file with actual data - .auth.json.local - auth data from application -/public - folder served with web-server - event-handler.php – event handler - index.php - base script loaded in default application placement - install.php - script for installation steps processing -/src - Application.php - example of local application -/var - /log - application-YYYY-m-d.log – application log -.gitignore - file with list of files and folders ignored with VCS -composer.json - configuration file used by Composer, a dependency management tool for PHP. This file defines the dependencies required for a project and specifies various metadata about the project. -composer.lock - automatically generated by Composer. It ensures that the same versions of dependencies are used every time the project is installed, providing consistency across different environments. -Makefile - commands for static code analysis of the codebase. -phpstan.neon.dist – phpstan config -rector.php - rector config -``` diff --git a/examples/local-app-workflows/bin/console.php b/examples/local-app-workflows/bin/console.php deleted file mode 100644 index db1ab0a9..00000000 --- a/examples/local-app-workflows/bin/console.php +++ /dev/null @@ -1,276 +0,0 @@ -setCode(function (InputInterface $input, OutputInterface $output): int { - Application::getLog()->debug('cliCommand.start'); - try { - while (true) { - /** - * @var QuestionHelper $helper - * - * method «setCode» override «execute» method for object Command - * we use SingleCommandApplication for reduce code in this example - */ - // @phpstan-ignore-next-line - $helper = $this->getHelper('question'); - $question = new ChoiceQuestion( - 'Please select command', - [ - 1 => 'workflow template: list', - 2 => 'workflow template: add template from file', - 3 => 'workflow template: delete added template', - 4 => 'workflow: start', - 5 => 'workflow: instances', - 6 => 'workflow: terminate', - 7 => 'workflow: kill', - 8 => 'workflow task: list', - 9 => 'workflow task: complete', - 0 => 'exit🚪' - ], - null - ); - $question->setErrorMessage('Menu item «%s» is invalid.'); - $menuItem = $helper->ask($input, $output, $question); - $output->writeln(sprintf('You have just selected: %s', $menuItem)); - - $sb = Application::getB24Service(); - switch ($menuItem) { - case 'workflow template: list': - $output->writeln('get workflow template list...'); - - $table = new Table($output); - $table->setHeaders(['ID', 'NAME', 'MODULE_ID', 'ENTITY', 'DOCUMENT_TYPE', 'AUTO_EXECUTE']); - foreach ($sb->getBizProcScope()->template()->list()->getTemplates() as $template) { - $table->addRow( - [ - $template->ID, - $template->NAME, - $template->MODULE_ID, - $template->ENTITY, - implode(' ', $template->DOCUMENT_TYPE), - $template->AUTO_EXECUTE->name - ] - ); - } - - $table->render(); - break; - case 'workflow template: add template from file': - $output->writeln('try to add new workflow template from file...'); - $result = $sb->getBizProcScope()->template()->add( - WorkflowDocumentType::buildForContact(), - 'test_workflow_for_contact', - 'Test workflow for contact with demonstration options', - WorkflowAutoExecutionType::withoutAutoExecution, - dirname(__DIR__) . '/templates/contact-demo-percentage.bpt' - ); - - $output->writeln(sprintf('added template id: %s', $result->getId())); - break; - case 'workflow template: delete added template': - $output->writeln('try to delete added template by id...'); - $question = new Question('Please enter the workflow template id for delete: '); - $rawId = $helper->ask($input, $output, $question); - $templateId = (int)$rawId; - if ($templateId === 0) { - throw new InvalidArgumentException(sprintf('invalid workflow template id «%s»', $rawId)); - } - - $result = $sb->getBizProcScope()->template()->delete($templateId); - //todo add issue api returns emtpy result - $output->writeln(sprintf('workflow template delete result: %s', $result->isSuccess() ? 'success' : 'failure')); - break; - case 'workflow: start': - $output->writeln('try to start workflow on contact...'); - $contactId = $sb->getCRMScope()->contact()->add([ - 'NAME' => sprintf('test_%s', time()), - ])->getId(); - - $question = new Question('Please enter the workflow template id: '); - $rawId = $helper->ask($input, $output, $question); - $templateId = (int)$rawId; - if ($templateId === 0) { - throw new InvalidArgumentException(sprintf('invalid workflow template id «%s»', $rawId)); - } - - try { - // try to run without required parameters ))))))) - //todo add issue to rest-api, we now can run workflow without required parameters - $wfInstanceIdWithoutParams = $sb->getBizProcScope()->workflow()->start( - DocumentType::crmContact, - $templateId, - $contactId, - [] - )->getRunningWorkflowInstanceId(); - //todo add url to contact - $output->writeln(sprintf('running workflow id: «%s» for contact «%s»', $wfInstanceIdWithoutParams, $contactId)); - } catch (Throwable $exception) { - $output->writeln(sprintf('%s', $exception->getMessage())); - $output->writeln(sprintf('DETAILS: %s', $exception->getTraceAsString())); - } - - try { - // try to run with required parameters - $contactId = $sb->getCRMScope()->contact()->add([ - 'NAME' => sprintf('test_%s', time()), - ])->getId(); - $wfInstanceIdWithParams = $sb->getBizProcScope()->workflow()->start( - DocumentType::crmContact, - $templateId, - $contactId, - [ - 'discount_percentage' => 50, - 'comment' => sprintf('hello from demo application at %s', (new DateTime())->format('H:i:s d.m.Y')) - ] - )->getRunningWorkflowInstanceId(); - //todo add url to contact - $output->writeln(sprintf('running workflow id: «%s» for contact «%s»', $wfInstanceIdWithParams, $contactId)); - } catch (Throwable $exception) { - $output->writeln(sprintf('%s', $exception->getMessage())); - $output->writeln(sprintf('DETAILS: %s', $exception->getTraceAsString())); - } - - break; - case 'workflow: instances': - $output->writeln('get running workflow instances list...'); - - $table = new Table($output); - $table->setHeaders(['ID', 'TEMPLATE_ID', 'STARTED', 'MODIFIED', 'OWNED_UNTIL', 'MODULE_ID', 'ENTITY', 'DOCUMENT_ID', 'STARTED_BY']); - foreach ($sb->getBizProcScope()->workflow()->instances()->getInstances() as $item) { - $table->addRow( - [ - $item->ID, - $item->TEMPLATE_ID, -//todo fix optional fields - $item->STARTED->format('H:i:s d.m.Y'), - $item->MODIFIED->format('H:i:s d.m.Y'), - $item->OWNED_UNTIL?->format('H:i:s d.m.Y'), - $item->MODULE_ID, - $item->ENTITY, - $item->DOCUMENT_ID, - $item->STARTED_BY - ] - ); - } - - $table->render(); - break; - case 'workflow: terminate': - $output->writeln('try to terminate workflow instance...'); - $question = new Question('Please enter running workflow id: '); - $rawId = $helper->ask($input, $output, $question); - - try { - $result = $sb->getBizProcScope()->workflow()->terminate($rawId, sprintf('terminate from cli at %s', (new DateTime())->format('H:i:s d.m.Y'))); - $output->writeln(sprintf('terminate result: %s', $result->isSuccess() ? 'succes' : 'failure')); - } catch (Throwable $exception) { - $output->writeln(sprintf('%s', $exception->getMessage())); - } - - break; - case 'workflow: kill': - $output->writeln('try to KILL workflow instance...'); - $question = new Question('Please enter running workflow id: '); - $rawId = $helper->ask($input, $output, $question); - - try { - $result = $sb->getBizProcScope()->workflow()->kill($rawId); - $output->writeln(sprintf('kill result: %s', $result->isSuccess() ? 'succes' : 'failure')); - } catch (Throwable $exception) { - $output->writeln(sprintf('%s', $exception->getMessage())); - } - - break; - case 'workflow task: list': - $output->writeln('get workflow task list...'); - - $table = new Table($output); - $table->setHeaders([ - 'ID', - 'WORKFLOW_ID', - 'DOCUMENT_NAME', - 'DOCUMENT_ID', - 'DOCUMENT_URL', - 'WORKFLOW_STATE', - 'NAME', - 'STATUS', - ]); - foreach ($sb->getBizProcScope()->task()->list([], [], [ - 'ID', - 'WORKFLOW_ID', - 'DOCUMENT_NAME', - 'DOCUMENT_ID', - 'DOCUMENT_URL', - 'NAME', - 'WORKFLOW_STATE', - 'STATUS' - ])->getTasks() as $item) { - $table->addRow( - [ - $item->ID, - $item->WORKFLOW_ID, - $item->DOCUMENT_NAME, - $item->DOCUMENT_ID, - $item->DOCUMENT_URL, - $item->WORKFLOW_STATE, - $item->NAME, - $item->STATUS->name, - ] - ); - } - - $table->render(); - - break; - case 'workflow task: complete': - $output->writeln('Try to workflow task complete...'); - - $question = new Question('Please enter TASK id: '); - $rawId = $helper->ask($input, $output, $question); - $taskId = (int)$rawId; - - try { - $result = $sb->getBizProcScope()->task()->complete( - $taskId, - WorkflowTaskCompleteStatusType::approved, - 'approved from cli', - ); - $output->writeln(sprintf('task complete status %s', $result->isSuccess() ? 'success' : 'failure')); - } catch (Throwable $exception) { - $output->writeln(sprintf('%s', $exception->getMessage())); - } - - break; - case 'exit🚪': - Application::getLog()->debug('cliCommand.finish'); - return Command::SUCCESS; - } - } - } catch (Throwable $throwable) { - Application::getLog()->debug('cliCommand.error', [ - 'message' => $throwable->getMessage(), - 'trace' => $throwable->getTraceAsString() - ]); - $output->writeln(sprintf('ERROR: %s', $throwable->getMessage())); - $output->writeln(sprintf('DETAILS: %s', $throwable->getTraceAsString())); - - return Command::FAILURE; - } - }) - ->run(); \ No newline at end of file diff --git a/examples/local-app-workflows/composer.json b/examples/local-app-workflows/composer.json deleted file mode 100644 index abd985de..00000000 --- a/examples/local-app-workflows/composer.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "bitrix24/b24phpsdk-local-app-example", - "description": "Example for work with bitrix24-php-sdk with local application and workflows", - "minimum-stability": "stable", - "license": "MIT", - "authors": [ - { - "name": "Maksim Mesilov", - "email": "mesilov.maxim@gmail.com" - } - ], - "config": { - "sort-packages": true - }, - "require": { - "bitrix24/b24phpsdk": "dev-dev", - "monolog/monolog": "^3", - "symfony/console": "^7", - "symfony/dotenv": "^7", - "symfony/event-dispatcher": "^7", - "symfony/filesystem": "^7" - }, - "require-dev": { - "symfony/var-dumper": "^7", - "phpstan/phpstan": "1.11.7", - "rector/rector": "^1", - "roave/security-advisories": "dev-latest" - }, - "autoload": { - "psr-4": { - "Examples\\Workflows\\": "src/" - } - } -} \ No newline at end of file diff --git a/examples/local-app-workflows/config/.env b/examples/local-app-workflows/config/.env deleted file mode 100644 index 64c5d69f..00000000 --- a/examples/local-app-workflows/config/.env +++ /dev/null @@ -1,35 +0,0 @@ -# In all environments, the following files are loaded if they exist, -# the latter taking precedence over the former: -# -# * .env contains default values for the environment variables needed by the app -# * .env.local uncommitted file with local overrides -# * .env.$APP_ENV committed environment-specific defaults -# * .env.$APP_ENV.local uncommitted environment-specific overrides - -# bitrix24 local application parameters -# THIS IS DEFAULT AND EXAMPLE CONFIGURATION -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -# DO NOT COMMIT PRODUCTION KEYS AND SECRETS IN THIS FILE -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -# To owerride settings use .env.local -BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID= -BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET= -BITRIX24_PHP_SDK_APPLICATION_SCOPE= - -# monolog log level -# see https://github.com/Seldaek/monolog/blob/main/doc/01-usage.md#log-levels -# DEBUG (100): Detailed debug information. -# INFO (200): Interesting events. Examples: User logs in, SQL logs. -# NOTICE (250): Normal but significant events. -# WARNING (300): Exceptional occurrences that are not errors. Examples: Use of deprecated APIs, poor use of an API, undesirable things that are not necessarily wrong. -# ERROR (400): Runtime errors that do not require immediate action but should typically be logged and monitored. -# CRITICAL (500): Critical conditions. Example: Application component unavailable, unexpected exception. -# ALERT (550): Action must be taken immediately. Example: Entire website down, database unavailable, etc. This should trigger the SMS alerts and wake you up. -# EMERGENCY (600): Emergency: system is unusable. -BITRIX24_PHP_SDK_LOG_LEVEL=100 - -# maximum files count with rule - file per day -# see https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/RotatingFileHandler.php -# you must setup Using logrotate to handle the rotation is strongly encouraged when you can use it. -BITRIX24_PHP_SDK_LOG_MAX_FILES_COUNT=7 diff --git a/examples/local-app-workflows/phpstan.neon.dist b/examples/local-app-workflows/phpstan.neon.dist deleted file mode 100644 index da2f2efb..00000000 --- a/examples/local-app-workflows/phpstan.neon.dist +++ /dev/null @@ -1,14 +0,0 @@ -parameters: - level: 4 - paths: - - bin/ - - src/ - bootstrapFiles: - - tests/bootstrap.php - parallel: - jobSize: 20 - maximumNumberOfProcesses: 8 - minimumNumberOfJobsPerProcess: 2 - editorUrlTitle: '%%relFile%%:%%line%%' - editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%' - treatPhpDocTypesAsCertain: false diff --git a/examples/local-app-workflows/public/event-handler.php b/examples/local-app-workflows/public/event-handler.php deleted file mode 100644 index d8600ef5..00000000 --- a/examples/local-app-workflows/public/event-handler.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the MIT-LICENSE.txt - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -use Examples\Workflows\Application; -use Symfony\Component\HttpFoundation\Request; - -require_once dirname(__DIR__) . '/vendor/autoload.php'; - -$incomingRequest = Request::createFromGlobals(); -Application::getLog()->debug('event-handler.init', ['request' => $incomingRequest->request->all(), 'query' => $incomingRequest->query->all()]); - -//try to process incoming requests and send processing result to response -Application::processRequest($incomingRequest)->send(); - diff --git a/examples/local-app-workflows/public/index.php b/examples/local-app-workflows/public/index.php deleted file mode 100644 index b5c72159..00000000 --- a/examples/local-app-workflows/public/index.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * For the full copyright and license information, please view the MIT-LICENSE.txt - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -use Examples\Workflows\Application; -use Symfony\Component\HttpFoundation\Request; - -require_once dirname(__DIR__). '/vendor/autoload.php'; - -$incomingRequest = Request::createFromGlobals(); -Application::getLog()->debug('index.init', ['request' => $incomingRequest->request->all(), 'query' => $incomingRequest->query->all()]); -?> -
-    Application is worked, auth tokens from bitrix24:
-    
-
- - * - * For the full copyright and license information, please view the MIT-LICENSE.txt - * file that was distributed with this source code. - */ - -declare(strict_types=1); - - -use Symfony\Component\HttpFoundation\Request; -use Examples\Workflows\Application; - -require_once dirname(__DIR__) . '/vendor/autoload.php'; - -$incomingRequest = Request::createFromGlobals(); -Application::getLog()->debug('install.init', ['request' => $incomingRequest->request->all(), 'query' => $incomingRequest->query->all()]); -// try to process ONAPPINSTALL event -Application::processRequest($incomingRequest)->send(); -?> -
-    Application installation started, tokens from Bitrix24:
-    
-
- - \ No newline at end of file diff --git a/examples/local-app-workflows/rector.php b/examples/local-app-workflows/rector.php deleted file mode 100644 index a7b7f497..00000000 --- a/examples/local-app-workflows/rector.php +++ /dev/null @@ -1,51 +0,0 @@ -withPaths([ - __DIR__ . '/bin', - __DIR__ . '/src', - ]) - ->withCache(cacheDirectory: __DIR__ . '/var/cache/rector') - ->withSets( - [ - DowngradeLevelSetList::DOWN_TO_PHP_82, - PHPUnitSetList::PHPUNIT_100 - ] - ) - ->withImportNames( - importNames: false, - importDocBlockNames: false, - importShortClasses: false, - removeUnusedImports: false, - ) - ->withPhpSets( - php82: true // 8.2 - ) - ->withPreparedSets( - deadCode: true, - codeQuality: true, - codingStyle: true, - typeDeclarations: true, - privatization: true, - naming: true, - instanceOf: true, - earlyReturn: true, - strictBooleans: true - ) - ->withSkip([ - RenamePropertyToMatchTypeRector::class - ]); \ No newline at end of file diff --git a/examples/local-app-workflows/src/Application.php b/examples/local-app-workflows/src/Application.php deleted file mode 100644 index 867ba74a..00000000 --- a/examples/local-app-workflows/src/Application.php +++ /dev/null @@ -1,372 +0,0 @@ - - * - * For the full copyright and license information, please view the MIT-LICENSE.txt - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Examples\Workflows; - -use Bitrix24\SDK\Application\Local\Entity\LocalAppAuth; -use Bitrix24\SDK\Application\Local\Infrastructure\Filesystem\AppAuthFileStorage; -use Bitrix24\SDK\Application\Local\Repository\LocalAppAuthRepositoryInterface; -use Bitrix24\SDK\Application\Requests\Events\OnApplicationInstall\OnApplicationInstall; -use Bitrix24\SDK\Application\Requests\Events\OnApplicationUninstall\OnApplicationUninstall; -use Bitrix24\SDK\Application\Requests\Placement\PlacementRequest; -use Bitrix24\SDK\Core\Contracts\Events\EventInterface; -use Bitrix24\SDK\Core\Credentials\ApplicationProfile; -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; -use Bitrix24\SDK\Core\Exceptions\TransportException; -use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; -use Bitrix24\SDK\Core\Exceptions\WrongConfigurationException; -use Bitrix24\SDK\Events\AuthTokenRenewedEvent; -use Bitrix24\SDK\Services\Main\Common\EventHandlerMetadata; -use Bitrix24\SDK\Services\RemoteEventsFabric; -use Bitrix24\SDK\Services\ServiceBuilder; -use Bitrix24\SDK\Services\ServiceBuilderFactory; -use Monolog\Formatter\JsonFormatter; -use Monolog\Handler\RotatingFileHandler; -use Monolog\Handler\SocketHandler; -use Monolog\Logger; -use Monolog\Processor\MemoryUsageProcessor; -use Monolog\Processor\UidProcessor; -use Psr\Log\LoggerInterface; -use Symfony\Component\Console\Input\ArgvInput; -use Symfony\Component\Dotenv\Dotenv; -use Symfony\Component\EventDispatcher\EventDispatcher; -use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Serializer\Encoder\JsonEncoder; -use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; -use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; -use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter; -use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; -use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; -use Symfony\Component\Serializer\Normalizer\PropertyNormalizer; -use Symfony\Component\Serializer\Serializer; -use Symfony\Component\Serializer\SerializerInterface; -use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; - -class Application -{ - private const CONFIG_FILE_NAME = '/config/.env'; - - private const LOG_FILE_NAME = '/var/log/application.log'; - - public static function processRequest(Request $incomingRequest): Response - { - self::getLog()->debug('processRequest.start', [ - 'request' => $incomingRequest->request->all(), - 'baseUrl' => $incomingRequest->getBaseUrl(), - ]); - // it can be - // - incoming request when placement or custom type in userfield loaded - // - incoming event request on install.php when lical app without UI - if (PlacementRequest::isCanProcess($incomingRequest)) { - self::getLog()->debug('processRequest.placementRequest', [ - 'request' => $incomingRequest->request->all() - ]); - $placementRequest = new PlacementRequest($incomingRequest); - - // is install url? - if ($placementRequest->getRequest()->getBaseUrl() === '/install.php') { - self::processOnInstallPlacementRequest($placementRequest); - } - - // todo process other placement request - - } elseif (RemoteEventsFabric::isCanProcess($incomingRequest)) { - self::getLog()->debug('processRequest.b24EventRequest'); - - // get application_token for check event security signature - // see https://apidocs.bitrix24.com/api-reference/events/safe-event-handlers.html - // on first lifecycle event OnApplicationInstall application token is null and file with auth data doesn't exists - // we save application_token and all next events will be validated security signature - $applicationToken = self::getAuthRepository()->getApplicationToken(); - $event = RemoteEventsFabric::init(self::getLog())->createEvent($incomingRequest, $applicationToken); - self::getLog()->debug('processRequest.eventRequest', [ - 'eventClassName' => $event::class, - 'eventCode' => $event->getEventCode(), - 'eventPayload' => $event->getEventPayload(), - ]); - self::processRemoteEvents($event); - } - - self::getLog()->debug('processRequest.finish'); - - return new Response('OK', 200); - } - - /** - * Process remote bitrix24 events - * - * @throws InvalidArgumentException - * @throws WrongConfigurationException - */ - protected static function processRemoteEvents(EventInterface $b24Event): void - { - self::getLog()->debug('processRemoteEvents.start', [ - 'event_code' => $b24Event->getEventCode(), - 'event_classname' => $b24Event::class, - 'event_payload' => $b24Event->getEventPayload() - ]); - - switch ($b24Event->getEventCode()) { - case OnApplicationInstall::CODE: - self::getLog()->debug('processRemoteEvents.onApplicationInstall'); - - // save auth tokens and application token - self::getAuthRepository()->save( - new LocalAppAuth( - $b24Event->getAuth()->authToken, - $b24Event->getAuth()->domain, - $b24Event->getAuth()->application_token - ) - ); - break; - default: - self::getLog()->warning('processRemoteEvents.unknownEvent', [ - 'event_code' => $b24Event->getEventCode(), - 'event_classname' => $b24Event::class, - 'event_payload' => $b24Event->getEventPayload() - ]); - break; - } - - self::getLog()->debug('processRemoteEvents.finish'); - } - - /** - * Process first request (installation) on default placement - * - * @throws InvalidArgumentException - * @throws UnknownScopeCodeException - * @throws WrongConfigurationException - * @throws BaseException - * @throws TransportException - */ - protected static function processOnInstallPlacementRequest(PlacementRequest $placementRequest): void - { - self::getLog()->debug('processRequest.processOnInstallPlacementRequest.start'); - - $currentB24UserId = self::getB24Service($placementRequest->getRequest()) - ->getMainScope() - ->main() - ->getCurrentUserProfile() - ->getUserProfile() - ->ID; - - $eventHandlerUrl = sprintf('https://%s/event-handler.php', $placementRequest->getRequest()->server->get('HTTP_HOST')); - self::getLog()->debug('processRequest.processOnInstallPlacementRequest.startBindEventHandlers', [ - 'eventHandlerUrl' => $eventHandlerUrl - ]); - - // register application lifecycle event handlers - self::getB24Service($placementRequest->getRequest())->getMainScope()->eventManager()->bindEventHandlers( - [ - // register event handlers for implemented in SDK events - new EventHandlerMetadata( - OnApplicationInstall::CODE, - $eventHandlerUrl, - $currentB24UserId - ), - new EventHandlerMetadata( - OnApplicationUninstall::CODE, - $eventHandlerUrl, - $currentB24UserId, - ), - ] - ); - self::getLog()->debug('processRequest.processOnInstallPlacementRequest.finishBindEventHandlers'); - - // save admin auth token without application_token key - // they will arrive at OnApplicationInstall event - self::getAuthRepository()->save( - new LocalAppAuth( - $placementRequest->getAccessToken(), - $placementRequest->getDomainUrl(), - null - ) - ); - self::getLog()->debug('processRequest.processOnInstallPlacementRequest.finish'); - } - - /** - * @throws WrongConfigurationException - * @throws InvalidArgumentException - */ - public static function getLog(): LoggerInterface - { - static $logger; - - if ($logger === null) { - // load config - self::loadConfigFromEnvFile(); - - // check settings - if (!array_key_exists('BITRIX24_PHP_SDK_LOG_LEVEL', $_ENV)) { - throw new InvalidArgumentException('in $_ENV variables not found key BITRIX24_PHP_SDK_LOG_LEVEL'); - } - - // rotating - $rotatingFileHandler = new RotatingFileHandler(dirname(__DIR__) . self::LOG_FILE_NAME, 0, (int)$_ENV['BITRIX24_PHP_SDK_LOG_LEVEL']); - $rotatingFileHandler->setFilenameFormat('{filename}-{date}', 'Y-m-d'); - - $logger = new Logger('App'); - - $logger->pushHandler($rotatingFileHandler); - $logger->pushProcessor(new MemoryUsageProcessor(true, true)); - $logger->pushProcessor(new UidProcessor()); - } - - return $logger; - } - - /** - * Retrieves an instance of the event dispatcher. - * - * @return EventDispatcherInterface The event dispatcher instance. - */ - protected static function getEventDispatcher(): EventDispatcherInterface - { - $eventDispatcher = new EventDispatcher(); - $eventDispatcher->addListener(AuthTokenRenewedEvent::class, function (AuthTokenRenewedEvent $authTokenRenewedEvent): void { - self::onAuthTokenRenewedEventListener($authTokenRenewedEvent); - }); - return $eventDispatcher; - } - - /** - * Event listener for when the authentication token is renewed. - * - * @param AuthTokenRenewedEvent $authTokenRenewedEvent The event object containing the renewed authentication token. - */ - protected static function onAuthTokenRenewedEventListener(AuthTokenRenewedEvent $authTokenRenewedEvent): void - { - self::getLog()->debug('onAuthTokenRenewedEventListener.start', [ - 'expires' => $authTokenRenewedEvent->getRenewedToken()->authToken->expires - ]); - - // save renewed auth token - self::getAuthRepository()->saveRenewedToken($authTokenRenewedEvent->getRenewedToken()); - - self::getLog()->debug('onAuthTokenRenewedEventListener.finish'); - } - - /** - * // todo сделать инициализацию сервис билдера из запроса к роботу - * - * @throws InvalidArgumentException - * @throws UnknownScopeCodeException - * @throws WrongConfigurationException - */ - public static function getB24Service(?Request $request = null): ServiceBuilder - { - // init bitrix24 service builder auth data from request - if ($request instanceof Request) { - self::getLog()->debug('getB24Service.authFromRequest'); - return ServiceBuilderFactory::createServiceBuilderFromPlacementRequest( - $request, - self::getApplicationProfile(), - self::getEventDispatcher(), - self::getLog(), - ); - } - - // init bitrix24 service builder auth data from saved auth token - self::getLog()->debug('getB24Service.authFromAuthRepositoryStorage'); - return (new ServiceBuilderFactory( - self::getEventDispatcher(), - self::getLog() - ))->init( - // load app profile from /config/.env.local to $_ENV and create ApplicationProfile object - self::getApplicationProfile(), - // load oauth tokens and portal URL stored in /config/auth.json.local to LocalAppAuth object - self::getAuthRepository()->getAuth()->getAuthToken(), - self::getAuthRepository()->getAuth()->getDomainUrl() - ); - } - - /** - * Retrieves the authentication repository. - * - * @return LocalAppAuthRepositoryInterface The authentication repository used for B24Service. - */ - protected static function getAuthRepository(): LocalAppAuthRepositoryInterface - { - return new AppAuthFileStorage( - dirname(__DIR__) . '/config/auth.json.local', - new Filesystem(), - self::getLog() - ); - } - - /** - * Get Application profile from environment variables - * - * By default behavioral - * - * @throws WrongConfigurationException - * @throws UnknownScopeCodeException - * @throws InvalidArgumentException - */ - protected static function getApplicationProfile(): ApplicationProfile - { - self::getLog()->debug('getApplicationProfile.start'); - // you can find list of local apps by this URL - // https://YOUR-PORTAL-URL.bitrix24.com/devops/list/ - // or see in left menu Developer resources → Integrations → select target local applicatoin - - // load config: application secrets, logging - self::loadConfigFromEnvFile(); - - try { - $profile = ApplicationProfile::initFromArray($_ENV); - self::getLog()->debug('getApplicationProfile.finish'); - return $profile; - } catch (InvalidArgumentException $invalidArgumentException) { - self::getLog()->error('getApplicationProfile.error', - [ - 'message' => sprintf('cannot read config from $_ENV: %s', $invalidArgumentException->getMessage()), - 'trace' => $invalidArgumentException->getTraceAsString() - ]); - throw $invalidArgumentException; - } - } - - /** - * Loads configuration from the environment file. - * - * @throws WrongConfigurationException if "symfony/dotenv" is not added as a Composer dependency. - */ - private static function loadConfigFromEnvFile(): void - { - static $isConfigLoaded = null; - if ($isConfigLoaded === null) { - if (!class_exists(Dotenv::class)) { - throw new WrongConfigurationException('You need to add "symfony/dotenv" as Composer dependencies.'); - } - - $argvInput = new ArgvInput(); - if (null !== $env = $argvInput->getParameterOption(['--env', '-e'], null, true)) { - putenv('APP_ENV=' . $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env); - } - - if ($argvInput->hasParameterOption('--no-debug', true)) { - putenv('APP_DEBUG=' . $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0'); - } - - (new Dotenv())->loadEnv(dirname(__DIR__) . self::CONFIG_FILE_NAME); - - $isConfigLoaded = true; - } - } -} \ No newline at end of file diff --git a/examples/local-app-workflows/templates/contact-demo-percentage.bpt b/examples/local-app-workflows/templates/contact-demo-percentage.bpt deleted file mode 100644 index f22d7f00..00000000 Binary files a/examples/local-app-workflows/templates/contact-demo-percentage.bpt and /dev/null differ diff --git a/examples/local-app-workflows/tests/bootstrap.php b/examples/local-app-workflows/tests/bootstrap.php deleted file mode 100644 index 53dc1ac8..00000000 --- a/examples/local-app-workflows/tests/bootstrap.php +++ /dev/null @@ -1,14 +0,0 @@ - - * - * For the full copyright and license information, please view the MIT-LICENSE.txt - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -require_once dirname(__DIR__) . '/vendor/autoload.php'; \ No newline at end of file diff --git a/rector.php b/rector.php index 513cc900..85ecc9ca 100644 --- a/rector.php +++ b/rector.php @@ -12,7 +12,7 @@ use Rector\Config\RectorConfig; use Rector\Naming\Rector\Class_\RenamePropertyToMatchTypeRector; use Rector\PHPUnit\Set\PHPUnitSetList; -use Rector\Set\ValueObject\DowngradeLevelSetList; +use Rector\Set\ValueObject\LevelSetList; return RectorConfig::configure() ->withPaths([ @@ -72,11 +72,11 @@ __DIR__ . '/tests/Integration/Services/CRM/Documentgenerator/Numerator', __DIR__ . '/tests/Unit/', ]) - ->withCache(cacheDirectory: __DIR__ . '.cache/rector') + ->withCache(cacheDirectory: __DIR__ . '/var/.cache/rector') ->withSets( [ - DowngradeLevelSetList::DOWN_TO_PHP_82, - PHPUnitSetList::PHPUNIT_100 + LevelSetList::UP_TO_PHP_84, + PHPUnitSetList::PHPUNIT_110 ] ) ->withImportNames( @@ -86,7 +86,7 @@ removeUnusedImports: false, ) ->withPhpSets( - php82: true // 8.2 + php84: true // 8.4 ) ->withPreparedSets( deadCode: true, diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 8cecd636..3a715739 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -43,7 +43,7 @@ class Batch implements BatchOperationsInterface 'entity.section.update', 'entity.item.property.update', ]; - + protected const MAX_BATCH_PACKET_SIZE = 50; protected const MAX_ELEMENTS_IN_PAGE = 50; @@ -135,7 +135,7 @@ public function deleteEntityItems( 'additionalParameters' => $additionalParameters, ] ); - + $useFieldsInsteadOfId = $apiMethod === 'crm.address.delete'; try { @@ -214,9 +214,9 @@ public function updateEntityItems(string $apiMethod, array $entityItems): Genera try { $this->clearCommands(); - + $useFieldsInsteadOfId = $apiMethod === 'crm.address.update'; - + foreach ($entityItems as $entityItemId => $entityItem) { if (!$useFieldsInsteadOfId && !is_int($entityItemId)) { throw new InvalidArgumentException( @@ -287,7 +287,6 @@ public function updateEntityItems(string $apiMethod, array $entityItems): Genera * Register api command to command collection for batch calls * * @param array $parameters - * @param callable|null $callback not implemented * * @throws \Exception */ @@ -295,7 +294,6 @@ protected function registerCommand( string $apiMethod, array $parameters = [], ?string $commandName = null, - callable $callback = null ): void { $this->logger->debug( 'registerCommand.start', @@ -315,7 +313,7 @@ protected function registerCommand( ] ); } - + /** * @param array $order * @@ -350,7 +348,7 @@ protected function getReverseOrder(array $order): array return $reverseOrder; } - + /** * @param array $oldFilter * @@ -387,9 +385,9 @@ protected function updateFilterForBatch( /** * Get traversable list without count elements - * + * * @link https://apidocs.bitrix24.com/api-reference/performance/huge-data.html - * + * * Depending on the requested sorting option, the method uses two scenarios * 1. Sorting is not specified or starts with sorting by ID (in any direction) * We use fast data loading with start=-1 and a dynamic filter by the ID value from the result of the previous subquery. See @@ -926,17 +924,17 @@ private function convertToApiCommands(): array return $apiCommands; } - + /** * Returns relative path to previous ID value */ protected function getReferenceFieldPath(string $prevCommandId, int $lastIndex, string $keyId, bool $isCrmItemsInBatch): string { - return $isCrmItemsInBatch ? - sprintf('$result[%s][items][%d][%s]', $prevCommandId, $lastIndex, $keyId) : + return $isCrmItemsInBatch ? + sprintf('$result[%s][items][%d][%s]', $prevCommandId, $lastIndex, $keyId) : sprintf('$result[%s][%d][%s]', $prevCommandId, $lastIndex, $keyId); } - + /** * Determines the ID key based on API method and parameters */ @@ -955,9 +953,9 @@ protected function getLastElementId(array $elements, string $keyId, bool $isAsce if ($elements === []) { return 0; } - + $lastElement = $isAscendingSort ? end($elements) : end($elements); - + return (int)$lastElement[$keyId]; } @@ -987,7 +985,7 @@ protected function extractElementsFromBatchResult(ResponseData $responseData, bo } else { return $resultData; } - + return []; } } diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index c09e93af..588df36b 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -289,7 +289,7 @@ public function getSmartProcessItem(int $entityTypeId): ?int return (int)$this->data[$fieldKey]; } - public function __construct(array $data, Currency $currency = null) + public function __construct(array $data, ?Currency $currency = null) { parent::__construct($data); if ($currency !== null) { diff --git a/src/Services/CRM/Deal/Result/DealItemResult.php b/src/Services/CRM/Deal/Result/DealItemResult.php index 816d7ce2..f41509ea 100644 --- a/src/Services/CRM/Deal/Result/DealItemResult.php +++ b/src/Services/CRM/Deal/Result/DealItemResult.php @@ -72,7 +72,7 @@ class DealItemResult extends AbstractCrmItem * @return mixed|null * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException */ - public function getUserfieldByFieldName(string $userfieldName) + public function getUserfieldByFieldName(string $userfieldName): mixed { return $this->getKeyWithUserfieldByFieldName($userfieldName); } diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php index f1d0c25b..7b6baad6 100644 --- a/src/Services/CRM/Deal/Service/DealProductRows.php +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -32,7 +32,6 @@ class DealProductRows extends AbstractService * * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_productrows_get.php * - * @param Currency|null $currency * @throws BaseException * @throws TransportException */ @@ -41,7 +40,7 @@ class DealProductRows extends AbstractService 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_productrows_get.php', 'Returns products inside the specified deal.' )] - public function get(int $dealId, Currency $currency = null): DealProductRowItemsResult + public function get(int $dealId, ?Currency $currency = null): DealProductRowItemsResult { if (!$currency instanceof \Money\Currency) { $res = $this->core->call('batch', [ diff --git a/src/Services/CRM/Lead/Result/LeadItemResult.php b/src/Services/CRM/Lead/Result/LeadItemResult.php index 32097fa1..474f7711 100644 --- a/src/Services/CRM/Lead/Result/LeadItemResult.php +++ b/src/Services/CRM/Lead/Result/LeadItemResult.php @@ -90,7 +90,7 @@ class LeadItemResult extends AbstractCrmItem * @return mixed|null * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException */ - public function getUserfieldByFieldName(string $userfieldName) + public function getUserfieldByFieldName(string $userfieldName): mixed { return $this->getKeyWithUserfieldByFieldName($userfieldName); } diff --git a/src/Services/CRM/Lead/Service/LeadProductRows.php b/src/Services/CRM/Lead/Service/LeadProductRows.php index 256352e6..eeb91197 100644 --- a/src/Services/CRM/Lead/Service/LeadProductRows.php +++ b/src/Services/CRM/Lead/Service/LeadProductRows.php @@ -31,7 +31,6 @@ class LeadProductRows extends AbstractService * * @link https://apidocs.bitrix24.com/api-reference/crm/leads/crm-lead-get.html * - * @param Currency|null $currency * @throws BaseException * @throws TransportException */ @@ -40,7 +39,7 @@ class LeadProductRows extends AbstractService 'https://apidocs.bitrix24.com/api-reference/crm/leads/crm-lead-get.html', 'Returns products inside the specified lead.' )] - public function get(int $leadId, Currency $currency = null): LeadProductRowItemsResult + public function get(int $leadId, ?Currency $currency = null): LeadProductRowItemsResult { if (!$currency instanceof \Money\Currency) { $res = $this->core->call('batch', [ diff --git a/src/Services/CRM/Quote/Result/QuoteItemResult.php b/src/Services/CRM/Quote/Result/QuoteItemResult.php index 9475b36f..a618c7c8 100644 --- a/src/Services/CRM/Quote/Result/QuoteItemResult.php +++ b/src/Services/CRM/Quote/Result/QuoteItemResult.php @@ -76,7 +76,7 @@ class QuoteItemResult extends AbstractCrmItem * @return mixed|null * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException */ - public function getUserfieldByFieldName(string $userfieldName) + public function getUserfieldByFieldName(string $userfieldName): mixed { return $this->getKeyWithUserfieldByFieldName($userfieldName); } diff --git a/src/Services/CRM/Quote/Service/QuoteProductRows.php b/src/Services/CRM/Quote/Service/QuoteProductRows.php index 3a224552..279b036b 100644 --- a/src/Services/CRM/Quote/Service/QuoteProductRows.php +++ b/src/Services/CRM/Quote/Service/QuoteProductRows.php @@ -31,7 +31,6 @@ class QuoteProductRows extends AbstractService * * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-product-rows-get.html * - * @param Currency|null $currency * @throws BaseException * @throws TransportException */ @@ -40,7 +39,7 @@ class QuoteProductRows extends AbstractService 'https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-product-rows-get.html', 'Returns products inside the specified quote.' )] - public function get(int $quoteId, Currency $currency = null): QuoteProductRowItemsResult + public function get(int $quoteId, ?Currency $currency = null): QuoteProductRowItemsResult { if (!$currency instanceof \Money\Currency) { $res = $this->core->call('batch', [ diff --git a/src/Services/CRM/Requisites/Result/RequisiteBankdetailItemResult.php b/src/Services/CRM/Requisites/Result/RequisiteBankdetailItemResult.php index 2fc75b4d..de450f2b 100644 --- a/src/Services/CRM/Requisites/Result/RequisiteBankdetailItemResult.php +++ b/src/Services/CRM/Requisites/Result/RequisiteBankdetailItemResult.php @@ -60,7 +60,7 @@ class RequisiteBankdetailItemResult extends AbstractCrmItem * @return mixed|null * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException */ - public function getUserfieldByFieldName(string $userfieldName) + public function getUserfieldByFieldName(string $userfieldName): mixed { return $this->getKeyWithUserfieldByFieldName($userfieldName); } diff --git a/src/Services/Catalog/Common/Result/AbstractCatalogItem.php b/src/Services/Catalog/Common/Result/AbstractCatalogItem.php index 7b6da5fd..e2929d73 100644 --- a/src/Services/Catalog/Common/Result/AbstractCatalogItem.php +++ b/src/Services/Catalog/Common/Result/AbstractCatalogItem.php @@ -25,7 +25,7 @@ abstract class AbstractCatalogItem extends AbstractItem private Currency $currency; - public function __construct(array $data, Currency $currency = null) + public function __construct(array $data, ?Currency $currency = null) { parent::__construct($data); if ($currency instanceof Currency) { diff --git a/src/Services/Entity/Item/Service/Batch.php b/src/Services/Entity/Item/Service/Batch.php index 132f0948..756d887f 100644 --- a/src/Services/Entity/Item/Service/Batch.php +++ b/src/Services/Entity/Item/Service/Batch.php @@ -37,7 +37,7 @@ public function __construct( 'https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-get.html', 'Get the list of storage items in batch mode' )] - public function get(string $entity, array $sort = [], array $filter = [], int $limit = null): Generator + public function get(string $entity, array $sort = [], array $filter = [], ?int $limit = null): Generator { foreach ( $this->batch->getTraversableList( diff --git a/src/Services/Entity/Section/Service/Batch.php b/src/Services/Entity/Section/Service/Batch.php index aa1d34fd..68905036 100644 --- a/src/Services/Entity/Section/Service/Batch.php +++ b/src/Services/Entity/Section/Service/Batch.php @@ -37,7 +37,7 @@ public function __construct( 'https://apidocs.bitrix24.com/api-reference/entity/sections/entity-section-get.html', 'Get the list of storage sections in batch mode' )] - public function get(string $entity, array $sort = [], array $filter = [], int $limit = null): Generator + public function get(string $entity, array $sort = [], array $filter = [], ?int $limit = null): Generator { foreach ( $this->batch->getTraversableList( diff --git a/src/Services/Task/Result/TaskItemResult.php b/src/Services/Task/Result/TaskItemResult.php index 6ae19f61..f3a24db4 100644 --- a/src/Services/Task/Result/TaskItemResult.php +++ b/src/Services/Task/Result/TaskItemResult.php @@ -94,7 +94,7 @@ class TaskItemResult extends AbstractItem * @return mixed|null * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException */ - public function getUserfieldByFieldName(string $userfieldName) + public function getUserfieldByFieldName(string $userfieldName): mixed { return $this->getKeyWithUserfieldByFieldName($userfieldName); } diff --git a/src/Services/Workflows/Workflow/Service/Workflow.php b/src/Services/Workflows/Workflow/Service/Workflow.php index 55071fc4..48cee0e8 100644 --- a/src/Services/Workflows/Workflow/Service/Workflow.php +++ b/src/Services/Workflows/Workflow/Service/Workflow.php @@ -94,7 +94,7 @@ public function start( int $bizProcTemplateId, int $entityId, array $callParameters = [], - int $smartProcessId = null + ?int $smartProcessId = null ): Workflows\Workflow\Result\WorkflowInstanceStartResult { $documentId = null; diff --git a/tests/Integration/Services/Sale/Status/Service/StatusTest.php b/tests/Integration/Services/Sale/Status/Service/StatusTest.php index 58ce45c7..c13d0e22 100644 --- a/tests/Integration/Services/Sale/Status/Service/StatusTest.php +++ b/tests/Integration/Services/Sale/Status/Service/StatusTest.php @@ -56,9 +56,9 @@ protected function setUp(): void protected function tearDown(): void { // Clean up any test statuses created during tests - foreach ($this->testStatusIds as $testRectorPrefix202407StatusId) { + foreach ($this->testStatusIds as $testRectorPrefix202411StatusId) { try { - $this->deleteStatus($testRectorPrefix202407StatusId); + $this->deleteStatus($testRectorPrefix202411StatusId); } catch (\Exception) { // Ignore errors during cleanup } diff --git a/tests/Integration/Services/Sale/StatusLang/Service/StatusLangTest.php b/tests/Integration/Services/Sale/StatusLang/Service/StatusLangTest.php index d02338af..1272c341 100644 --- a/tests/Integration/Services/Sale/StatusLang/Service/StatusLangTest.php +++ b/tests/Integration/Services/Sale/StatusLang/Service/StatusLangTest.php @@ -57,12 +57,12 @@ protected function setUp(): void protected function tearDown(): void { // Clean up any test status langs created during tests - foreach ($this->createdStatusLangs as $createdRectorPrefix202407StatusLang) { + foreach ($this->createdStatusLangs as $createdRectorPrefix202411StatusLang) { try { $this->statusLangService->deleteByFilter([ - 'statusId' => $createdRectorPrefix202407StatusLang['STATUS_ID'], - 'lid' => $createdRectorPrefix202407StatusLang['LID'], - 'name' => $createdRectorPrefix202407StatusLang['NAME'], + 'statusId' => $createdRectorPrefix202411StatusLang['STATUS_ID'], + 'lid' => $createdRectorPrefix202411StatusLang['LID'], + 'name' => $createdRectorPrefix202411StatusLang['NAME'], ]); } catch (\Exception) { // Ignore errors during cleanup @@ -71,9 +71,9 @@ protected function tearDown(): void // Clean up any test statuses created during tests $statusService = Fabric::getServiceBuilder()->getSaleScope()->status(); - foreach ($this->createdStatusIds as $createdRectorPrefix202407StatusId) { + foreach ($this->createdStatusIds as $createdRectorPrefix202411StatusId) { try { - $statusService->delete($createdRectorPrefix202407StatusId); + $statusService->delete($createdRectorPrefix202411StatusId); } catch (\Exception) { // Ignore errors during cleanup } @@ -208,9 +208,9 @@ public function testAdd(): void // Find our status language $found = false; - foreach ($statusLangs as $RectorPrefix202407statusLang) { - if ($RectorPrefix202407statusLang->statusId === $statusId && $RectorPrefix202407statusLang->lid === $langId) { - $this->assertEquals($name, $RectorPrefix202407statusLang->name); + foreach ($statusLangs as $RectorPrefix202411statusLang) { + if ($RectorPrefix202411statusLang->statusId === $statusId && $RectorPrefix202411statusLang->lid === $langId) { + $this->assertEquals($name, $RectorPrefix202411statusLang->name); $found = true; break; } diff --git a/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php index e89edda0..d654eed3 100644 --- a/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php +++ b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php @@ -38,7 +38,7 @@ class ExternalLineTest extends TestCase #[TestDox('Method tests add external line method')] public function testExternalLineAdd(): void { - $lineNumber = time() . abs(random_int(PHP_INT_MIN, PHP_INT_MAX)); + $lineNumber = time() . random_int(0, PHP_INT_MAX); $externalLineAddedResult = $this->externalLine->add($lineNumber, true, sprintf('line-name-%s', $lineNumber)); $this->assertGreaterThan(0, $externalLineAddedResult->getExternalLineAddResultItem()->ID); $this->assertContains($lineNumber, array_column($this->externalLine->get()->getExternalLines(), 'NUMBER')); @@ -61,7 +61,7 @@ public function testGetExternalLine(): void #[TestDox('Method tests delete external line method')] public function testDeleteExternalLine(): void { - $lineNumber = time() . abs(random_int(PHP_INT_MIN, PHP_INT_MAX)); + $lineNumber = time() . random_int(1000, PHP_INT_MAX); $this->externalLine->add($lineNumber, true, sprintf('line-name-%s', $lineNumber)); $this->assertContains($lineNumber, array_column($this->externalLine->get()->getExternalLines(), 'NUMBER'));