From 17392393b6b1e50d158e87f6c2630ce2a03ea20a Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 21 Jan 2025 01:48:44 +0600 Subject: [PATCH 1/9] Add support for entity service in SDK Introduced the `Entity` service to handle Bitrix24 custom entities. This includes CRUD operations, rights management, and integration tests for validation. Updated supporting classes to accommodate the new service functionality. Signed-off-by: mesilov --- src/Core/Result/AddedEntityResult.php | 27 +++ src/Services/AbstractService.php | 10 + .../Entity/Entity/Result/EntitiesResult.php | 34 ++++ .../Entity/Entity/Result/EntityItemResult.php | 31 ++++ .../Entity/Result/EntityRightsResult.php | 25 +++ src/Services/Entity/Entity/Service/Batch.php | 31 ++++ src/Services/Entity/Entity/Service/Entity.php | 172 ++++++++++++++++++ src/Services/Entity/EntityServiceBuilder.php | 36 ++++ src/Services/ServiceBuilder.php | 91 +++++++-- tests/Integration/Fabric.php | 39 ++-- .../Entity/Entity/Service/EntityTest.php | 128 +++++++++++++ 11 files changed, 594 insertions(+), 30 deletions(-) create mode 100644 src/Core/Result/AddedEntityResult.php create mode 100644 src/Services/Entity/Entity/Result/EntitiesResult.php create mode 100644 src/Services/Entity/Entity/Result/EntityItemResult.php create mode 100644 src/Services/Entity/Entity/Result/EntityRightsResult.php create mode 100644 src/Services/Entity/Entity/Service/Batch.php create mode 100644 src/Services/Entity/Entity/Service/Entity.php create mode 100644 src/Services/Entity/EntityServiceBuilder.php create mode 100644 tests/Integration/Services/Entity/Entity/Service/EntityTest.php diff --git a/src/Core/Result/AddedEntityResult.php b/src/Core/Result/AddedEntityResult.php new file mode 100644 index 00000000..40a991fd --- /dev/null +++ b/src/Core/Result/AddedEntityResult.php @@ -0,0 +1,27 @@ + + * + * 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\Core\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; + +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/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/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..f84772ea --- /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\AddedEntityResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +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.get', + '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..b6f716a3 --- /dev/null +++ b/src/Services/Entity/EntityServiceBuilder.php @@ -0,0 +1,36 @@ + + * + * 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__]; + } +} \ 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/Fabric.php b/tests/Integration/Fabric.php index 238e4b9b..a815a74a 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -94,24 +94,29 @@ 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; } 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 From f42e0e81fa54cf5522b32643b789841fe8ea1578 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 23 Jan 2025 01:04:34 +0600 Subject: [PATCH 2/9] Relocate AddedEntityResult to the correct namespace Moved AddedEntityResult from Core\Result to Services\Entity\Entity\Result for better organization and alignment with the modular structure. Updated all relevant references to reflect the new location. Signed-off-by: mesilov --- .../Entity/Entity}/Result/AddedEntityResult.php | 3 ++- src/Services/Entity/Entity/Service/Entity.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) rename src/{Core => Services/Entity/Entity}/Result/AddedEntityResult.php (85%) diff --git a/src/Core/Result/AddedEntityResult.php b/src/Services/Entity/Entity/Result/AddedEntityResult.php similarity index 85% rename from src/Core/Result/AddedEntityResult.php rename to src/Services/Entity/Entity/Result/AddedEntityResult.php index 40a991fd..352a989a 100644 --- a/src/Core/Result/AddedEntityResult.php +++ b/src/Services/Entity/Entity/Result/AddedEntityResult.php @@ -11,9 +11,10 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Core\Result; +namespace Bitrix24\SDK\Services\Entity\Entity\Result; use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; class AddedEntityResult extends AbstractResult { diff --git a/src/Services/Entity/Entity/Service/Entity.php b/src/Services/Entity/Entity/Service/Entity.php index f84772ea..639f7afe 100644 --- a/src/Services/Entity/Entity/Service/Entity.php +++ b/src/Services/Entity/Entity/Service/Entity.php @@ -20,10 +20,10 @@ use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Bitrix24\SDK\Core\Exceptions\TransportException; -use Bitrix24\SDK\Core\Result\AddedEntityResult; 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; From eb2e273ba19653d0360234d068c97d680ee37ab0 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 23 Jan 2025 02:18:42 +0600 Subject: [PATCH 3/9] Add Item service and integration test Signed-off-by: mesilov --- .../CRM/Common/Result/AbstractCrmItem.php | 2 + src/Services/Entity/EntityServiceBuilder.php | 13 ++ .../Entity/Item/Result/ItemItemResult.php | 40 +++++ .../Entity/Item/Result/ItemsResult.php | 34 ++++ src/Services/Entity/Item/Service/Batch.php | 31 ++++ src/Services/Entity/Item/Service/Item.php | 155 ++++++++++++++++++ .../Services/Entity/Item/Service/ItemTest.php | 140 ++++++++++++++++ 7 files changed, 415 insertions(+) create mode 100644 src/Services/Entity/Item/Result/ItemItemResult.php create mode 100644 src/Services/Entity/Item/Result/ItemsResult.php create mode 100644 src/Services/Entity/Item/Service/Batch.php create mode 100644 src/Services/Entity/Item/Service/Item.php create mode 100644 tests/Integration/Services/Entity/Item/Service/ItemTest.php 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/EntityServiceBuilder.php b/src/Services/Entity/EntityServiceBuilder.php index b6f716a3..2bb6d5d3 100644 --- a/src/Services/Entity/EntityServiceBuilder.php +++ b/src/Services/Entity/EntityServiceBuilder.php @@ -33,4 +33,17 @@ public function entity(): Entity\Entity\Service\Entity 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..cf926baa --- /dev/null +++ b/src/Services/Entity/Item/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\Item\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/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/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 From 5237d01477df5e3ec93fde280f0531ab481a94bc Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 29 Jan 2025 02:30:44 +0600 Subject: [PATCH 4/9] Add batch operations for entity items with tests Introduce batch methods for adding and deleting entity items, supporting additional parameters for flexibility. Updated related interfaces, services, and stubs to align with the new functionality. Included integration tests to validate batch operations. Signed-off-by: mesilov --- src/Core/Batch.php | 18 +++- .../Contracts/BatchOperationsInterface.php | 6 +- src/Services/Entity/Item/Service/Batch.php | 45 ++++++++- tests/Integration/Fabric.php | 14 +-- .../Entity/Item/Service/BatchTest.php | 91 +++++++++++++++++++ tests/Unit/Stubs/NullBatch.php | 32 +++++-- 6 files changed, 186 insertions(+), 20 deletions(-) create mode 100644 tests/Integration/Services/Entity/Item/Service/BatchTest.php diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 39c23814..b48601ea 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -108,18 +108,24 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator /** * Delete entity items with batch call * - * @param array $entityItemId * + * @param string $apiMethod + * @param array $entityItemId + * @param array|null $additionalParameters * @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 +143,11 @@ 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) { 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/Entity/Item/Service/Batch.php b/src/Services/Entity/Item/Service/Batch.php index cf926baa..49b1495b 100644 --- a/src/Services/Entity/Item/Service/Batch.php +++ b/src/Services/Entity/Item/Service/Batch.php @@ -13,11 +13,15 @@ namespace Bitrix24\SDK\Services\Entity\Item\Service; +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AddedItemBatchResult; +use Bitrix24\SDK\Core\Result\AddedItemResult; use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; use Bitrix24\SDK\Core\Result\UpdatedItemBatchResult; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealItemResult; use Generator; use Psr\Log\LoggerInterface; @@ -25,7 +29,46 @@ { public function __construct( protected BatchOperationsInterface $batch, - protected LoggerInterface $log) + protected LoggerInterface $log + ) { + } + + #[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); + } } } \ No newline at end of file diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index a815a74a..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 { @@ -111,7 +111,6 @@ public static function getCore(bool $isNeedApplicationCredentials = false): Core ApplicationProfile::initFromArray($_ENV), $_ENV['BITRIX24_PHP_SDK_APPLICATION_DOMAIN_URL'] ); - return (new CoreBuilder()) ->withLogger(self::getLogger()) ->withEventDispatcher($eventDispatcher) @@ -135,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/Item/Service/BatchTest.php b/tests/Integration/Services/Entity/Item/Service/BatchTest.php new file mode 100644 index 00000000..839d4614 --- /dev/null +++ b/tests/Integration/Services/Entity/Item/Service/BatchTest.php @@ -0,0 +1,91 @@ + + * + * 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(Item::class, 'delete')] + +//#[CoversMethod(Item::class, 'get')] +//#[CoversMethod(Item::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 BaseException + * @throws TransportException + */ + public function testAdd(): void + { + $elementsCount = 110; + $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()); + } + } +} \ No newline at end of file diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php index 8b28d0c8..159782fb 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,25 @@ 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()); } /** + * @param string $apiMethod + * @param array $entityItemId + * @param array|null $additionalParameters * @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 +82,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 From f716641dec6c157cf764d01565be8d46aa494c60 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 29 Jan 2025 09:58:41 +0600 Subject: [PATCH 5/9] Remove redundant PHPDoc param annotations in Batch classes Cleaned up unnecessary PHPDoc `@param` annotations in `deleteEntityItems` methods. The parameters are already clear from the method signature, ensuring consistency and improving readability. Signed-off-by: mesilov --- src/Core/Batch.php | 4 +--- tests/Unit/Stubs/NullBatch.php | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index b48601ea..7f9050e9 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -109,9 +109,6 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator * Delete entity items with batch call * * - * @param string $apiMethod - * @param array $entityItemId - * @param array|null $additionalParameters * @return Generator|ResponseData[] * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ @@ -147,6 +144,7 @@ public function deleteEntityItems( if ($apiMethod === 'entity.item.delete') { $parameters = array_merge($parameters, $additionalParameters); } + $this->registerCommand($apiMethod, $parameters); } diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php index 159782fb..a16e24b8 100644 --- a/tests/Unit/Stubs/NullBatch.php +++ b/tests/Unit/Stubs/NullBatch.php @@ -62,9 +62,6 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator } /** - * @param string $apiMethod - * @param array $entityItemId - * @param array|null $additionalParameters * @inheritDoc */ public function deleteEntityItems( From 9dda2025c7a33f0a8f4067a6caabadd260dbafc0 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 31 Jan 2025 02:23:56 +0600 Subject: [PATCH 6/9] Fix errors in core batch for method entity.item.get Signed-off-by: mesilov --- src/Core/Batch.php | 31 +++++++++++++++------- src/Services/Entity/Item/Service/Batch.php | 22 +++++++++++++++ 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 7f9050e9..5fdb6676 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -405,7 +405,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', [ @@ -461,8 +464,15 @@ public function getTraversableList( // getLastElementId in filtered result // todo wait new api version if ($apiMethod !== 'user.get') { + $defaultOrderKey = 'order'; + if ($apiMethod === 'entity.item.get') { + $orderKey = 'SORT'; + } else { + $orderKey = $defaultOrderKey; + } + $params = [ - 'order' => $this->getReverseOrder($order), + $orderKey => $this->getReverseOrder($order), 'filter' => $filter, 'select' => $select, 'start' => 0, @@ -481,26 +491,29 @@ public function getTraversableList( if ($additionalParameters !== null) { $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]; } else { $lastElementId = (int)$lastResultPage->getResponseData()->getResult()[0][$keyId]; } + $this->logger->debug('getTraversableList.lastElementsId', [ + 'lastElementIdInFirstPage' => $lastElementIdInFirstPage, + 'lastElementIdInLastPage' => $lastElementId, + ]); - // reverse order if you need + + // 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/Services/Entity/Item/Service/Batch.php b/src/Services/Entity/Item/Service/Batch.php index 49b1495b..35d5d89f 100644 --- a/src/Services/Entity/Item/Service/Batch.php +++ b/src/Services/Entity/Item/Service/Batch.php @@ -22,6 +22,7 @@ use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; use Bitrix24\SDK\Core\Result\UpdatedItemBatchResult; use Bitrix24\SDK\Services\CRM\Deal\Result\DealItemResult; +use Bitrix24\SDK\Services\Entity\Item\Result\ItemItemResult; use Generator; use Psr\Log\LoggerInterface; @@ -33,6 +34,27 @@ public function __construct( ) { } + #[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', From 6643e8759efd578dea087e242617cfe1f45c72b3 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 1 Feb 2025 18:54:32 +0600 Subject: [PATCH 7/9] Add batch support for update and retrieval operations. This commit introduces batch processing for 'update' and 'get' actions in the Entity/Item service, enabling efficient bulk operations. Tests for these operations have been added to ensure reliability. Additionally, minor adjustments and cleanup were performed in related batch handling logic. Signed-off-by: mesilov --- src/Core/Batch.php | 34 ++-- src/Services/Entity/Item/Service/Batch.php | 30 +++- tests/Integration/Core/BatchTest.php | 53 +++--- .../Entity/Item/Service/BatchTest.php | 158 +++++++++++++++++- 4 files changed, 225 insertions(+), 50 deletions(-) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 5fdb6676..1dc7d46f 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -212,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); @@ -465,11 +469,7 @@ public function getTraversableList( // todo wait new api version if ($apiMethod !== 'user.get') { $defaultOrderKey = 'order'; - if ($apiMethod === 'entity.item.get') { - $orderKey = 'SORT'; - } else { - $orderKey = $defaultOrderKey; - } + $orderKey = $apiMethod === 'entity.item.get' ? 'SORT' : $defaultOrderKey; $params = [ $orderKey => $this->getReverseOrder($order), @@ -491,6 +491,7 @@ public function getTraversableList( if ($additionalParameters !== null) { $params = array_merge($params, $additionalParameters); } + $this->logger->debug('getTraversableList.getLastPage', [ 'apiMethod' => $apiMethod, 'params' => $params, @@ -501,6 +502,7 @@ public function getTraversableList( } else { $lastElementId = (int)$lastResultPage->getResponseData()->getResult()[0][$keyId]; } + $this->logger->debug('getTraversableList.lastElementsId', [ 'lastElementIdInFirstPage' => $lastElementIdInFirstPage, 'lastElementIdInLastPage' => $lastElementId, diff --git a/src/Services/Entity/Item/Service/Batch.php b/src/Services/Entity/Item/Service/Batch.php index 35d5d89f..132f0948 100644 --- a/src/Services/Entity/Item/Service/Batch.php +++ b/src/Services/Entity/Item/Service/Batch.php @@ -14,18 +14,16 @@ namespace Bitrix24\SDK\Services\Entity\Item\Service; use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; -use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; -use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Credentials\Scope; use Bitrix24\SDK\Core\Result\AddedItemBatchResult; -use Bitrix24\SDK\Core\Result\AddedItemResult; use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; -use Bitrix24\SDK\Core\Result\UpdatedItemBatchResult; -use Bitrix24\SDK\Services\CRM\Deal\Result\DealItemResult; use Bitrix24\SDK\Services\Entity\Item\Result\ItemItemResult; use Generator; use Psr\Log\LoggerInterface; +#[ApiBatchServiceMetadata(new Scope(['entity']))] readonly class Batch { public function __construct( @@ -93,4 +91,26 @@ public function delete(string $entity, array $itemIds): Generator 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/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/Services/Entity/Item/Service/BatchTest.php b/tests/Integration/Services/Entity/Item/Service/BatchTest.php index 839d4614..384ee611 100644 --- a/tests/Integration/Services/Entity/Item/Service/BatchTest.php +++ b/tests/Integration/Services/Entity/Item/Service/BatchTest.php @@ -26,10 +26,9 @@ #[CoversClass(Batch::class)] #[CoversMethod(Batch::class, 'add')] -#[CoversMethod(Item::class, 'delete')] - -//#[CoversMethod(Item::class, 'get')] -//#[CoversMethod(Item::class, 'update')] +#[CoversMethod(Batch::class, 'delete')] +#[CoversMethod(Batch::class, 'get')] +#[CoversMethod(Batch::class, 'update')] class BatchTest extends TestCase { private ServiceBuilder $sb; @@ -50,13 +49,129 @@ protected function tearDown(): void } } + /** + * @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 = 110; + $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 = []; @@ -83,6 +198,39 @@ public function testAdd(): void } $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()); From 995085e125d024b9dcc9b8f599808abbfb60eba8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 1 Feb 2025 19:10:36 +0600 Subject: [PATCH 8/9] Update Entity API metadata for access permissions handling Replaced the API endpoint metadata key from `entity.get` to `entity.rights` in the `Entity` service. Updated the changelog to reflect enhancements, including new methods for managing entity access permissions and batch operations. Signed-off-by: mesilov --- CHANGELOG.md | 18 +++++++++++++++++- src/Services/Entity/Entity/Service/Entity.php | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) 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/src/Services/Entity/Entity/Service/Entity.php b/src/Services/Entity/Entity/Service/Entity.php index 639f7afe..d2501753 100644 --- a/src/Services/Entity/Entity/Service/Entity.php +++ b/src/Services/Entity/Entity/Service/Entity.php @@ -153,7 +153,7 @@ public function get(?string $entity = null): EntitiesResult * @throws BaseException */ #[ApiEndpointMetadata( - 'entity.get', + 'entity.rights', 'https://apidocs.bitrix24.com/api-reference/entity/entities/entity-rights.html', 'Get or Change Access Permissions' )] From 3cb355ef97b137213e23eeeddc9be42bbf7bc0d7 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 1 Feb 2025 19:16:05 +0600 Subject: [PATCH 9/9] Add integration tests and update entity documentation Added a new integration test suite for 'integration_tests_scope_entity' and updated the documentation to include methods for 'entity' and 'entity.item' services. These changes enhance test coverage and improve the SDK's reference material. Signed-off-by: mesilov --- Makefile | 4 +++- docs/EN/Services/bitrix24-php-sdk-methods.md | 21 ++++++++++++++------ phpunit.xml.dist | 3 +++ 3 files changed, 21 insertions(+), 7 deletions(-) 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:
  • `Bitrix24\SDK\Services\Entity\Item\Service\Batch::add`
    Return type: `Generator`
| +|`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:
  • `Bitrix24\SDK\Services\Entity\Item\Service\Batch::get`
    Return type: `Generator`
| +|`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:
  • `Bitrix24\SDK\Services\Entity\Item\Service\Batch::delete`
    Return type: `Generator`
| +|`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:
  • `Bitrix24\SDK\Services\Entity\Item\Service\Batch::update`
    Return type: `Generator`
| |`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:
  • `Bitrix24\SDK\Services\User\Service\Batch::add`
    Return type: `Generator`
| +|`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:
  • `Bitrix24\SDK\Services\User\Service\Batch::get`
    Return type: `Generator`
| +|`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/ +