diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php
index 6e5393c3..4807506f 100644
--- a/.php-cs-fixer.php
+++ b/.php-cs-fixer.php
@@ -29,6 +29,7 @@
->in(__DIR__ . '/src/Services/SonetGroup/')
->in(__DIR__ . '/src/Services/IMOpenLines/')
->in(__DIR__ . '/src/Services/Landing/')
+ ->in(__DIR__ . '/src/Services/MailService/')
->name('*.php')
->exclude(['vendor', 'storage', 'docker', 'docs']) // Exclude directories
->ignoreDotFiles(true)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f4bc3b52..3ced0bc4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,16 @@
### Added
+- Added service `Services\MailService` with support for `mailservice.*` methods,
+ see [mailservice.* methods](https://apidocs.bitrix24.com/api-reference/mailservice/index.html) ([#495](https://github.com/bitrix24/b24phpsdk/issues/495)):
+ - `add` creates a new mail service (IMAP integration), with batch calls support
+ - `update` updates an existing mail service, with batch calls support
+ - `get` gets information about a mail service by its identifier
+ - `list` gets the list of active mail services, with batch calls support
+ - `delete` deletes a mail service, with batch calls support
+ - `fields` returns localized field labels of a mail service
+ - `count` counts active mail services
+
- Added service `Services\Landing\Site\Service\Site` with support methods,
see [landing.site.* methods](https://github.com/bitrix24/b24phpsdk/issues/267):
- `add` adds a site
diff --git a/Makefile b/Makefile
index c2fc4a9a..8bc3f4f6 100644
--- a/Makefile
+++ b/Makefile
@@ -69,7 +69,7 @@ help:
@echo "test-integration-landing-role - run Landing Role integration tests"
@echo "test-integration-landing-repowidget - run Landing RepoWidget integration tests"
@echo "test-integration-scope-landing-template - run Landing Template integration tests"
-
+ @echo "test-integration-mailservice - run MailService integration tests"
.PHONY: docker-init
docker-init:
@@ -492,6 +492,10 @@ test-integration-landing-role:
test-integration-landing-repowidget:
docker compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_landing_repowidget
+.PHONY: test-integration-mailservice
+test-integration-mailservice:
+ docker compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_mailservice
+
# work dev environment
.PHONY: php-dev-server-up
php-dev-server-up:
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
index e6ce503a..055dd738 100644
--- a/phpstan.neon.dist
+++ b/phpstan.neon.dist
@@ -37,6 +37,7 @@ parameters:
- tests/Integration/Services/CRM/Documentgenerator/Document
- tests/Integration/Services/CRM/Documentgenerator/Template
- tests/Integration/Services/Landing
+ - tests/Integration/Services/MailService
excludePaths:
- tests/Integration/Services/CRM/Requisites/Service/RequisiteUserfieldUseCaseTest.php
- tests/Integration/Services/CRM/Status
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index d0187ae5..eda20536 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -262,6 +262,9 @@
./tests/Integration/Services/Landing/RepoWidget/
+
+ ./tests/Integration/Services/MailService/
+
diff --git a/rector.php b/rector.php
index fb38e858..fbbae7cb 100644
--- a/rector.php
+++ b/rector.php
@@ -78,6 +78,8 @@
__DIR__ . '/tests/Integration/Services/CRM/Documentgenerator/Template',
__DIR__ . '/src/Services/Landing',
__DIR__ . '/tests/Integration/Services/Landing',
+ __DIR__ . '/src/Services/MailService',
+ __DIR__ . '/tests/Integration/Services/MailService',
__DIR__ . '/tests/Unit/',
])
->withCache(cacheDirectory: __DIR__ . '/var/.cache/rector')
diff --git a/src/Services/MailService/Batch.php b/src/Services/MailService/Batch.php
new file mode 100644
index 00000000..fc87459e
--- /dev/null
+++ b/src/Services/MailService/Batch.php
@@ -0,0 +1,108 @@
+
+ *
+ * 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\MailService;
+
+use Bitrix24\SDK\Core\Contracts\CoreInterface;
+use Bitrix24\SDK\Core\Exceptions\BaseException;
+use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException;
+use Bitrix24\SDK\Core\Response\DTO\ResponseData;
+use Generator;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Custom Batch for MailService scope.
+ *
+ * Overrides updateEntityItems to pass ID as a top-level key (flat structure),
+ * matching the mailservice.update parameter format which does not use nested 'fields'.
+ *
+ * @see https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-update.html
+ */
+class Batch extends \Bitrix24\SDK\Core\Batch
+{
+ public function __construct(CoreInterface $core, LoggerInterface $logger)
+ {
+ parent::__construct($core, $logger);
+ }
+
+ /**
+ * Update mail service items with batch call.
+ *
+ * Expects array structure:
+ * [
+ * $mailServiceId => ['NAME' => '...', 'ACTIVE' => 'Y', ...],
+ * ...
+ * ]
+ *
+ * @param array> $entityItems
+ *
+ * @return Generator
+ * @throws BaseException
+ */
+ #[\Override]
+ public function updateEntityItems(string $apiMethod, array $entityItems): Generator
+ {
+ $this->logger->debug(
+ 'updateEntityItems.start',
+ [
+ 'apiMethod' => $apiMethod,
+ 'entityItems' => $entityItems,
+ ]
+ );
+
+ try {
+ $this->clearCommands();
+ foreach ($entityItems as $entityItemId => $entityItem) {
+ if (!is_int($entityItemId)) {
+ throw new InvalidArgumentException(
+ sprintf(
+ 'invalid type «%s» of mail service id «%s», the id must be integer type',
+ gettype($entityItemId),
+ $entityItemId
+ )
+ );
+ }
+
+ $entityItem['ID'] = $entityItemId;
+ $cmdArguments = $entityItem;
+
+ $this->registerCommand($apiMethod, $cmdArguments);
+ }
+
+ foreach ($this->getTraversable(true) as $cnt => $updatedItemResult) {
+ yield $cnt => $updatedItemResult;
+ }
+ } catch (InvalidArgumentException $exception) {
+ $errorMessage = sprintf('batch update entity items: %s', $exception->getMessage());
+ $this->logger->error(
+ $errorMessage,
+ [
+ 'trace' => $exception->getTrace(),
+ ]
+ );
+ throw $exception;
+ } catch (\Throwable $exception) {
+ $errorMessage = sprintf('batch update entity items: %s', $exception->getMessage());
+ $this->logger->error(
+ $errorMessage,
+ [
+ 'trace' => $exception->getTrace(),
+ ]
+ );
+
+ throw new BaseException($errorMessage, $exception->getCode(), $exception);
+ }
+
+ $this->logger->debug('updateEntityItems.finish');
+ }
+}
diff --git a/src/Services/MailService/MailServiceServiceBuilder.php b/src/Services/MailService/MailServiceServiceBuilder.php
new file mode 100644
index 00000000..ab9ee969
--- /dev/null
+++ b/src/Services/MailService/MailServiceServiceBuilder.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\MailService;
+
+use Bitrix24\SDK\Attributes\ApiServiceBuilderMetadata;
+use Bitrix24\SDK\Core\Credentials\Scope;
+use Bitrix24\SDK\Services\AbstractServiceBuilder;
+use Bitrix24\SDK\Services\MailService;
+
+#[ApiServiceBuilderMetadata(new Scope(['mailservice']))]
+class MailServiceServiceBuilder extends AbstractServiceBuilder
+{
+ public function mailService(): MailService\Service\MailService
+ {
+ if (!isset($this->serviceCache[__METHOD__])) {
+ $batch = new MailService\Batch(
+ $this->core,
+ $this->log
+ );
+ $this->serviceCache[__METHOD__] = new MailService\Service\MailService(
+ new MailService\Service\Batch($batch, $this->log),
+ $this->core,
+ $this->log
+ );
+ }
+
+ return $this->serviceCache[__METHOD__];
+ }
+}
diff --git a/src/Services/MailService/Result/MailServiceItemResult.php b/src/Services/MailService/Result/MailServiceItemResult.php
new file mode 100644
index 00000000..d87de3c7
--- /dev/null
+++ b/src/Services/MailService/Result/MailServiceItemResult.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\MailService\Result;
+
+use Bitrix24\SDK\Core\Result\AbstractItem;
+
+/**
+ * Mail service item result.
+ *
+ * @property-read int $ID
+ * @property-read string $SITE_ID
+ * @property-read bool $ACTIVE
+ * @property-read int $SORT
+ * @property-read string $NAME
+ * @property-read string $SERVER
+ * @property-read int|null $PORT
+ * @property-read bool $ENCRYPTION
+ * @property-read string $LINK
+ * @property-read string|null $ICON
+ * @property-read string|null $SMTP_SERVER
+ * @property-read int|null $SMTP_PORT
+ * @property-read bool $SMTP_LOGIN_AS_IMAP
+ * @property-read bool $SMTP_PASSWORD_AS_IMAP
+ * @property-read bool|null $SMTP_ENCRYPTION
+ * @property-read bool|null $UPLOAD_OUTGOING
+ */
+class MailServiceItemResult extends AbstractItem
+{
+ public function __get($offset)
+ {
+ return match ($offset) {
+ 'ID', 'SORT', 'PORT', 'SMTP_PORT' => isset($this->data[$offset]) ? (int)$this->data[$offset] : null,
+ 'ACTIVE', 'ENCRYPTION', 'SMTP_LOGIN_AS_IMAP', 'SMTP_PASSWORD_AS_IMAP' => $this->data[$offset] === 'Y',
+ 'SMTP_ENCRYPTION', 'UPLOAD_OUTGOING' => isset($this->data[$offset]) ? $this->data[$offset] === 'Y' : null,
+ default => $this->data[$offset] ?? null,
+ };
+ }
+}
diff --git a/src/Services/MailService/Result/MailServiceResult.php b/src/Services/MailService/Result/MailServiceResult.php
new file mode 100644
index 00000000..361e5942
--- /dev/null
+++ b/src/Services/MailService/Result/MailServiceResult.php
@@ -0,0 +1,32 @@
+
+ *
+ * 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\MailService\Result;
+
+use Bitrix24\SDK\Core\Result\AbstractResult;
+
+/**
+ * Single mail service result for mailservice.get.
+ *
+ * @see https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-get.html
+ */
+class MailServiceResult extends AbstractResult
+{
+ /**
+ * Get mail service item.
+ */
+ public function mailService(): MailServiceItemResult
+ {
+ return new MailServiceItemResult($this->getCoreResponse()->getResponseData()->getResult());
+ }
+}
diff --git a/src/Services/MailService/Result/MailServicesResult.php b/src/Services/MailService/Result/MailServicesResult.php
new file mode 100644
index 00000000..8641ace0
--- /dev/null
+++ b/src/Services/MailService/Result/MailServicesResult.php
@@ -0,0 +1,41 @@
+
+ *
+ * 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\MailService\Result;
+
+use Bitrix24\SDK\Core\Exceptions\BaseException;
+use Bitrix24\SDK\Core\Result\AbstractResult;
+
+/**
+ * Mail services list result for mailservice.list.
+ *
+ * @see https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-list.html
+ */
+class MailServicesResult extends AbstractResult
+{
+ /**
+ * Get mail service items.
+ *
+ * @return MailServiceItemResult[]
+ * @throws BaseException
+ */
+ public function getMailServices(): array
+ {
+ $items = [];
+ foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) {
+ $items[] = new MailServiceItemResult($item);
+ }
+
+ return $items;
+ }
+}
diff --git a/src/Services/MailService/Service/Batch.php b/src/Services/MailService/Service/Batch.php
new file mode 100644
index 00000000..6c443298
--- /dev/null
+++ b/src/Services/MailService/Service/Batch.php
@@ -0,0 +1,136 @@
+
+ *
+ * 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\MailService\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\Exceptions\BaseException;
+use Bitrix24\SDK\Core\Result\AddedItemBatchResult;
+use Bitrix24\SDK\Core\Result\DeletedItemBatchResult;
+use Bitrix24\SDK\Core\Result\UpdatedItemBatchResult;
+use Bitrix24\SDK\Services\MailService\Result\MailServiceItemResult;
+use Generator;
+use Psr\Log\LoggerInterface;
+
+#[ApiBatchServiceMetadata(new Scope(['mailservice']))]
+class Batch
+{
+ public function __construct(protected BatchOperationsInterface $batch, protected LoggerInterface $log)
+ {
+ }
+
+ /**
+ * Batch list of mail services.
+ *
+ * @link https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-list.html
+ *
+ * @return Generator
+ * @throws BaseException
+ */
+ #[ApiBatchMethodMetadata(
+ 'mailservice.list',
+ 'https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-list.html',
+ 'Batch list of mail services'
+ )]
+ public function list(?int $limit = null): Generator
+ {
+ $this->log->debug(
+ 'batchList',
+ [
+ 'limit' => $limit,
+ ]
+ );
+ foreach ($this->batch->getTraversableList('mailservice.list', [], [], [], $limit) as $key => $value) {
+ yield $key => new MailServiceItemResult($value);
+ }
+ }
+
+ /**
+ * Batch add mail services.
+ *
+ * @link https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-add.html
+ *
+ * @param array $mailServices
+ *
+ * @return Generator
+ * @throws BaseException
+ */
+ #[ApiBatchMethodMetadata(
+ 'mailservice.add',
+ 'https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-add.html',
+ 'Batch add mail services'
+ )]
+ public function add(array $mailServices): Generator
+ {
+ foreach ($this->batch->addEntityItems('mailservice.add', $mailServices) as $key => $item) {
+ yield $key => new AddedItemBatchResult($item);
+ }
+ }
+
+ /**
+ * Batch update mail services.
+ *
+ * Array structure: [$mailServiceId => ['NAME' => '...', ...], ...]
+ *
+ * @link https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-update.html
+ *
+ * @param array> $mailServiceItems
+ *
+ * @return Generator
+ * @throws BaseException
+ */
+ #[ApiBatchMethodMetadata(
+ 'mailservice.update',
+ 'https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-update.html',
+ 'Batch update mail services'
+ )]
+ public function update(array $mailServiceItems): Generator
+ {
+ foreach ($this->batch->updateEntityItems('mailservice.update', $mailServiceItems) as $key => $item) {
+ yield $key => new UpdatedItemBatchResult($item);
+ }
+ }
+
+ /**
+ * Batch delete mail services.
+ *
+ * @link https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-delete.html
+ *
+ * @param int[] $mailServiceIds
+ *
+ * @return Generator
+ * @throws BaseException
+ */
+ #[ApiBatchMethodMetadata(
+ 'mailservice.delete',
+ 'https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-delete.html',
+ 'Batch delete mail services'
+ )]
+ public function delete(array $mailServiceIds): Generator
+ {
+ foreach ($this->batch->deleteEntityItems('mailservice.delete', $mailServiceIds) as $key => $item) {
+ yield $key => new DeletedItemBatchResult($item);
+ }
+ }
+}
diff --git a/src/Services/MailService/Service/MailService.php b/src/Services/MailService/Service/MailService.php
new file mode 100644
index 00000000..c547935c
--- /dev/null
+++ b/src/Services/MailService/Service/MailService.php
@@ -0,0 +1,206 @@
+
+ *
+ * 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\MailService\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\FieldsResult;
+use Bitrix24\SDK\Core\Result\UpdatedItemResult;
+use Bitrix24\SDK\Services\AbstractService;
+use Bitrix24\SDK\Services\MailService\Result\MailServiceResult;
+use Bitrix24\SDK\Services\MailService\Result\MailServicesResult;
+use Psr\Log\LoggerInterface;
+
+#[ApiServiceMetadata(new Scope(['mailservice']))]
+class MailService extends AbstractService
+{
+ public function __construct(public Batch $batch, CoreInterface $core, LoggerInterface $logger)
+ {
+ parent::__construct($core, $logger);
+ }
+
+ /**
+ * Add a new mail service.
+ *
+ * @link https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-add.html
+ *
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[ApiEndpointMetadata(
+ 'mailservice.add',
+ 'https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-add.html',
+ 'Creates a new mail service for the current Bitrix24'
+ )]
+ public function add(
+ string $name,
+ string $active = 'Y',
+ string $server = '',
+ int $port = 993,
+ string $encryption = 'Y',
+ string $link = '',
+ int $sort = 100
+ ): AddedItemResult {
+ $params = [
+ 'NAME' => $name,
+ 'ACTIVE' => $active,
+ 'SORT' => $sort,
+ ];
+ if ($server !== '') {
+ $params['SERVER'] = $server;
+ }
+
+ if ($port !== 993) {
+ $params['PORT'] = $port;
+ }
+
+ if ($link !== '') {
+ $params['LINK'] = $link;
+ }
+
+ $params['ENCRYPTION'] = $encryption;
+
+ return new AddedItemResult(
+ $this->core->call('mailservice.add', $params)
+ );
+ }
+
+ /**
+ * Update an existing mail service.
+ *
+ * @link https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-update.html
+ *
+ * @param array{
+ * NAME?: string,
+ * ACTIVE?: string,
+ * SERVER?: string,
+ * PORT?: int,
+ * ENCRYPTION?: string,
+ * LINK?: string,
+ * SORT?: int,
+ * } $fields
+ *
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[ApiEndpointMetadata(
+ 'mailservice.update',
+ 'https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-update.html',
+ 'Updates an existing mail service parameters'
+ )]
+ public function update(int $id, array $fields): UpdatedItemResult
+ {
+ $params = $fields;
+ $params['ID'] = $id;
+
+ return new UpdatedItemResult(
+ $this->core->call('mailservice.update', $params)
+ );
+ }
+
+ /**
+ * Get mail service by ID.
+ *
+ * @link https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-get.html
+ *
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[ApiEndpointMetadata(
+ 'mailservice.get',
+ 'https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-get.html',
+ 'Returns mail service parameters by its identifier'
+ )]
+ public function get(int $id): MailServiceResult
+ {
+ return new MailServiceResult(
+ $this->core->call('mailservice.get', ['ID' => $id])
+ );
+ }
+
+ /**
+ * Get list of active mail services.
+ *
+ * @link https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-list.html
+ *
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[ApiEndpointMetadata(
+ 'mailservice.list',
+ 'https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-list.html',
+ 'Returns the list of active mail services'
+ )]
+ public function list(): MailServicesResult
+ {
+ return new MailServicesResult(
+ $this->core->call('mailservice.list')
+ );
+ }
+
+ /**
+ * Delete a mail service by ID.
+ *
+ * @link https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-delete.html
+ *
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[ApiEndpointMetadata(
+ 'mailservice.delete',
+ 'https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-delete.html',
+ 'Deletes a mail service by its identifier'
+ )]
+ public function delete(int $id): DeletedItemResult
+ {
+ return new DeletedItemResult(
+ $this->core->call('mailservice.delete', ['ID' => $id])
+ );
+ }
+
+ /**
+ * Get the localized field labels of a mail service.
+ *
+ * @link https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-fields.html
+ *
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[ApiEndpointMetadata(
+ 'mailservice.fields',
+ 'https://apidocs.bitrix24.com/api-reference/mailservice/mailservice-fields.html',
+ 'Returns localized field labels of mail service'
+ )]
+ public function fields(): FieldsResult
+ {
+ return new FieldsResult($this->core->call('mailservice.fields'));
+ }
+
+ /**
+ * Count active mail services.
+ *
+ * @throws BaseException
+ * @throws TransportException
+ */
+ public function count(): int
+ {
+ return count($this->list()->getMailServices());
+ }
+}
diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php
index 4c1026e5..f8d7184a 100644
--- a/src/Services/ServiceBuilder.php
+++ b/src/Services/ServiceBuilder.php
@@ -37,6 +37,7 @@
use Bitrix24\SDK\Services\Paysystem\PaysystemServiceBuilder;
use Bitrix24\SDK\Services\SonetGroup\SonetGroupServiceBuilder;
use Bitrix24\SDK\Services\Landing\LandingServiceBuilder;
+use Bitrix24\SDK\Services\MailService\MailServiceServiceBuilder;
use Psr\Log\LoggerInterface;
class ServiceBuilder extends AbstractServiceBuilder
@@ -349,4 +350,18 @@ public function getLandingScope(): LandingServiceBuilder
return $this->serviceCache[__METHOD__];
}
+
+ public function getMailServiceScope(): MailServiceServiceBuilder
+ {
+ if (!isset($this->serviceCache[__METHOD__])) {
+ $this->serviceCache[__METHOD__] = new MailServiceServiceBuilder(
+ $this->core,
+ $this->batch,
+ $this->bulkItemsReader,
+ $this->log
+ );
+ }
+
+ return $this->serviceCache[__METHOD__];
+ }
}
diff --git a/tests/Integration/Services/MailService/Result/MailServiceItemResultAnnotationsTest.php b/tests/Integration/Services/MailService/Result/MailServiceItemResultAnnotationsTest.php
new file mode 100644
index 00000000..f62c2662
--- /dev/null
+++ b/tests/Integration/Services/MailService/Result/MailServiceItemResultAnnotationsTest.php
@@ -0,0 +1,70 @@
+
+ *
+ * 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\MailService\Result;
+
+use Bitrix24\SDK\Services\MailService\Result\MailServiceItemResult;
+use Bitrix24\SDK\Services\MailService\Service\MailService;
+use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions;
+use Bitrix24\SDK\Tests\Integration\Fabric;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\TestDox;
+use PHPUnit\Framework\TestCase;
+
+#[CoversClass(MailServiceItemResult::class)]
+class MailServiceItemResultAnnotationsTest extends TestCase
+{
+ use CustomBitrix24Assertions;
+
+ private MailService $mailService;
+
+ private int $testMailServiceId = 0;
+
+ #[\Override]
+ protected function setUp(): void
+ {
+ $this->mailService = Fabric::getServiceBuilder()->getMailServiceScope()->mailService();
+ $this->testMailServiceId = $this->mailService->add(
+ 'SDK Annotations Test MailService',
+ 'Y',
+ 'imap.example.com',
+ 993,
+ 'Y',
+ 'https://mail.example.com'
+ )->getId();
+ }
+
+ #[\Override]
+ protected function tearDown(): void
+ {
+ if ($this->testMailServiceId > 0) {
+ $this->mailService->delete($this->testMailServiceId);
+ }
+ }
+
+ #[Test]
+ #[TestDox('all system fields are annotated in MailServiceItemResult phpdoc')]
+ public function testAllSystemFieldsAnnotated(): void
+ {
+ $rawItem = $this->mailService->get($this->testMailServiceId)
+ ->getCoreResponse()
+ ->getResponseData()
+ ->getResult();
+
+ $this->assertBitrix24AllResultItemFieldsAnnotated(
+ array_keys($rawItem),
+ MailServiceItemResult::class
+ );
+ }
+}
diff --git a/tests/Integration/Services/MailService/Service/BatchTest.php b/tests/Integration/Services/MailService/Service/BatchTest.php
new file mode 100644
index 00000000..02f36d30
--- /dev/null
+++ b/tests/Integration/Services/MailService/Service/BatchTest.php
@@ -0,0 +1,138 @@
+
+ *
+ * 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\MailService\Service;
+
+use Bitrix24\SDK\Core\Exceptions\BaseException;
+use Bitrix24\SDK\Core\Exceptions\TransportException;
+use Bitrix24\SDK\Services\MailService\Service\Batch;
+use Bitrix24\SDK\Services\MailService\Service\MailService;
+use Bitrix24\SDK\Tests\Integration\Fabric;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\TestDox;
+use PHPUnit\Framework\TestCase;
+
+#[CoversClass(Batch::class)]
+class BatchTest extends TestCase
+{
+ private MailService $mailService;
+
+ #[\Override]
+ protected function setUp(): void
+ {
+ $this->mailService = Fabric::getServiceBuilder()->getMailServiceScope()->mailService();
+ }
+
+ /**
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[TestDox('batch add creates multiple mail services')]
+ public function testBatchAdd(): void
+ {
+ $items = [];
+ for ($i = 1; $i <= 3; $i++) {
+ $items[] = [
+ 'NAME' => 'SDK Batch Test MailService ' . $i,
+ 'ACTIVE' => 'Y',
+ 'SERVER' => 'imap.example' . $i . '.com',
+ 'PORT' => 993,
+ 'ENCRYPTION' => 'Y',
+ ];
+ }
+
+ $ids = [];
+ $cnt = 0;
+ foreach ($this->mailService->batch->add($items) as $result) {
+ $cnt++;
+ $ids[] = $result->getId();
+ }
+
+ self::assertSame(count($items), $cnt);
+
+ // cleanup
+ foreach ($this->mailService->batch->delete($ids) as $deleteResult) {
+ // iterate to trigger execution
+ }
+ }
+
+ /**
+ * @throws BaseException
+ */
+ #[TestDox('batch delete removes multiple mail services')]
+ public function testBatchDelete(): void
+ {
+ $items = [];
+ for ($i = 1; $i <= 3; $i++) {
+ $items[] = [
+ 'NAME' => 'SDK Batch Delete Test ' . $i,
+ 'ACTIVE' => 'Y',
+ 'ENCRYPTION' => 'N',
+ ];
+ }
+
+ $ids = [];
+ foreach ($this->mailService->batch->add($items) as $result) {
+ $ids[] = $result->getId();
+ }
+
+ $cnt = 0;
+ foreach ($this->mailService->batch->delete($ids) as $deleteResult) {
+ $cnt++;
+ self::assertTrue($deleteResult->isSuccess());
+ }
+
+ self::assertSame(count($items), $cnt);
+ }
+
+ /**
+ * @throws BaseException
+ */
+ #[TestDox('batch update modifies multiple mail services')]
+ public function testBatchUpdate(): void
+ {
+ $items = [];
+ for ($i = 1; $i <= 3; $i++) {
+ $items[] = [
+ 'NAME' => 'SDK Batch Update Test ' . $i,
+ 'ACTIVE' => 'Y',
+ 'ENCRYPTION' => 'N',
+ ];
+ }
+
+ $ids = [];
+ foreach ($this->mailService->batch->add($items) as $result) {
+ $ids[] = $result->getId();
+ }
+
+ $updates = [];
+ foreach ($ids as $id) {
+ $updates[$id] = [
+ 'NAME' => 'SDK Batch Updated ' . $id,
+ ];
+ }
+
+ $cnt = 0;
+ foreach ($this->mailService->batch->update($updates) as $updateResult) {
+ $cnt++;
+ self::assertTrue($updateResult->isSuccess());
+ }
+
+ self::assertSame(count($updates), $cnt);
+
+ // cleanup
+ foreach ($this->mailService->batch->delete($ids) as $deleteResult) {
+ // iterate to trigger execution
+ }
+ }
+}
diff --git a/tests/Integration/Services/MailService/Service/MailServiceTest.php b/tests/Integration/Services/MailService/Service/MailServiceTest.php
new file mode 100644
index 00000000..8d6a744d
--- /dev/null
+++ b/tests/Integration/Services/MailService/Service/MailServiceTest.php
@@ -0,0 +1,194 @@
+
+ *
+ * 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\MailService\Service;
+
+use Bitrix24\SDK\Core\Exceptions\BaseException;
+use Bitrix24\SDK\Core\Exceptions\TransportException;
+use Bitrix24\SDK\Services\MailService\Service\MailService;
+use Bitrix24\SDK\Tests\Integration\Fabric;
+use PHPUnit\Framework\Attributes\CoversClass;
+use PHPUnit\Framework\Attributes\TestDox;
+use PHPUnit\Framework\TestCase;
+
+#[CoversClass(MailService::class)]
+class MailServiceTest extends TestCase
+{
+ private MailService $mailService;
+
+ private int $testMailServiceId = 0;
+
+ #[\Override]
+ protected function setUp(): void
+ {
+ $this->mailService = Fabric::getServiceBuilder()->getMailServiceScope()->mailService();
+ }
+
+ #[\Override]
+ protected function tearDown(): void
+ {
+ if ($this->testMailServiceId > 0) {
+ $this->mailService->delete($this->testMailServiceId);
+ $this->testMailServiceId = 0;
+ }
+ }
+
+ /**
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[TestDox('add creates a new mail service and returns its ID')]
+ public function testAdd(): void
+ {
+ $addedItemResult = $this->mailService->add(
+ 'SDK Test MailService',
+ 'Y',
+ 'imap.example.com',
+ 993,
+ 'Y',
+ 'https://mail.example.com'
+ );
+ $this->testMailServiceId = $addedItemResult->getId();
+
+ self::assertGreaterThan(0, $this->testMailServiceId);
+ }
+
+ /**
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[TestDox('update modifies an existing mail service')]
+ public function testUpdate(): void
+ {
+ $this->testMailServiceId = $this->mailService->add(
+ 'SDK Test MailService Update',
+ 'Y',
+ 'imap.example.com',
+ 993,
+ 'Y',
+ 'https://mail.example.com'
+ )->getId();
+
+ $updatedName = 'SDK Test MailService Updated';
+ $updatedItemResult = $this->mailService->update($this->testMailServiceId, ['NAME' => $updatedName]);
+
+ self::assertTrue($updatedItemResult->isSuccess());
+
+ $mailServiceItemResult = $this->mailService->get($this->testMailServiceId)->mailService();
+ self::assertSame($updatedName, $mailServiceItemResult->NAME);
+ }
+
+ /**
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[TestDox('get returns a mail service by its ID')]
+ public function testGet(): void
+ {
+ $this->testMailServiceId = $this->mailService->add(
+ 'SDK Test MailService Get',
+ 'Y',
+ 'imap.example.com',
+ 993,
+ 'Y',
+ 'https://mail.example.com'
+ )->getId();
+
+ $mailServiceItemResult = $this->mailService->get($this->testMailServiceId)->mailService();
+
+ self::assertSame($this->testMailServiceId, $mailServiceItemResult->ID);
+ self::assertSame('SDK Test MailService Get', $mailServiceItemResult->NAME);
+ }
+
+ /**
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[TestDox('list returns active mail services')]
+ public function testList(): void
+ {
+ $this->testMailServiceId = $this->mailService->add(
+ 'SDK Test MailService List',
+ 'Y',
+ 'imap.example.com',
+ 993,
+ 'Y',
+ 'https://mail.example.com'
+ )->getId();
+
+ $items = $this->mailService->list()->getMailServices();
+
+ self::assertIsArray($items);
+ self::assertGreaterThanOrEqual(1, count($items));
+ }
+
+ /**
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[TestDox('delete removes a mail service')]
+ public function testDelete(): void
+ {
+ $id = $this->mailService->add(
+ 'SDK Test MailService Delete',
+ 'Y',
+ 'imap.example.com',
+ 993,
+ 'Y',
+ 'https://mail.example.com'
+ )->getId();
+
+ $deletedItemResult = $this->mailService->delete($id);
+
+ self::assertTrue($deletedItemResult->isSuccess());
+ // prevent double-delete in tearDown
+ $this->testMailServiceId = 0;
+ }
+
+ /**
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[TestDox('fields returns localized field labels')]
+ public function testFields(): void
+ {
+ $fields = $this->mailService->fields()->getFieldsDescription();
+
+ self::assertIsArray($fields);
+ self::assertArrayHasKey('ID', $fields);
+ self::assertArrayHasKey('NAME', $fields);
+ }
+
+ /**
+ * @throws BaseException
+ * @throws TransportException
+ */
+ #[TestDox('count returns number of active mail services')]
+ public function testCount(): void
+ {
+ $before = $this->mailService->count();
+
+ $this->testMailServiceId = $this->mailService->add(
+ 'SDK Test MailService Count',
+ 'Y',
+ 'imap.example.com',
+ 993,
+ 'Y',
+ 'https://mail.example.com'
+ )->getId();
+
+ $after = $this->mailService->count();
+
+ self::assertSame($before + 1, $after);
+ }
+}