diff --git a/CHANGELOG.md b/CHANGELOG.md index 94b67449..76e2800b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,23 @@ # b24-php-sdk change log -## Unreleased 1.3.0 – 2025.01.19 +## Unreleased 1.3.0 – 2025.02.03 ### Added +- Added support new scope `entity` +- Added service `Services\Entity\Service\Item` with support methods, + see [fix entity.item.* methods](https://github.com/bitrix24/b24phpsdk/issues/53): + - `get` get item, with batch calls support + - `add` add new item, with batch calls support + - `delete` delete item, with batch calls support + - `update` update item, with batch calls support +- Added service `Services\Entity\Service\Entity` with support methods, + see [fix entity.* methods](https://github.com/bitrix24/b24phpsdk/issues/53): + - `get` get entity + - `add` add new entity + - `delete` delete entity + - `update` update entity + - `rights` get or change access permissions - Added new application scope nodes `humanresources.hcmlink` and `sign.b2e` - Added method `Bitrix24\SDK\Core\Credentials\Scope::contains` for check is current scope code contains in scope, for task «[split cli commands](https://github.com/bitrix24/b24phpsdk/issues/92)» @@ -59,6 +73,8 @@ - Fixed errors in `Bitrix24\SDK\Core\Batch` for method `user.get`, [see details](https://github.com/bitrix24/b24phpsdk/issues/103) +- Fixed errors in `Bitrix24\SDK\Core\Batch` for methods `entity.item.get` and + `entity.item.update`, [see details](https://github.com/bitrix24/b24phpsdk/issues/53) ### Statistics diff --git a/Makefile b/Makefile index db997b97..1c447c00 100644 --- a/Makefile +++ b/Makefile @@ -127,4 +127,6 @@ test-integration-scope-user: test-integration-scope-user-consent: vendor/bin/phpunit --testsuite integration_tests_scope_user_consent test-integration-core: - vendor/bin/phpunit --testsuite integration_tests_core \ No newline at end of file + vendor/bin/phpunit --testsuite integration_tests_core +test-integration-scope-entity: + vendor/bin/phpunit --testsuite integration_tests_scope_entity \ No newline at end of file diff --git a/docs/EN/Services/bitrix24-php-sdk-methods.md b/docs/EN/Services/bitrix24-php-sdk-methods.md index 89ca1f2f..c18042ce 100644 --- a/docs/EN/Services/bitrix24-php-sdk-methods.md +++ b/docs/EN/Services/bitrix24-php-sdk-methods.md @@ -11,6 +11,15 @@ |`–`|[methods](https://training.bitrix24.com/rest_help/general/methods.php)|Returns the methods available to the current application|[`Bitrix24\SDK\Services\Main\Service\Main::getMethodsByScope`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Main/Service/Main.php#L212-L215)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Response/Response.php)| |`–`|[app.info](https://training.bitrix24.com/rest_help/general/app_info.php)|Displays application information. The method supports secure calling convention.|[`Bitrix24\SDK\Services\Main\Service\Main::getApplicationInfo`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Main/Service/Main.php#L229-L232)
Return type
[`Bitrix24\SDK\Services\Main\Result\ApplicationInfoResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Main/Result/ApplicationInfoResult.php)| |`–`|[user.admin](https://training.bitrix24.com/rest_help/general/user_admin.php)|Checks if a current user has permissions to manage application parameters.|[`Bitrix24\SDK\Services\Main\Service\Main::isCurrentUserHasAdminRights`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Main/Service/Main.php#L246-L249)
Return type
[`Bitrix24\SDK\Services\Main\Result\IsUserAdminResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Main/Result/IsUserAdminResult.php)| +|`entity`|[entity.add](https://apidocs.bitrix24.com/api-reference/entity/entities/entity-add.html)|Create Data Storage|[`Bitrix24\SDK\Services\Entity\Entity\Service\Entity::add`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Entity/Entity/Service/Entity.php#L54-L69)
Return type
[`Bitrix24\SDK\Services\Entity\Entity\Result\AddedEntityResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Entity/Entity/Result/AddedEntityResult.php)| +|`entity`|[entity.update](https://apidocs.bitrix24.com/api-reference/entity/entities/entity-update.html)|Change Parameters|[`Bitrix24\SDK\Services\Entity\Entity\Service\Entity::update`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Entity/Entity/Service/Entity.php#L83-L102)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/UpdatedItemResult.php)| +|`entity`|[entity.delete](https://apidocs.bitrix24.com/api-reference/entity/entities/entity-delete.html)|Delete Storage|[`Bitrix24\SDK\Services\Entity\Entity\Service\Entity::delete`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Entity/Entity/Service/Entity.php#L117-L129)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/DeletedItemResult.php)| +|`entity`|[entity.get](https://apidocs.bitrix24.com/api-reference/entity/entities/entity-get.html)|Get Storage Parameters or List of All Storages|[`Bitrix24\SDK\Services\Entity\Entity\Service\Entity::get`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Entity/Entity/Service/Entity.php#L143-L146)
Return type
[`Bitrix24\SDK\Services\Entity\Entity\Result\EntitiesResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Entity/Entity/Result/EntitiesResult.php)| +|`entity`|[entity.rights](https://apidocs.bitrix24.com/api-reference/entity/entities/entity-rights.html)|Get or Change Access Permissions|[`Bitrix24\SDK\Services\Entity\Entity\Service\Entity::rights`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Entity/Entity/Service/Entity.php#L160-L171)
Return type
[`Bitrix24\SDK\Services\Entity\Entity\Result\EntityRightsResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Entity/Entity/Result/EntityRightsResult.php)| +|`entity`|[entity.item.add](https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-add.html)|Add Storage Element|[`Bitrix24\SDK\Services\Entity\Item\Service\Item::add`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Entity/Item/Service/Item.php#L52-L69)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/AddedItemResult.php)

⚡️Batch methods:
| +|`entity`|[entity.item.get](https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-get.html)|Get the list of storage items|[`Bitrix24\SDK\Services\Entity\Item\Service\Item::get`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Entity/Item/Service/Item.php#L83-L98)
Return type
[`Bitrix24\SDK\Services\Entity\Item\Result\ItemsResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Entity/Item/Result/ItemsResult.php)

⚡️Batch methods:
| +|`entity`|[entity.item.delete](https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-delete.html)|Delete Storage Element|[`Bitrix24\SDK\Services\Entity\Item\Service\Item::delete`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Entity/Item/Service/Item.php#L112-L125)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/DeletedItemResult.php)

⚡️Batch methods:
| +|`entity`|[entity.item.update](https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-update.html)|Update Storage Item|[`Bitrix24\SDK\Services\Entity\Item\Service\Item::update`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Entity/Item/Service/Item.php#L139-L154)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/UpdatedItemResult.php)

⚡️Batch methods:
| |`catalog`|[catalog.catalog.get](https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_get.php)|The method gets field values of commercial catalog by ID.|[`Bitrix24\SDK\Services\Catalog\Catalog\Service\Catalog::get`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Catalog/Catalog/Service/Catalog.php#L41-L44)
Return type
[`Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Catalog/Catalog/Result/CatalogResult.php)| |`catalog`|[catalog.catalog.list](https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_list.php)|The method gets field value of commercial catalog product list|[`Bitrix24\SDK\Services\Catalog\Catalog\Service\Catalog::list`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Catalog/Catalog/Service/Catalog.php#L58-L66)
Return type
[`Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogsResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Catalog/Catalog/Result/CatalogsResult.php)| |`catalog`|[catalog.catalog.getFields](https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_getfields.php)|Retrieves the fields for the catalog.|[`Bitrix24\SDK\Services\Catalog\Catalog\Service\Catalog::fields`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Catalog/Catalog/Service/Catalog.php#L81-L84)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/FieldsResult.php)| @@ -160,12 +169,12 @@ |`bizproc`|[bizproc.task.complete](https://training.bitrix24.com/rest_help/workflows/workflows_tasks/bizproc_task_complete.php)|Complete workflow task|[`Bitrix24\SDK\Services\Workflows\Task\Service\Task::complete`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Workflows/Task/Service/Task.php#L63-L71)
Return type
[`Bitrix24\SDK\Services\Workflows\Task\Result\WorkflowTaskCompleteResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Workflows/Task/Result/WorkflowTaskCompleteResult.php)| |`bizproc`|[bizproc.task.list](https://training.bitrix24.com/rest_help/workflows/workflows_tasks/bizproc_task_list.php)|List of workflow tasks|[`Bitrix24\SDK\Services\Workflows\Task\Service\Task::list`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Workflows/Task/Service/Task.php#L133-L143)
Return type
[`Bitrix24\SDK\Services\Workflows\Task\Result\WorkflowTasksResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Workflows/Task/Result/WorkflowTasksResult.php)| |`bizproc`|[bizproc.event.send](https://training.bitrix24.com/rest_help/workflows/workflows_events/bizproc_event_send.php)|returns output parameters to an activity. Parameters are specified in the activity description.|[`Bitrix24\SDK\Services\Workflows\Event\Service\Event::send`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Workflows/Event/Service/Event.php#L50-L64)
Return type
[`Bitrix24\SDK\Services\Workflows\Event\Result\EventSendResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Workflows/Event/Result/EventSendResult.php)| -|`user`|[user.fields](https://training.bitrix24.com/rest_help/users/user_fields.php)|Get user entity fields|[`Bitrix24\SDK\Services\User\Service\User::fields`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Service/User.php#L43-L46)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/FieldsResult.php)| -|`user`|[user.current](https://training.bitrix24.com/rest_help/users/user_current.php)|Get current user|[`Bitrix24\SDK\Services\User\Service\User::current`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Service/User.php#L59-L62)
Return type
[`Bitrix24\SDK\Services\User\Result\UserResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Result/UserResult.php)| -|`user`|[user.add](https://training.bitrix24.com/rest_help/users/user_add.php)|Invites a user. Available only for users with invitation permissions, usually an administrator. Sends a standard account invitation to the user on success.|[`Bitrix24\SDK\Services\User\Service\User::add`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Service/User.php#L77-L92)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/AddedItemResult.php)| -|`user`|[user.get](https://training.bitrix24.com/rest_help/users/user_get.php)|Get user by id|[`Bitrix24\SDK\Services\User\Service\User::get`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Service/User.php#L104-L116)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Result/UsersResult.php)| -|`user`|[user.update](https://training.bitrix24.com/rest_help/users/user_get.php)|Updates user information. Available only for users with invitation permissions.|[`Bitrix24\SDK\Services\User\Service\User::update`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Service/User.php#L129-L137)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/UpdatedItemResult.php)| -|`user`|[user.search](https://training.bitrix24.com/rest_help/users/user_search.php)|This method is used to retrieve list of users with expedited personal data search.|[`Bitrix24\SDK\Services\User\Service\User::search`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Service/User.php#L151-L154)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Result/UsersResult.php)| +|`user`|[user.fields](https://training.bitrix24.com/rest_help/users/user_fields.php)|Get user entity fields|[`Bitrix24\SDK\Services\User\Service\User::fields`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Service/User.php#L50-L53)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/FieldsResult.php)| +|`user`|[user.current](https://training.bitrix24.com/rest_help/users/user_current.php)|Get current user|[`Bitrix24\SDK\Services\User\Service\User::current`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Service/User.php#L66-L69)
Return type
[`Bitrix24\SDK\Services\User\Result\UserResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Result/UserResult.php)| +|`user`|[user.add](https://training.bitrix24.com/rest_help/users/user_add.php)|Invites a user. Available only for users with invitation permissions, usually an administrator. Sends a standard account invitation to the user on success.|[`Bitrix24\SDK\Services\User\Service\User::add`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Service/User.php#L84-L99)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/AddedItemResult.php)

⚡️Batch methods:
| +|`user`|[user.get](https://training.bitrix24.com/rest_help/users/user_get.php)|Get user by id|[`Bitrix24\SDK\Services\User\Service\User::get`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Service/User.php#L111-L123)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Result/UsersResult.php)

⚡️Batch methods:
| +|`user`|[user.update](https://training.bitrix24.com/rest_help/users/user_get.php)|Updates user information. Available only for users with invitation permissions.|[`Bitrix24\SDK\Services\User\Service\User::update`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Service/User.php#L136-L144)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/UpdatedItemResult.php)| +|`user`|[user.search](https://training.bitrix24.com/rest_help/users/user_search.php)|This method is used to retrieve list of users with expedited personal data search.|[`Bitrix24\SDK\Services\User\Service\User::search`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Service/User.php#L158-L161)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/User/Result/UsersResult.php)| |`telephony`|[voximplant.user.deactivatePhone](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_user_deactivatePhone.php)|This method disables an indicator of SIP-phone availability. Method checks the availability of the access permissions to modify users.|[`Bitrix24\SDK\Services\Telephony\Voximplant\User\Service\User::deactivatePhone`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Telephony/Voximplant/User/Service/User.php#L52-L57)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/UserInterfaceDialogCallResult.php)| |`telephony`|[voximplant.user.activatePhone](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_user_activatePhone.php)|This method raises the event of SIP-phone availability for an employee. Method checks the availability of the access permissions to modify users.|[`Bitrix24\SDK\Services\Telephony\Voximplant\User\Service\User::activatePhone`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Telephony/Voximplant/User/Service/User.php#L73-L78)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Core/Result/UserInterfaceDialogCallResult.php)| |`telephony`|[voximplant.user.get](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_user_get.php)|This method returns user settings.|[`Bitrix24\SDK\Services\Telephony\Voximplant\User\Service\User::get`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Telephony/Voximplant/User/Service/User.php#L95-L102)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\User\Result\VoximplantUserSettingsResult`](https://github.com/bitrix24/b24phpsdk/blob/master/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsResult.php)| diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 9976fd86..6c2bcbcc 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -37,6 +37,9 @@ ./tests/Integration/Services/Workflows/ + + ./tests/Integration/Services/Entity/ + diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 39c23814..1dc7d46f 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -108,18 +108,21 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator /** * Delete entity items with batch call * - * @param array $entityItemId * * @return Generator|ResponseData[] * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator - { + public function deleteEntityItems( + string $apiMethod, + array $entityItemId, + ?array $additionalParameters = null + ): Generator { $this->logger->debug( 'deleteEntityItems.start', [ 'apiMethod' => $apiMethod, 'entityItems' => $entityItemId, + 'additionalParameters' => $additionalParameters, ] ); @@ -137,7 +140,12 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener ); } - $this->registerCommand($apiMethod, ['ID' => $itemId]); + $parameters = ['ID' => $itemId]; + if ($apiMethod === 'entity.item.delete') { + $parameters = array_merge($parameters, $additionalParameters); + } + + $this->registerCommand($apiMethod, $parameters); } foreach ($this->getTraversable(true) as $cnt => $deletedItemResult) { @@ -204,18 +212,22 @@ public function updateEntityItems(string $apiMethod, array $entityItems): Genera ); } - if (!array_key_exists('fields', $entityItem)) { - throw new InvalidArgumentException( - sprintf('array key «fields» not found in entity item with id %s', $entityItemId) - ); - } + if ($apiMethod !== 'entity.item.update') { + if (!array_key_exists('fields', $entityItem)) { + throw new InvalidArgumentException( + sprintf('array key «fields» not found in entity item with id %s', $entityItemId) + ); + } - $cmdArguments = [ - 'id' => $entityItemId, - 'fields' => $entityItem['fields'] - ]; - if (array_key_exists('params', $entityItem)) { - $cmdArguments['params'] = $entityItem['params']; + $cmdArguments = [ + 'id' => $entityItemId, + 'fields' => $entityItem['fields'] + ]; + if (array_key_exists('params', $entityItem)) { + $cmdArguments['params'] = $entityItem['params']; + } + } else { + $cmdArguments = $entityItem; } $this->registerCommand($apiMethod, $cmdArguments); @@ -397,7 +409,10 @@ public function getTraversableList( } $keyId = $isCrmItemsInBatch ? 'id' : 'ID'; - + $this->logger->debug('getTraversableList.getFirstPage', [ + 'apiMethod' => $apiMethod, + 'params' => $params, + ]); $response = $this->core->call($apiMethod, $params); $totalElementsCount = $response->getResponseData()->getPagination()->getTotal(); $this->logger->debug('getTraversableList.totalElementsCount', [ @@ -453,8 +468,11 @@ public function getTraversableList( // getLastElementId in filtered result // todo wait new api version if ($apiMethod !== 'user.get') { + $defaultOrderKey = 'order'; + $orderKey = $apiMethod === 'entity.item.get' ? 'SORT' : $defaultOrderKey; + $params = [ - 'order' => $this->getReverseOrder($order), + $orderKey => $this->getReverseOrder($order), 'filter' => $filter, 'select' => $select, 'start' => 0, @@ -474,6 +492,10 @@ public function getTraversableList( $params = array_merge($params, $additionalParameters); } + $this->logger->debug('getTraversableList.getLastPage', [ + 'apiMethod' => $apiMethod, + 'params' => $params, + ]); $lastResultPage = $this->core->call($apiMethod, $params); if ($isCrmItemsInBatch) { $lastElementId = (int)$lastResultPage->getResponseData()->getResult()['items'][0][$keyId]; @@ -481,18 +503,19 @@ public function getTraversableList( $lastElementId = (int)$lastResultPage->getResponseData()->getResult()[0][$keyId]; } - // reverse order if you need + $this->logger->debug('getTraversableList.lastElementsId', [ + 'lastElementIdInFirstPage' => $lastElementIdInFirstPage, + 'lastElementIdInLastPage' => $lastElementId, + ]); + + + // reverse order if elements in batch ordered in DESC direction if ($lastElementIdInFirstPage > $lastElementId) { $tmp = $lastElementIdInFirstPage; $lastElementIdInFirstPage = $lastElementId; $lastElementId = $tmp; } - $this->logger->debug('getTraversableList.lastElementsId', [ - 'lastElementIdInFirstPage' => $lastElementIdInFirstPage, - 'lastElementId' => $lastElementId, - ]); - // register commands with updated filter //more than one page in results - register list commands ++$lastElementIdInFirstPage; diff --git a/src/Core/Contracts/BatchOperationsInterface.php b/src/Core/Contracts/BatchOperationsInterface.php index e79b415c..76bd8938 100644 --- a/src/Core/Contracts/BatchOperationsInterface.php +++ b/src/Core/Contracts/BatchOperationsInterface.php @@ -76,7 +76,11 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator * @return Generator|ResponseData[] * @throws BaseException */ - public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator; + public function deleteEntityItems( + string $apiMethod, + array $entityItemId, + ?array $additionalParameters = null + ): Generator; /** * Update entity items with batch call diff --git a/src/Services/AbstractService.php b/src/Services/AbstractService.php index ce1f9fad..756b8a61 100644 --- a/src/Services/AbstractService.php +++ b/src/Services/AbstractService.php @@ -55,4 +55,14 @@ protected function guardPositiveId(int $id): void throw new InvalidArgumentException(sprintf('id must be positive, current value: %s', $id)); } } + + /** + * @throws InvalidArgumentException + */ + protected function guardNonEmptyString(string $value, ?string $message = null): void + { + if (trim($value) === '') { + throw new InvalidArgumentException($message ?? 'value must be non empty'); + } + } } \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index d756db80..cf130122 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -141,6 +141,8 @@ public function __get($offset) case 'LAST_ACTIVITY_TIME': case 'START_TIME': case 'END_TIME': + case 'DATE_ACTIVE_FROM': + case 'DATE_ACTIVE_TO': case 'TIMESTAMP_X': if ($this->data[$offset] !== '') { return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); diff --git a/src/Services/Entity/Entity/Result/AddedEntityResult.php b/src/Services/Entity/Entity/Result/AddedEntityResult.php new file mode 100644 index 00000000..352a989a --- /dev/null +++ b/src/Services/Entity/Entity/Result/AddedEntityResult.php @@ -0,0 +1,28 @@ + + * + * 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 Bitrix24\SDK\Services\Entity\Entity\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class AddedEntityResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function isSuccess(): bool + { + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Entity/Entity/Result/EntitiesResult.php b/src/Services/Entity/Entity/Result/EntitiesResult.php new file mode 100644 index 00000000..9b539a1e --- /dev/null +++ b/src/Services/Entity/Entity/Result/EntitiesResult.php @@ -0,0 +1,34 @@ + + * + * 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 Bitrix24\SDK\Services\Entity\Entity\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class EntitiesResult extends AbstractResult +{ + /** + * @return EntityItemResult[] + * @throws BaseException + */ + public function getEntities(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new EntityItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Entity/Entity/Result/EntityItemResult.php b/src/Services/Entity/Entity/Result/EntityItemResult.php new file mode 100644 index 00000000..5a37c284 --- /dev/null +++ b/src/Services/Entity/Entity/Result/EntityItemResult.php @@ -0,0 +1,31 @@ + + * + * 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 Bitrix24\SDK\Services\Entity\Entity\Result; + +use Bitrix24\SDK\Services\Catalog\Common\ProductType; +use Bitrix24\SDK\Services\Catalog\Common\Result\AbstractCatalogItem; +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use Carbon\CarbonImmutable; +use Money\Currency; +use Money\Money; + +/** + * @property-read int $ID + * @property-read string $IBLOCK_TYPE_ID + * @property-read string $ENTITY + * @property-read string $NAME + */ +class EntityItemResult extends AbstractCrmItem +{ +} \ No newline at end of file diff --git a/src/Services/Entity/Entity/Result/EntityRightsResult.php b/src/Services/Entity/Entity/Result/EntityRightsResult.php new file mode 100644 index 00000000..0aa69f55 --- /dev/null +++ b/src/Services/Entity/Entity/Result/EntityRightsResult.php @@ -0,0 +1,25 @@ + + * + * 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 Bitrix24\SDK\Services\Entity\Entity\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class EntityRightsResult extends AbstractResult +{ + public function getRights(): array + { + return $this->getCoreResponse()->getResponseData()->getResult(); + } +} \ No newline at end of file diff --git a/src/Services/Entity/Entity/Service/Batch.php b/src/Services/Entity/Entity/Service/Batch.php new file mode 100644 index 00000000..c30c83c6 --- /dev/null +++ b/src/Services/Entity/Entity/Service/Batch.php @@ -0,0 +1,31 @@ + + * + * 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 Bitrix24\SDK\Services\Entity\Entity\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AddedItemBatchResult; +use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; +use Bitrix24\SDK\Core\Result\UpdatedItemBatchResult; +use Generator; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Entity/Entity/Service/Entity.php b/src/Services/Entity/Entity/Service/Entity.php new file mode 100644 index 00000000..d2501753 --- /dev/null +++ b/src/Services/Entity/Entity/Service/Entity.php @@ -0,0 +1,172 @@ + + * + * 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 Bitrix24\SDK\Services\Entity\Entity\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Entity\Entity\Result\AddedEntityResult; +use Bitrix24\SDK\Services\Entity\Entity\Result\EntitiesResult; +use Bitrix24\SDK\Services\Entity\Entity\Result\EntityRightsResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['entity']))] +class Entity extends AbstractService +{ + public function __construct( + public Batch $batch, + CoreInterface $core, + LoggerInterface $logger + ) { + parent::__construct($core, $logger); + } + + /** + * Create Data Storage + * + * @see https://apidocs.bitrix24.com/api-reference/entity/entities/entity-add.html + * @throws TransportException + * @throws BaseException + */ + #[ApiEndpointMetadata( + 'entity.add', + 'https://apidocs.bitrix24.com/api-reference/entity/entities/entity-add.html', + 'Create Data Storage' + )] + public function add(string $entity, string $name, array $access): AddedEntityResult + { + $this->guardNonEmptyString($entity, 'entity must be an non empty string'); + $this->guardNonEmptyString($name, 'entity name must be an non empty string'); + + return new AddedEntityResult( + $this->core->call( + 'entity.add', + [ + 'ENTITY' => $entity, + 'NAME' => $name, + 'ACCESS' => $access, + ] + ) + ); + } + + /** + * Change Parameters + * + * @see https://apidocs.bitrix24.com/api-reference/entity/entities/entity-update.html + * @throws TransportException + * @throws BaseException + */ + #[ApiEndpointMetadata( + 'entity.update', + 'https://apidocs.bitrix24.com/api-reference/entity/entities/entity-update.html', + 'Change Parameters' + )] + public function update( + string $entity, + ?string $name = null, + ?array $access = null, + ?string $updatedEntity = null + ): UpdatedItemResult { + $this->guardNonEmptyString($entity, 'entity must be an non empty string'); + + return new UpdatedItemResult( + $this->core->call( + 'entity.update', + [ + 'ENTITY' => $entity, + 'NAME' => $name, + 'ACCESS' => $access, + 'ENTITY_NEW' => $updatedEntity, + ] + ) + ); + } + + /** + * Delete Storage entity.delete + * + * @see https://apidocs.bitrix24.com/api-reference/entity/entities/entity-delete.html + * @throws TransportException + * @throws InvalidArgumentException + * @throws BaseException + */ + #[ApiEndpointMetadata( + 'entity.delete', + 'https://apidocs.bitrix24.com/api-reference/entity/entities/entity-delete.html', + 'Delete Storage' + )] + public function delete(string $entity): DeletedItemResult + { + $this->guardNonEmptyString($entity, 'entity must be an non empty string'); + + return new DeletedItemResult( + $this->core->call( + 'entity.delete', + [ + 'ENTITY' => $entity, + ] + ) + ); + } + + /** + * Get Storage Parameters or List of All Storages + * + * @see https://apidocs.bitrix24.com/api-reference/entity/entities/entity-get.html + * @throws TransportException + * @throws BaseException + */ + #[ApiEndpointMetadata( + 'entity.get', + 'https://apidocs.bitrix24.com/api-reference/entity/entities/entity-get.html', + 'Get Storage Parameters or List of All Storages' + )] + public function get(?string $entity = null): EntitiesResult + { + return new EntitiesResult($this->core->call('entity.get', ['ENTITY' => $entity])); + } + + /** + * Get or Change Access Permissions + * + * @see https://apidocs.bitrix24.com/api-reference/entity/entities/entity-rights.html + * @throws TransportException + * @throws BaseException + */ + #[ApiEndpointMetadata( + 'entity.rights', + 'https://apidocs.bitrix24.com/api-reference/entity/entities/entity-rights.html', + 'Get or Change Access Permissions' + )] + public function rights(?string $entity = null, ?array $access = null): EntityRightsResult + { + return new EntityRightsResult( + $this->core->call( + 'entity.rights', + [ + 'ENTITY' => $entity, + 'ACCESS' => $access + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/Entity/EntityServiceBuilder.php b/src/Services/Entity/EntityServiceBuilder.php new file mode 100644 index 00000000..2bb6d5d3 --- /dev/null +++ b/src/Services/Entity/EntityServiceBuilder.php @@ -0,0 +1,49 @@ + + * + * 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 Bitrix24\SDK\Services\Entity; + +use Bitrix24\SDK\Attributes\ApiServiceBuilderMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\Entity; + +#[ApiServiceBuilderMetadata(new Scope(['entity']))] +class EntityServiceBuilder extends AbstractServiceBuilder +{ + public function entity(): Entity\Entity\Service\Entity + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Entity\Entity\Service\Entity( + new Entity\Entity\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function item(): Entity\Item\Service\Item + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Entity\Item\Service\Item( + new Entity\Item\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/Entity/Item/Result/ItemItemResult.php b/src/Services/Entity/Item/Result/ItemItemResult.php new file mode 100644 index 00000000..2bbc949e --- /dev/null +++ b/src/Services/Entity/Item/Result/ItemItemResult.php @@ -0,0 +1,40 @@ + + * + * 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 Bitrix24\SDK\Services\Entity\Item\Result; + +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use Carbon\CarbonImmutable; + +/** + * @property-read int $ID + * @property-read CarbonImmutable $TIMESTAMP_X + * @property-read int $MODIFIED_BY + * @property-read int $CREATED_BY + * @property-read int $SORT + * @property-read int|null $SECTION + * @property-read bool $ACTIVE + * @property-read CarbonImmutable $DATE_CREATE + * @property-read CarbonImmutable|null $DATE_ACTIVE_FROM + * @property-read CarbonImmutable|null $DATE_ACTIVE_TO + * @property-read string $NAME + * @property-read array|null $PREVIEW_PICTURE + * @property-read string|null $PREVIEW_TEXT + * @property-read string|null $DETAIL_TEXT + * @property-read string|null $CODE + * @property-read string $ENTITY + * @property-read array|null $DETAIL_PICTURE + */ +class ItemItemResult extends AbstractCrmItem +{ +} \ No newline at end of file diff --git a/src/Services/Entity/Item/Result/ItemsResult.php b/src/Services/Entity/Item/Result/ItemsResult.php new file mode 100644 index 00000000..aeb09e79 --- /dev/null +++ b/src/Services/Entity/Item/Result/ItemsResult.php @@ -0,0 +1,34 @@ + + * + * 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 Bitrix24\SDK\Services\Entity\Item\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ItemsResult extends AbstractResult +{ + /** + * @return ItemItemResult[] + * @throws BaseException + */ + public function getItems(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new ItemItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Entity/Item/Service/Batch.php b/src/Services/Entity/Item/Service/Batch.php new file mode 100644 index 00000000..132f0948 --- /dev/null +++ b/src/Services/Entity/Item/Service/Batch.php @@ -0,0 +1,116 @@ + + * + * 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 Bitrix24\SDK\Services\Entity\Item\Service; + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Result\AddedItemBatchResult; +use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; +use Bitrix24\SDK\Services\Entity\Item\Result\ItemItemResult; +use Generator; +use Psr\Log\LoggerInterface; + +#[ApiBatchServiceMetadata(new Scope(['entity']))] +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log + ) { + } + + #[ApiBatchMethodMetadata( + 'entity.item.get', + '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 + { + foreach ( + $this->batch->getTraversableList( + 'entity.item.get', + $sort, + $filter, + [], + $limit, + ['ENTITY' => $entity] + ) as $key => $value + ) { + yield $key => new ItemItemResult($value); + } + } + + #[ApiBatchMethodMetadata( + 'entity.item.add', + 'https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-add.html', + 'Add in batch mode a list of storage elements' + )] + public function add(string $entity, array $items): Generator + { + $elements = []; + foreach ($items as $item) { + $elements[] = array_merge( + [ + 'ENTITY' => $entity + ], + $item + ); + } + foreach ($this->batch->addEntityItems('entity.item.add', $elements) as $key => $item) { + yield $key => new AddedItemBatchResult($item); + } + } + + #[ApiBatchMethodMetadata( + 'entity.item.delete', + 'https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-delete.html', + 'Delete in batch mode a list of storage elements' + )] + public function delete(string $entity, array $itemIds): Generator + { + foreach ( + $this->batch->deleteEntityItems( + 'entity.item.delete', + $itemIds, + ['ENTITY' => $entity] + ) as $key => $item + ) { + yield $key => new DeletedItemBatchResult($item); + } + } + + #[ApiBatchMethodMetadata( + 'entity.item.update', + 'https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-update.html', + 'Update in batch mode a list of storage elements' + )] + public function update(string $entity, array $items): Generator + { + $dataForUpdate = []; + foreach ($items as $item) { + unset($item['ENTITY']); + $dataForUpdate[] = array_merge( + [ + 'ENTITY' => $entity + ], + $item + ); + } + foreach ($this->batch->updateEntityItems('entity.item.update', $dataForUpdate) as $key => $item) { + yield $key => new DeletedItemBatchResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/Entity/Item/Service/Item.php b/src/Services/Entity/Item/Service/Item.php new file mode 100644 index 00000000..8e77f3b0 --- /dev/null +++ b/src/Services/Entity/Item/Service/Item.php @@ -0,0 +1,155 @@ + + * + * 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 Bitrix24\SDK\Services\Entity\Item\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Entity\Item\Result\ItemsResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['entity']))] +class Item extends AbstractService +{ + public function __construct( + public Batch $batch, + CoreInterface $core, + LoggerInterface $logger + ) { + parent::__construct($core, $logger); + } + + /** + * Add Storage Element + * + * @see https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-add.html + * @throws TransportException + * @throws BaseException + */ + #[ApiEndpointMetadata( + 'entity.item.add', + 'https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-add.html', + 'Add Storage Element' + )] + public function add(string $entity, string $name, array $fields): AddedItemResult + { + $this->guardNonEmptyString($entity, 'entity must be an non empty string'); + $this->guardNonEmptyString($name, 'entity name must be an non empty string'); + + return new AddedItemResult( + $this->core->call( + 'entity.item.add', + array_merge( + [ + 'ENTITY' => $entity, + 'NAME' => $name, + ], + $fields + ), + ) + ); + } + + /** + * Get the list of storage items + * + * @see https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-get.html + * @throws TransportException + * @throws BaseException + */ + #[ApiEndpointMetadata( + 'entity.item.get', + 'https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-get.html', + 'Get the list of storage items' + )] + public function get(string $entity, array $sort = [], array $filter = [], int $startItem = 0): ItemsResult + { + $this->guardNonEmptyString($entity, 'entity must be an non empty string'); + + return new ItemsResult( + $this->core->call( + 'entity.item.get', + [ + 'ENTITY' => $entity, + 'SORT' => $sort, + 'FILTER' => $filter, + 'START' => $startItem, + ], + ) + ); + } + + /** + * Delete Storage Element + * + * @see https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-delete.html + * @throws TransportException + * @throws BaseException + */ + #[ApiEndpointMetadata( + 'entity.item.delete', + 'https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-delete.html', + 'Delete Storage Element' + )] + public function delete(string $entity, int $itemId): DeletedItemResult + { + $this->guardNonEmptyString($entity, 'entity must be an non empty string'); + + return new DeletedItemResult( + $this->core->call( + 'entity.item.delete', + [ + 'ENTITY' => $entity, + 'ID' => $itemId, + ], + ) + ); + } + + /** + * Update Storage Item + * + * @see https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-update.html + * @throws TransportException + * @throws BaseException + */ + #[ApiEndpointMetadata( + 'entity.item.update', + 'https://apidocs.bitrix24.com/api-reference/entity/items/entity-item-update.html', + 'Update Storage Item' + )] + public function update(string $entity, int $id, array $fields): UpdatedItemResult + { + $this->guardNonEmptyString($entity, 'entity must be an non empty string'); + return new UpdatedItemResult( + $this->core->call( + 'entity.item.update', + array_merge( + [ + 'ENTITY' => $entity, + 'ID' => $id, + ], + $fields + ), + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index 85415f1c..e80b9cfe 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -18,6 +18,7 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Services\Catalog\CatalogServiceBuilder; use Bitrix24\SDK\Services\CRM\CRMServiceBuilder; +use Bitrix24\SDK\Services\Entity\EntityServiceBuilder; use Bitrix24\SDK\Services\IM\IMServiceBuilder; use Bitrix24\SDK\Services\IMOpenLines\IMOpenLinesServiceBuilder; use Bitrix24\SDK\Services\Main\MainServiceBuilder; @@ -31,18 +32,37 @@ class ServiceBuilder extends AbstractServiceBuilder { public function __construct( - public CoreInterface $core, + public CoreInterface $core, protected BatchOperationsInterface $batch, protected BulkItemsReaderInterface $bulkItemsReader, - protected LoggerInterface $log) - { + protected LoggerInterface $log + ) { parent::__construct($core, $batch, $bulkItemsReader, $log); } + public function getEntityScope(): EntityServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new EntityServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + public function getCRMScope(): CRMServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new CRMServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + $this->serviceCache[__METHOD__] = new CRMServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); } return $this->serviceCache[__METHOD__]; @@ -51,7 +71,12 @@ public function getCRMScope(): CRMServiceBuilder public function getIMScope(): IMServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new IMServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + $this->serviceCache[__METHOD__] = new IMServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); } return $this->serviceCache[__METHOD__]; @@ -60,7 +85,12 @@ public function getIMScope(): IMServiceBuilder public function getIMOpenLinesScope(): IMOpenLinesServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new IMOpenLinesServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + $this->serviceCache[__METHOD__] = new IMOpenLinesServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); } return $this->serviceCache[__METHOD__]; @@ -72,7 +102,12 @@ public function getIMOpenLinesScope(): IMOpenLinesServiceBuilder public function getMainScope(): MainServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new MainServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + $this->serviceCache[__METHOD__] = new MainServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); } return $this->serviceCache[__METHOD__]; @@ -81,7 +116,12 @@ public function getMainScope(): MainServiceBuilder public function getUserConsentScope(): UserConsentServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new UserConsentServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + $this->serviceCache[__METHOD__] = new UserConsentServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); } return $this->serviceCache[__METHOD__]; @@ -90,7 +130,12 @@ public function getUserConsentScope(): UserConsentServiceBuilder public function getUserScope(): UserServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new UserServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + $this->serviceCache[__METHOD__] = new UserServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); } return $this->serviceCache[__METHOD__]; @@ -102,7 +147,12 @@ public function getUserScope(): UserServiceBuilder public function getPlacementScope(): PlacementServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new PlacementServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + $this->serviceCache[__METHOD__] = new PlacementServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); } return $this->serviceCache[__METHOD__]; @@ -111,7 +161,12 @@ public function getPlacementScope(): PlacementServiceBuilder public function getCatalogScope(): CatalogServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new CatalogServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + $this->serviceCache[__METHOD__] = new CatalogServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); } return $this->serviceCache[__METHOD__]; @@ -120,7 +175,12 @@ public function getCatalogScope(): CatalogServiceBuilder public function getBizProcScope(): WorkflowsServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new WorkflowsServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + $this->serviceCache[__METHOD__] = new WorkflowsServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); } return $this->serviceCache[__METHOD__]; @@ -129,7 +189,12 @@ public function getBizProcScope(): WorkflowsServiceBuilder public function getTelephonyScope(): TelephonyServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new TelephonyServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + $this->serviceCache[__METHOD__] = new TelephonyServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); } return $this->serviceCache[__METHOD__]; diff --git a/tests/Integration/Core/BatchTest.php b/tests/Integration/Core/BatchTest.php index 42c66ba0..99e5639d 100644 --- a/tests/Integration/Core/BatchTest.php +++ b/tests/Integration/Core/BatchTest.php @@ -14,13 +14,23 @@ namespace Bitrix24\SDK\Tests\Integration\Core; use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Services\ServiceBuilder; use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\TestDox; use PHPUnit\Framework\TestCase; use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +#[CoversClass(Batch::class)] +#[CoversMethod(Batch::class, 'getTraversableList')] +#[CoversMethod(Batch::class, 'addEntityItems')] +#[CoversMethod(Batch::class, 'deleteEntityItems')] class BatchTest extends TestCase { private Batch $batch; @@ -32,13 +42,12 @@ class BatchTest extends TestCase /** * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException * @throws \Exception - * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface - * @covers \Bitrix24\SDK\Core\Batch::getTraversableList - * @testdox Get traversable list items in batch mode with more than max batch page count elements + * @throws TransportExceptionInterface */ + #[TestDox("Get traversable list items in batch mode with more than max batch page count elements")] public function testGetTraversableListWithMoreThanMaxBatchPageCountWithoutLimit(): void { // prepare demo data @@ -122,13 +131,12 @@ public function testGetTraversableListWithMoreThanMaxBatchPageCountWithoutLimit( /** * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException * @throws \Exception - * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface - * @covers \Bitrix24\SDK\Core\Batch::getTraversableList - * @testdox Get traversable list items in batch mode with less than one page with limit elements + * @throws TransportExceptionInterface */ + #[TestDox("Get traversable list items in batch mode with less than one page with limit elements")] public function testGetTraversableListWithLessThanPageSizeWithLimit(): void { // prepare demo data @@ -199,13 +207,12 @@ public function testGetTraversableListWithLessThanPageSizeWithLimit(): void /** * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException * @throws \Exception - * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface - * @covers \Bitrix24\SDK\Core\Batch::getTraversableList - * @testdox Get traversable list items in batch mode with count more than one page without limit + * @throws TransportExceptionInterface */ + #[TestDox("Get traversable list items in batch mode with count more than one page without limit")] public function testGetTraversableListWithLessThanPageSizeWithoutLimit(): void { // prepare demo data @@ -275,8 +282,8 @@ public function testGetTraversableListWithLessThanPageSizeWithoutLimit(): void /** * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException * @throws \Exception * @covers \Bitrix24\SDK\Core\Batch::addEntityItems * @testdox Add items in batch mode @@ -313,13 +320,11 @@ public function testBatchAddEntityItems(): void /** * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException * @throws \Exception - * @covers \Bitrix24\SDK\Core\Batch::addEntityItems - * @covers \Bitrix24\SDK\Core\Batch::deleteEntityItems - * @testdox Delete items in batch mode */ + #[TestDox("Delete items in batch mode")] public function testBatchDeleteEntityItems(): void { // prepare demo data @@ -359,9 +364,9 @@ public function testBatchDeleteEntityItems(): void /** * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @testdox Delete items in batch mode with wrong type of entity id + * @throws BaseException */ + #[TestDox("Delete items in batch mode with wrong type of entity id")] public function testBatchDeleteEntityItemsWithWrongTypeOfEntityId(): void { $this->expectException(InvalidArgumentException::class); diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index 238e4b9b..322888b0 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -49,7 +49,7 @@ public static function getServiceBuilder(bool $isNeedApplicationCredentials = fa { return new ServiceBuilder( self::getCore($isNeedApplicationCredentials), - self::getBatchService(), + self::getBatchService($isNeedApplicationCredentials), self::getBulkItemsReader(), self::getLogger() ); @@ -65,7 +65,7 @@ public static function getOpenLineCode(): string /** * @return \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws InvalidArgumentException */ public static function getBulkItemsReader(): BulkItemsReaderInterface { @@ -94,24 +94,28 @@ public static function getCore(bool $isNeedApplicationCredentials = false): Core $credentialsProvider = ApplicationCredentialsProvider::buildProviderForLocalApplication(); - if ($credentialsProvider->isCredentialsAvailable()) { - // register event handler for store new tokens - $eventDispatcher = new EventDispatcher(); - $eventDispatcher->addListener(AuthTokenRenewedEvent::class, [ - $credentialsProvider, - 'onAuthTokenRenewedEventListener' - ]); - - $credentials = $credentialsProvider->getCredentials( - ApplicationProfile::initFromArray($_ENV), - $_ENV['BITRIX24_PHP_SDK_APPLICATION_DOMAIN_URL']); - - return (new CoreBuilder()) - ->withLogger(self::getLogger()) - ->withEventDispatcher($eventDispatcher) - ->withCredentials($credentials) - ->build(); + if (!$credentialsProvider->isCredentialsAvailable()) { + throw new InvalidArgumentException( + 'Application credentials for integration tests are not available. Go to «tests/ApplicationBridge/» and run application bridge.' + ); } + + // register event handler for store new tokens + $eventDispatcher = new EventDispatcher(); + $eventDispatcher->addListener(AuthTokenRenewedEvent::class, [ + $credentialsProvider, + 'onAuthTokenRenewedEventListener' + ]); + + $credentials = $credentialsProvider->getCredentials( + ApplicationProfile::initFromArray($_ENV), + $_ENV['BITRIX24_PHP_SDK_APPLICATION_DOMAIN_URL'] + ); + return (new CoreBuilder()) + ->withLogger(self::getLogger()) + ->withEventDispatcher($eventDispatcher) + ->withCredentials($credentials) + ->build(); } return $default; } @@ -130,11 +134,12 @@ public static function getLogger(): LoggerInterface } /** - * @return \Bitrix24\SDK\Core\Batch - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @param bool $isNeedApplicationCredentials + * @return Batch + * @throws InvalidArgumentException */ - public static function getBatchService(): Batch + public static function getBatchService(bool $isNeedApplicationCredentials = false): Batch { - return new Batch(self::getCore(), self::getLogger()); + return new Batch(self::getCore($isNeedApplicationCredentials), self::getLogger()); } } \ No newline at end of file diff --git a/tests/Integration/Services/Entity/Entity/Service/EntityTest.php b/tests/Integration/Services/Entity/Entity/Service/EntityTest.php new file mode 100644 index 00000000..b78671ae --- /dev/null +++ b/tests/Integration/Services/Entity/Entity/Service/EntityTest.php @@ -0,0 +1,128 @@ + + * + * 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 Bitrix24\SDK\Tests\Integration\Services\Entity\Entity\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Entity\Entity\Service\Entity; +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Attributes\TestDox; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Entity::class)] +#[CoversMethod(Entity::class, 'add')] +#[CoversMethod(Entity::class, 'get')] +#[CoversMethod(Entity::class, 'delete')] +#[CoversMethod(Entity::class, 'rights')] +#[CoversMethod(Entity::class, 'update')] +class EntityTest extends TestCase +{ + protected ServiceBuilder $sb; + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test Entity::add')] + public function testAdd(): void + { + $entity = (string)time(); + $this->assertTrue( + $this->sb->getEntityScope()->entity()->add( + $entity, + 'test entity', + [] + )->isSuccess() + ); + $this->assertTrue($this->sb->getEntityScope()->entity()->delete($entity)->isSuccess()); + } + + public function testUpdate(): void + { + $entity = (string)time(); + $this->assertTrue( + $this->sb->getEntityScope()->entity()->add( + $entity, + 'test entity', + [] + )->isSuccess() + ); + + $newName = Uuid::v7()->toRfc4122(); + + $this->assertTrue($this->sb->getEntityScope()->entity()->update($entity, $newName)->isSuccess()); + $this->assertContains( + $newName, + array_column($this->sb->getEntityScope()->entity()->get()->getEntities(), 'NAME') + ); + + $this->assertTrue($this->sb->getEntityScope()->entity()->delete($entity)->isSuccess()); + } + + public function testGet(): void + { + $entity = (string)time(); + $this->assertTrue( + $this->sb->getEntityScope()->entity()->add( + $entity, + 'test entity', + [] + )->isSuccess() + ); + $entities = $this->sb->getEntityScope()->entity()->get()->getEntities(); + $this->assertContains($entity, array_column($entities, 'ENTITY')); + + + $this->assertTrue($this->sb->getEntityScope()->entity()->delete($entity)->isSuccess()); + } + + public function testRights(): void + { + $entity = (string)time(); + $this->assertTrue( + $this->sb->getEntityScope()->entity()->add( + $entity, + 'test entity', + [] + )->isSuccess() + ); + $this->assertEquals('X', current($this->sb->getEntityScope()->entity()->rights($entity)->getRights())); + $this->assertTrue($this->sb->getEntityScope()->entity()->delete($entity)->isSuccess()); + } + + public function testDelete(): void + { + $entity = (string)time(); + $this->assertTrue( + $this->sb->getEntityScope()->entity()->add( + $entity, + 'test entity', + [] + )->isSuccess() + ); + $this->assertTrue($this->sb->getEntityScope()->entity()->delete($entity)->isSuccess()); + + $entities = $this->sb->getEntityScope()->entity()->get()->getEntities(); + $this->assertNotContains($entity, array_column($entities, 'ENTITY')); + } + + protected function setUp(): void + { + $this->sb = Fabric::getServiceBuilder(true); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Entity/Item/Service/BatchTest.php b/tests/Integration/Services/Entity/Item/Service/BatchTest.php new file mode 100644 index 00000000..384ee611 --- /dev/null +++ b/tests/Integration/Services/Entity/Item/Service/BatchTest.php @@ -0,0 +1,239 @@ + + * + * 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 Bitrix24\SDK\Tests\Integration\Services\Entity\Item\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Entity\Item\Service\Batch; +use Bitrix24\SDK\Services\Entity\Item\Service\Item; +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Batch::class)] +#[CoversMethod(Batch::class, 'add')] +#[CoversMethod(Batch::class, 'delete')] +#[CoversMethod(Batch::class, 'get')] +#[CoversMethod(Batch::class, 'update')] +class BatchTest extends TestCase +{ + private ServiceBuilder $sb; + /** + * @var array + */ + private array $entities; + + protected function setUp(): void + { + $this->sb = Fabric::getServiceBuilder(true); + } + + protected function tearDown(): void + { + foreach ($this->entities as $entity) { + $this->sb->getEntityScope()->entity()->delete($entity); + } + } + + /** + * @throws TransportException + * @throws BaseException + */ + public function testGet(): void + { + $elementsCount = 160; + $entity = (string)time(); + + $elements = []; + for ($i = 0; $i < $elementsCount; $i++) { + $elements[] = [ + 'NAME' => 'name ' . Uuid::v7()->toRfc4122(), + ]; + } + + //create entity + $this->assertTrue( + $this->sb->getEntityScope()->entity()->add( + $entity, + 'test entity', + [] + )->isSuccess() + ); + $this->entities[] = $entity; + + //add items in batch mode + $addedItemsIds = []; + foreach ($this->sb->getEntityScope()->item()->batch->add($entity, $elements) as $key => $result) { + $addedItemsIds[] = $result->getId(); + } + $this->assertCount($elementsCount, $addedItemsIds); + + // read elements in batch mode + $resultElements = []; + foreach ($this->sb->getEntityScope()->item()->batch->get($entity, [], []) as $key => $item) { + $resultElements[] = $item; + } + + for ($i = 0; $i < $elementsCount; $i++) { + $this->assertArrayHasKey($i, $resultElements); + $this->assertEquals($addedItemsIds[$i], $resultElements[$i]->ID); + } + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testAdd(): void + { + $elementsCount = 160; + $entity = (string)time(); + + $elements = []; + for ($i = 0; $i < $elementsCount; $i++) { + $elements[] = [ + 'NAME' => 'name ' . Uuid::v7()->toRfc4122(), + ]; + } + + //create entity + $this->assertTrue( + $this->sb->getEntityScope()->entity()->add( + $entity, + 'test entity', + [] + )->isSuccess() + ); + $this->entities[] = $entity; + + //add items in batch mode + $addedItemsIds = []; + foreach ($this->sb->getEntityScope()->item()->batch->add($entity, $elements) as $result) { + $addedItemsIds[] = $result->getId(); + } + $this->assertCount($elementsCount, $addedItemsIds); + + // delete elements + foreach ($this->sb->getEntityScope()->item()->batch->delete($entity, $addedItemsIds) as $result) { + $this->assertTrue($result->isSuccess()); + } + } + + public function testDelete(): void + { + $elementsCount = 160; + $entity = (string)time(); + + $elements = []; + for ($i = 0; $i < $elementsCount; $i++) { + $elements[] = [ + 'NAME' => 'name ' . Uuid::v7()->toRfc4122(), + ]; + } + + //create entity + $this->assertTrue( + $this->sb->getEntityScope()->entity()->add( + $entity, + 'test entity', + [] + )->isSuccess() + ); + $this->entities[] = $entity; + + //add items in batch mode + $addedItemsIds = []; + foreach ($this->sb->getEntityScope()->item()->batch->add($entity, $elements) as $result) { + $addedItemsIds[] = $result->getId(); + } + $this->assertCount($elementsCount, $addedItemsIds); + + // delete elements + foreach ($this->sb->getEntityScope()->item()->batch->delete($entity, $addedItemsIds) as $result) { + $this->assertTrue($result->isSuccess()); + } + $this->assertEquals([], $this->sb->getEntityScope()->item()->get($entity, [], ['ID' => $addedItemsIds])->getItems()); + } + + public function testUpdate(): void + { + $elementsCount = 160; + $entity = (string)time(); + + $elements = []; + for ($i = 0; $i < $elementsCount; $i++) { + $elements[] = [ + 'NAME' => 'name ' . Uuid::v7()->toRfc4122(), + ]; + } + + //create entity + $this->assertTrue( + $this->sb->getEntityScope()->entity()->add( + $entity, + 'test entity', + [] + )->isSuccess() + ); + $this->entities[] = $entity; + + //add items in batch mode + $addedItemsIds = []; + foreach ($this->sb->getEntityScope()->item()->batch->add($entity, $elements) as $result) { + $addedItemsIds[] = $result->getId(); + } + $this->assertCount($elementsCount, $addedItemsIds); + + // read elements in batch mode + $resultElements = []; + foreach ($this->sb->getEntityScope()->item()->batch->get($entity, [], []) as $key => $item) { + $resultElements[] = $item; + } + + // prepare data for update + $modifiedElements = []; + foreach ($resultElements as $key => $item) { + $modifiedElements[] = [ + 'id' => $item->ID, + 'NAME' => 'updated name ' . Uuid::v7()->toRfc4122(), + ]; + } + + // batch update elements + foreach ($this->sb->getEntityScope()->item()->batch->update($entity, $modifiedElements) as $result) { + $this->assertTrue($result->isSuccess()); + } + + // read elements in batch mode + $updatedElements = []; + foreach ($this->sb->getEntityScope()->item()->batch->get($entity, [], []) as $key => $item) { + $updatedElements[] = $item; + } + + for ($i = 0; $i < $elementsCount; $i++) { + $this->assertEquals( + $modifiedElements[$i]['NAME'], + $updatedElements[$i]->NAME, + ); + } + + // delete elements + foreach ($this->sb->getEntityScope()->item()->batch->delete($entity, $addedItemsIds) as $result) { + $this->assertTrue($result->isSuccess()); + } + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Entity/Item/Service/ItemTest.php b/tests/Integration/Services/Entity/Item/Service/ItemTest.php new file mode 100644 index 00000000..81ab125a --- /dev/null +++ b/tests/Integration/Services/Entity/Item/Service/ItemTest.php @@ -0,0 +1,140 @@ + + * + * 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 Bitrix24\SDK\Tests\Integration\Services\Entity\Item\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Entity\Item\Service\Item; +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Item::class)] +#[CoversMethod(Item::class, 'add')] +#[CoversMethod(Item::class, 'get')] +#[CoversMethod(Item::class, 'delete')] +#[CoversMethod(Item::class, 'update')] +class ItemTest extends TestCase +{ + private ServiceBuilder $sb; + private array $entities; + + protected function setUp(): void + { + $this->sb = Fabric::getServiceBuilder(true); + } + + protected function tearDown(): void + { + foreach ($this->entities as $entity) { + $this->sb->getEntityScope()->entity()->delete($entity); + } + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testAdd(): void + { + $entity = (string)time(); + $this->assertTrue( + $this->sb->getEntityScope()->entity()->add( + $entity, + 'test entity', + [] + )->isSuccess() + ); + $this->entities[] = $entity; + + + $name = Uuid::v7()->toRfc4122(); + $itemId = $this->sb->getEntityScope()->item()->add($entity, $name, [])->getId(); + $items = $this->sb->getEntityScope()->item()->get($entity, [], ['ID' => $itemId])->getItems(); + $this->assertEquals($itemId, current(array_column($items, 'ID'))); + $this->assertEquals($name, current(array_column($items, 'NAME'))); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGet(): void + { + $entity = (string)time(); + $this->assertTrue( + $this->sb->getEntityScope()->entity()->add( + $entity, + 'test entity', + [] + )->isSuccess() + ); + $this->entities[] = $entity; + + $name = Uuid::v7()->toRfc4122(); + $itemId = $this->sb->getEntityScope()->item()->add($entity, $name, [])->getId(); + + $items = $this->sb->getEntityScope()->item()->get($entity, [], ['ID' => $itemId])->getItems(); + $this->assertEquals($itemId, current(array_column($items, 'ID'))); + } + + public function testDelete(): void + { + $entity = (string)time(); + $this->assertTrue( + $this->sb->getEntityScope()->entity()->add( + $entity, + 'test entity', + [] + )->isSuccess() + ); + $this->entities[] = $entity; + + $name = Uuid::v7()->toRfc4122(); + $itemId = $this->sb->getEntityScope()->item()->add($entity, $name, [])->getId(); + + $this->assertTrue($this->sb->getEntityScope()->item()->delete($entity, $itemId)->isSuccess()); + $this->assertEquals([], $this->sb->getEntityScope()->item()->get($entity, [], ['ID' => $itemId])->getItems()); + } + + public function testUpdate(): void + { + $entity = (string)time(); + $this->assertTrue( + $this->sb->getEntityScope()->entity()->add( + $entity, + 'test entity', + [] + )->isSuccess() + ); + $this->entities[] = $entity; + + $name = Uuid::v7()->toRfc4122(); + $itemId = $this->sb->getEntityScope()->item()->add($entity, $name, [])->getId(); + + $items = $this->sb->getEntityScope()->item()->get($entity, [], ['ID' => $itemId])->getItems(); + $this->assertEquals($itemId, current(array_column($items, 'ID'))); + + $newName = Uuid::v7()->toRfc4122(); + $this->assertTrue($this->sb->getEntityScope()->item()->update( + $entity,$itemId, ['NAME'=>$newName] + )->isSuccess()); + + $items = $this->sb->getEntityScope()->item()->get($entity, [], ['ID' => $itemId])->getItems(); + $this->assertEquals($newName, current(array_column($items, 'NAME'))); + } +} \ No newline at end of file diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php index 8b28d0c8..a16e24b8 100644 --- a/tests/Unit/Stubs/NullBatch.php +++ b/tests/Unit/Stubs/NullBatch.php @@ -27,8 +27,14 @@ class NullBatch implements BatchOperationsInterface /** * @inheritDoc */ - public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null, ?array $additionalParameters = null): Generator - { + public function getTraversableList( + string $apiMethod, + array $order, + array $filter, + array $select, + ?int $limit = null, + ?array $additionalParameters = null + ): Generator { yield []; } @@ -50,15 +56,22 @@ public function getTraversableListWithCount( */ public function addEntityItems(string $apiMethod, array $entityItems): Generator { - yield new ResponseData([],new Time(0,0,0,0,0, new CarbonImmutable(),new CarbonImmutable(),0,),new Pagination()); + yield new ResponseData([], + new Time(0, 0, 0, 0, 0, new CarbonImmutable(), new CarbonImmutable(), 0,), + new Pagination()); } /** * @inheritDoc */ - public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator - { - yield new ResponseData([],new Time(0,0,0,0,0, new CarbonImmutable(),new CarbonImmutable(),0,),new Pagination()); + public function deleteEntityItems( + string $apiMethod, + array $entityItemId, + ?array $additionalParameters = null + ): Generator { + yield new ResponseData([], + new Time(0, 0, 0, 0, 0, new CarbonImmutable(), new CarbonImmutable(), 0,), + new Pagination()); } /** @@ -66,6 +79,8 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener */ public function updateEntityItems(string $apiMethod, array $entityItems): Generator { - yield new ResponseData([],new Time(0,0,0,0,0, new CarbonImmutable(),new CarbonImmutable(),0,),new Pagination()); + yield new ResponseData([], + new Time(0, 0, 0, 0, 0, new CarbonImmutable(), new CarbonImmutable(), 0,), + new Pagination()); } } \ No newline at end of file