diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d2465a3..351a58b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,41 @@ # b24-php-sdk change log + + +## 1.1.0 – 2024.09. + +### Added + +- Added method `Bitrix24\SDK\Services\ServiceBuilderFactory::createServiceBuilderFromWebhook` for simple work with + webhook, see [add super-simple kick-off guide](https://github.com/bitrix24/b24phpsdk/issues/17). +- Added method `Bitrix24\SDK\Services\ServiceBuilderFactory::createServiceBuilderFromPlacementRequest` for simple work + with placement request, see [add super-simple kick-off guide](https://github.com/bitrix24/b24phpsdk/issues/17). + +### Changed + +- Changed scope for properties `Bitrix24\SDK\Core\Credentials\ApplicationProfile` - mark as public +- Changed example for work with webhook in [README.md](README.md) file and directory `/examples/webhook/` +- Changed example for work with local application in [README.md](README.md) file and directory + `/examples/local-application/` + + + ## 1.0 + * Initial release \ No newline at end of file diff --git a/README.md b/README.md index cb128843..612b3a78 100644 --- a/README.md +++ b/README.md @@ -113,39 +113,19 @@ composer install 3. Open Bitrix24 account: Developer resources → Other → Inbound webhook 4. Open example file and insert webhook url into `$webhookUrl` -
- see example.php file - ```php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; -use Symfony\Component\EventDispatcher\EventDispatcher; -use Monolog\Logger; -use Monolog\Handler\StreamHandler; -use Monolog\Processor\MemoryUsageProcessor; require_once 'vendor/autoload.php'; -$webhookUrl = 'INSERT_HERE_YOUR_WEBHOOK_URL'; - -$log = new Logger('bitrix24-php-sdk'); -$log->pushHandler(new StreamHandler('bitrix24-php-sdk.log')); -$log->pushProcessor(new MemoryUsageProcessor(true, true)); - -// create service builder factory -$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); // init bitrix24-php-sdk service from webhook -$b24Service = $b24ServiceFactory->initFromWebhook($webhookUrl); +$b24Service = ServiceBuilderFactory::createServiceBuilderFromWebhook('INSERT_HERE_YOUR_WEBHOOK_URL'); -// work with interested scope -var_dump($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()); -// get deals list and address to first element -var_dump($b24Service->getCRMScope()->lead()->list([], [], ['ID', 'TITLE'])->getLeads()[0]->TITLE); +// call some method +var_dump($b24Service->getMainScope()->main()->getApplicationInfo()->applicationInfo()); ``` - -
- 5. Call php file in shell ```shell @@ -201,13 +181,8 @@ x-powered-by: PHP/8.3.8 ```php declare(strict_types=1); -use Bitrix24\SDK\Core\Credentials\AuthToken; use Bitrix24\SDK\Core\Credentials\ApplicationProfile; use Bitrix24\SDK\Services\ServiceBuilderFactory; -use Monolog\Handler\StreamHandler; -use Monolog\Logger; -use Monolog\Processor\MemoryUsageProcessor; -use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpFoundation\Request; require_once 'vendor/autoload.php'; @@ -217,23 +192,16 @@ require_once 'vendor/autoload.php'; pushHandler(new StreamHandler('bitrix24-php-sdk.log')); -$log->pushProcessor(new MemoryUsageProcessor(true, true)); - -$b24ServiceBuilderFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); $appProfile = ApplicationProfile::initFromArray([ 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => 'INSERT_HERE_YOUR_DATA', 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => 'INSERT_HERE_YOUR_DATA', 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'INSERT_HERE_YOUR_DATA' ]); -$b24Service = $b24ServiceBuilderFactory->initFromRequest($appProfile, AuthToken::initFromPlacementRequest($request), $request->get('DOMAIN')); + +$b24Service = ServiceBuilderFactory::createServiceBuilderFromPlacementRequest(Request::createFromGlobals(), $appProfile); var_dump($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()); -// get deals list and address to first element -var_dump($b24Service->getCRMScope()->lead()->list([], [], ['ID', 'TITLE'])->getLeads()[0]->TITLE); ``` diff --git a/examples/local-application/composer.json b/examples/local-application/composer.json index fd2eefd1..40de84c5 100644 --- a/examples/local-application/composer.json +++ b/examples/local-application/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "bitrix24/b24phpsdk": "1.0", + "bitrix24/b24phpsdk": "1.*", "monolog/monolog": "^3", "symfony/dotenv": "^7" }, diff --git a/examples/local-application/index.php b/examples/local-application/index.php index a5f7fe27..41c62d47 100644 --- a/examples/local-application/index.php +++ b/examples/local-application/index.php @@ -11,13 +11,8 @@ declare(strict_types=1); -use Bitrix24\SDK\Core\Credentials\AuthToken; use Bitrix24\SDK\Core\Credentials\ApplicationProfile; use Bitrix24\SDK\Services\ServiceBuilderFactory; -use Monolog\Handler\StreamHandler; -use Monolog\Logger; -use Monolog\Processor\MemoryUsageProcessor; -use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpFoundation\Request; require_once 'vendor/autoload.php'; @@ -27,20 +22,13 @@ pushHandler(new StreamHandler('bitrix24-php-sdk.log')); -$log->pushProcessor(new MemoryUsageProcessor(true, true)); - -$b24ServiceBuilderFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); $appProfile = ApplicationProfile::initFromArray([ 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => 'INSERT_HERE_YOUR_DATA', 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => 'INSERT_HERE_YOUR_DATA', - 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'INSERT_HERE_YOUR_DATA' + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'INSERT_HERE_YOUR_DATA', ]); -$b24Service = $b24ServiceBuilderFactory->initFromRequest($appProfile, AuthToken::initFromPlacementRequest($request), $request->get('DOMAIN')); + +$b24Service = ServiceBuilderFactory::createServiceBuilderFromPlacementRequest(Request::createFromGlobals(), $appProfile); var_dump($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()); -// get deals list and address to first element -var_dump($b24Service->getCRMScope()->lead()->list([], [], ['ID', 'TITLE'])->getLeads()[0]->TITLE); \ No newline at end of file diff --git a/examples/webhook/composer.json b/examples/webhook/composer.json index 3fc9ddf6..4723f520 100644 --- a/examples/webhook/composer.json +++ b/examples/webhook/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "bitrix24/b24phpsdk": "1.0", + "bitrix24/b24phpsdk": "1.*", "monolog/monolog": "^3", "symfony/dotenv": "^7" }, diff --git a/examples/webhook/example.php b/examples/webhook/example.php index 446fb703..2da1acba 100644 --- a/examples/webhook/example.php +++ b/examples/webhook/example.php @@ -12,25 +12,11 @@ declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; -use Symfony\Component\EventDispatcher\EventDispatcher; -use Monolog\Logger; -use Monolog\Handler\StreamHandler; -use Monolog\Processor\MemoryUsageProcessor; require_once 'vendor/autoload.php'; -$webhookUrl = 'INSERT_HERE_YOUR_WEBHOOK_URL'; - -$log = new Logger('bitrix24-php-sdk'); -$log->pushHandler(new StreamHandler('bitrix24-php-sdk.log')); -$log->pushProcessor(new MemoryUsageProcessor(true, true)); - -// create service builder factory -$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); // init bitrix24-php-sdk service from webhook -$b24Service = $b24ServiceFactory->initFromWebhook($webhookUrl); +$b24Service = ServiceBuilderFactory::createServiceBuilderFromWebhook('INSERT_HERE_YOUR_WEBHOOK_URL'); -// work with interested scope -var_dump($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()); -// get deals list and address to first element -var_dump($b24Service->getCRMScope()->lead()->list([], [], ['ID', 'TITLE'])->getLeads()[0]->TITLE); +// call some method +var_dump($b24Service->getMainScope()->main()->getApplicationInfo()->applicationInfo()); \ No newline at end of file diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index 9f1df967..10c759ac 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -103,8 +103,8 @@ public function getNewAuthToken(): RenewedAuthToken http_build_query( [ 'grant_type' => 'refresh_token', - 'client_id' => $this->getCredentials()->getApplicationProfile()->getClientId(), - 'client_secret' => $this->getCredentials()->getApplicationProfile()->getClientSecret(), + 'client_id' => $this->getCredentials()->getApplicationProfile()->clientId, + 'client_secret' => $this->getCredentials()->getApplicationProfile()->clientSecret, 'refresh_token' => $this->getCredentials()->getAuthToken()->getRefreshToken(), $this->requestIdGenerator->getQueryStringParameterName() => $requestId ] diff --git a/src/Core/Credentials/ApplicationProfile.php b/src/Core/Credentials/ApplicationProfile.php index f8b0a39f..6353ce33 100644 --- a/src/Core/Credentials/ApplicationProfile.php +++ b/src/Core/Credentials/ApplicationProfile.php @@ -14,13 +14,9 @@ namespace Bitrix24\SDK\Core\Credentials; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; -/** - * Class ApplicationProfile - * - * @package Bitrix24\SDK\Core\Credentials - */ -class ApplicationProfile +readonly class ApplicationProfile { private const BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID = 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID'; @@ -31,27 +27,24 @@ class ApplicationProfile /** * ApplicationProfile constructor. */ - public function __construct(private readonly string $clientId, private readonly string $clientSecret, private readonly Scope $scope) - { - } - - public function getClientId(): string - { - return $this->clientId; - } - - public function getClientSecret(): string - { - return $this->clientSecret; - } - - public function getScope(): Scope + public function __construct( + public string $clientId, + public string $clientSecret, + public Scope $scope) { - return $this->scope; } /** - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * Init Application profile from array + * + * @param array{ + * BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID: string, + * BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET: string, + * BITRIX24_PHP_SDK_APPLICATION_SCOPE: string + * } $appProfile + * + * @throws UnknownScopeCodeException + * @throws InvalidArgumentException */ public static function initFromArray(array $appProfile): self { @@ -70,7 +63,7 @@ public static function initFromArray(array $appProfile): self return new self( $appProfile[self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID], $appProfile[self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET], - new Scope(str_replace(' ', '', explode(',', (string) $appProfile[self::BITRIX24_PHP_SDK_APPLICATION_SCOPE]))), + Scope::initFromString($appProfile[self::BITRIX24_PHP_SDK_APPLICATION_SCOPE]) ); } } \ No newline at end of file diff --git a/src/Services/ServiceBuilderFactory.php b/src/Services/ServiceBuilderFactory.php index c7af145f..b85e725d 100644 --- a/src/Services/ServiceBuilderFactory.php +++ b/src/Services/ServiceBuilderFactory.php @@ -23,6 +23,9 @@ use Bitrix24\SDK\Core\Credentials\WebhookUrl; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\HttpFoundation\Request; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class ServiceBuilderFactory @@ -64,7 +67,7 @@ public function initFromAccount(ApplicationProfile $applicationProfile, Bitrix24 * Init service builder from request * * @param ApplicationProfile $applicationProfile - * @param AuthToken $accessToken + * @param AuthToken $authToken * @param string $bitrix24DomainUrl * * @return ServiceBuilder @@ -72,13 +75,13 @@ public function initFromAccount(ApplicationProfile $applicationProfile, Bitrix24 */ public function initFromRequest( ApplicationProfile $applicationProfile, - AuthToken $accessToken, + AuthToken $authToken, string $bitrix24DomainUrl ): ServiceBuilder { return $this->getServiceBuilder( Credentials::createFromOAuth( - $accessToken, + $authToken, $applicationProfile, $bitrix24DomainUrl ) @@ -125,4 +128,66 @@ private function getServiceBuilder(Credentials $credentials): ServiceBuilder ); } + /** + * Create service builder from incoming webhook + * + * @param non-empty-string $webhookUrl incoming webhook url from your bitrix24 portal + * @param EventDispatcherInterface|null $eventDispatcher optional event dispatcher for subscribe some domain events if need + * @param LoggerInterface|null $logger optional logger for debug logs + * @throws InvalidArgumentException + */ + public static function createServiceBuilderFromWebhook( + string $webhookUrl, + ?EventDispatcherInterface $eventDispatcher = null, + ?LoggerInterface $logger = null): ServiceBuilder + { + if ($eventDispatcher === null) { + $eventDispatcher = new EventDispatcher(); + } + if ($logger === null) { + $logger = new NullLogger(); + } + return (new ServiceBuilderFactory($eventDispatcher, $logger))->initFromWebhook($webhookUrl); + } + + /** + * Create service builder from placement request + * + * @param Request $placementRequest The placement request object that contains the request data. + * @param ApplicationProfile $applicationProfile The application profile object. + * @param EventDispatcherInterface|null $eventDispatcher Optional event dispatcher for subscribing to domain events. + * @param LoggerInterface|null $logger Optional logger for debug logs. + * @return ServiceBuilder The service builder object. + * @throws InvalidArgumentException If the key "DOMAIN" is not found in the request. + */ + public static function createServiceBuilderFromPlacementRequest( + Request $placementRequest, + ApplicationProfile $applicationProfile, + ?EventDispatcherInterface $eventDispatcher = null, + ?LoggerInterface $logger = null + ): ServiceBuilder + { + if (!array_key_exists('DOMAIN', $placementRequest->query->keys())) { + throw new InvalidArgumentException('key «DOMAIN» not found in request'); + } + + $rawDomainUrl = trim((string)$placementRequest->query->get('DOMAIN')); + if ($rawDomainUrl === '') { + throw new InvalidArgumentException('DOMAIN key cannot be empty in request'); + } + + if ($eventDispatcher === null) { + $eventDispatcher = new EventDispatcher(); + } + if ($logger === null) { + $logger = new NullLogger(); + } + + return (new ServiceBuilderFactory($eventDispatcher, $logger)) + ->initFromRequest( + $applicationProfile, + AuthToken::initFromPlacementRequest($placementRequest), + $rawDomainUrl + ); + } } \ No newline at end of file diff --git a/tests/Unit/Core/Credentials/ApplicationProfileTest.php b/tests/Unit/Core/Credentials/ApplicationProfileTest.php index 823ef7fa..e33b906d 100644 --- a/tests/Unit/Core/Credentials/ApplicationProfileTest.php +++ b/tests/Unit/Core/Credentials/ApplicationProfileTest.php @@ -16,6 +16,7 @@ use Bitrix24\SDK\Core\Credentials\ApplicationProfile; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Generator; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class ApplicationProfileTest extends TestCase @@ -25,7 +26,7 @@ class ApplicationProfileTest extends TestCase * * @throws InvalidArgumentException */ - #[\PHPUnit\Framework\Attributes\DataProvider('arrayDataProvider')] + #[DataProvider('arrayDataProvider')] public function testFromArray(array $arr, ?string $expectedException): void { if ($expectedException !== null) { @@ -34,8 +35,8 @@ public function testFromArray(array $arr, ?string $expectedException): void $applicationProfile = ApplicationProfile::initFromArray($arr); - $this->assertEquals($applicationProfile->getClientId(), $arr['BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID']); - $this->assertEquals($applicationProfile->getClientSecret(), $arr['BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET']); + $this->assertEquals($applicationProfile->clientId, $arr['BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID']); + $this->assertEquals($applicationProfile->clientSecret, $arr['BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET']); } public static function arrayDataProvider(): Generator diff --git a/tests/Unit/Services/ServiceBuilderCacheTest.php b/tests/Unit/Services/ServiceBuilderCacheTest.php new file mode 100644 index 00000000..aa42a053 --- /dev/null +++ b/tests/Unit/Services/ServiceBuilderCacheTest.php @@ -0,0 +1,88 @@ + + * + * 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\Unit\Services; + +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBatch; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBulkItemsReader; +use Bitrix24\SDK\Tests\Unit\Stubs\NullCore; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; +use Psr\Log\NullLogger; + +#[CoversClass(ServiceBuilder::class)] +class ServiceBuilderCacheTest extends TestCase +{ + private ServiceBuilder $serviceBuilder; + + public function testGetMainScopeBuilder(): void + { + $this::assertSame($this->serviceBuilder->getMainScope(), $this->serviceBuilder->getMainScope()); + } + + public function testGetCrmScopeBuilder(): void + { + $this::assertSame($this->serviceBuilder->getCRMScope(), $this->serviceBuilder->getCRMScope()); + } + + public function testGetImScopeBuilder(): void + { + $this::assertSame($this->serviceBuilder->getIMScope(), $this->serviceBuilder->getIMScope()); + } + + public function testGetImOpenLinesBuilder(): void + { + $this::assertSame($this->serviceBuilder->getIMOpenLinesScope(), $this->serviceBuilder->getIMOpenLinesScope()); + } + + public function testGetUserConsentBuilder(): void + { + $this::assertSame($this->serviceBuilder->getUserConsentScope(), $this->serviceBuilder->getUserConsentScope()); + } + + public function testGetUserBuilder(): void + { + $this::assertSame($this->serviceBuilder->getUserScope(), $this->serviceBuilder->getUserScope()); + } + + public function testGetPlacementBuilder(): void + { + $this::assertSame($this->serviceBuilder->getPlacementScope(), $this->serviceBuilder->getPlacementScope()); + } + + public function testGetCatalogBuilder(): void + { + $this::assertSame($this->serviceBuilder->getCatalogScope(), $this->serviceBuilder->getCatalogScope()); + } + + public function testGetBizProcBuilder(): void + { + $this::assertSame($this->serviceBuilder->getBizProcScope(), $this->serviceBuilder->getBizProcScope()); + } + + public function testGetTelephonyBuilder(): void + { + $this::assertSame($this->serviceBuilder->getTelephonyScope(), $this->serviceBuilder->getTelephonyScope()); + } + + protected function setUp(): void + { + $this->serviceBuilder = new ServiceBuilder( + new NullCore(), + new NullBatch(), + new NullBulkItemsReader(), + new NullLogger() + ); + } +} \ No newline at end of file diff --git a/tests/Unit/Services/ServiceBuilderTest.php b/tests/Unit/Services/ServiceBuilderTest.php deleted file mode 100644 index 698e1ec4..00000000 --- a/tests/Unit/Services/ServiceBuilderTest.php +++ /dev/null @@ -1,60 +0,0 @@ - - * - * For the full copyright and license information, please view the MIT-LICENSE.txt - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Bitrix24\SDK\Tests\Unit\Services; - -use Bitrix24\SDK\Services\ServiceBuilder; -use Bitrix24\SDK\Tests\Unit\Stubs\NullBatch; -use Bitrix24\SDK\Tests\Unit\Stubs\NullBulkItemsReader; -use Bitrix24\SDK\Tests\Unit\Stubs\NullCore; -use PHPUnit\Framework\TestCase; -use Psr\Log\NullLogger; - -/** - * Class TestServiceBuilder - * - * @package Bitrix24\SDK\Tests\Unit\Services - */ -#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\ServiceBuilder::class)] -class ServiceBuilderTest extends TestCase -{ - private ServiceBuilder $serviceBuilder; - - public function testGetMainScopeBuilder(): void - { - $this->serviceBuilder->getMainScope(); - $this::assertTrue(true); - } - - public function testGetIMScopeBuilder(): void - { - $this->serviceBuilder->getIMScope(); - $this::assertTrue(true); - } - - public function testGetCrmScopeBuilder(): void - { - $this->serviceBuilder->getCRMScope(); - $this::assertTrue(true); - } - - protected function setUp(): void - { - $this->serviceBuilder = new ServiceBuilder( - new NullCore(), - new NullBatch(), - new NullBulkItemsReader(), - new NullLogger() - ); - } -} \ No newline at end of file