From 1b0987939032c261ee08a720fafe18ae0e864094 Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Tue, 30 Sep 2025 13:47:25 +0400 Subject: [PATCH 01/14] add Landing Site service and tests --- Makefile | 8 + phpunit.xml.dist | 6 + .../Landing/LandingServiceBuilder.php | 42 ++ .../Landing/Site/Result/FolderAddedResult.php | 28 + .../Site/Result/FolderMarkedDeletedResult.php | 28 + .../Result/FolderMarkedUnDeletedResult.php | 28 + .../Site/Result/FolderPublishedResult.php | 28 + .../Site/Result/FolderUnpublishedResult.php | 28 + .../Site/Result/FolderUpdatedResult.php | 28 + .../Landing/Site/Result/FoldersResult.php | 31 ++ .../Landing/Site/Result/SiteAddedResult.php | 28 + .../Landing/Site/Result/SiteDeletedResult.php | 28 + .../Landing/Site/Result/SiteItemResult.php | 42 ++ .../Site/Result/SiteMarkedDeletedResult.php | 24 + .../Site/Result/SiteMarkedUnDeletedResult.php | 28 + .../Site/Result/SitePublishedResult.php | 24 + .../Site/Result/SiteUnpublishedResult.php | 28 + .../Landing/Site/Result/SiteUpdatedResult.php | 28 + .../Landing/Site/Result/SiteUrlResult.php | 24 + .../Landing/Site/Result/SitesResult.php | 32 ++ src/Services/Landing/Site/Service/Site.php | 451 +++++++++++++++ src/Services/ServiceBuilder.php | 15 + .../Landing/Site/Service/SiteTest.php | 520 ++++++++++++++++++ 23 files changed, 1527 insertions(+) create mode 100644 src/Services/Landing/LandingServiceBuilder.php create mode 100644 src/Services/Landing/Site/Result/FolderAddedResult.php create mode 100644 src/Services/Landing/Site/Result/FolderMarkedDeletedResult.php create mode 100644 src/Services/Landing/Site/Result/FolderMarkedUnDeletedResult.php create mode 100644 src/Services/Landing/Site/Result/FolderPublishedResult.php create mode 100644 src/Services/Landing/Site/Result/FolderUnpublishedResult.php create mode 100644 src/Services/Landing/Site/Result/FolderUpdatedResult.php create mode 100644 src/Services/Landing/Site/Result/FoldersResult.php create mode 100644 src/Services/Landing/Site/Result/SiteAddedResult.php create mode 100644 src/Services/Landing/Site/Result/SiteDeletedResult.php create mode 100644 src/Services/Landing/Site/Result/SiteItemResult.php create mode 100644 src/Services/Landing/Site/Result/SiteMarkedDeletedResult.php create mode 100644 src/Services/Landing/Site/Result/SiteMarkedUnDeletedResult.php create mode 100644 src/Services/Landing/Site/Result/SitePublishedResult.php create mode 100644 src/Services/Landing/Site/Result/SiteUnpublishedResult.php create mode 100644 src/Services/Landing/Site/Result/SiteUpdatedResult.php create mode 100644 src/Services/Landing/Site/Result/SiteUrlResult.php create mode 100644 src/Services/Landing/Site/Result/SitesResult.php create mode 100644 src/Services/Landing/Site/Service/Site.php create mode 100644 tests/Integration/Services/Landing/Site/Service/SiteTest.php diff --git a/Makefile b/Makefile index 5c93b5ac..6abbd709 100644 --- a/Makefile +++ b/Makefile @@ -192,6 +192,14 @@ test-integration-scope-log: test-integration-scope-sale: docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_scope_sale +.PHONY: test-integration-scope-landing +test-integration-scope-landing: + docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_scope_landing + +.PHONY: test-integration-landing-site +test-integration-landing-site: + docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_landing_site + .PHONY: test-integration-sale-status test-integration-sale-status: docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_sale_status diff --git a/phpunit.xml.dist b/phpunit.xml.dist index d69753c3..edfbcd65 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -136,6 +136,12 @@ ./tests/Integration/Services/Sale/Order/ + + ./tests/Integration/Services/Landing/ + + + ./tests/Integration/Services/Landing/Site/ + diff --git a/src/Services/Landing/LandingServiceBuilder.php b/src/Services/Landing/LandingServiceBuilder.php new file mode 100644 index 00000000..3e864ff2 --- /dev/null +++ b/src/Services/Landing/LandingServiceBuilder.php @@ -0,0 +1,42 @@ + + * + * 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\Landing; + +use Bitrix24\SDK\Attributes\ApiServiceBuilderMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Services\AbstractServiceBuilder; + +/** + * Class LandingServiceBuilder + * + * @package Bitrix24\SDK\Services\Landing + */ +#[ApiServiceBuilderMetadata(new Scope(['landing']))] +class LandingServiceBuilder extends AbstractServiceBuilder +{ + /** + * Get Site service + */ + public function site(): Site\Service\Site + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Site\Service\Site( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/FolderAddedResult.php b/src/Services/Landing/Site/Result/FolderAddedResult.php new file mode 100644 index 00000000..01880966 --- /dev/null +++ b/src/Services/Landing/Site/Result/FolderAddedResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class FolderAddedResult extends AbstractResult +{ + public function getId(): int + { + echo "\n FolderAddedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return (int)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/FolderMarkedDeletedResult.php b/src/Services/Landing/Site/Result/FolderMarkedDeletedResult.php new file mode 100644 index 00000000..71dcd6db --- /dev/null +++ b/src/Services/Landing/Site/Result/FolderMarkedDeletedResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class FolderMarkedDeletedResult extends AbstractResult +{ + public function isSuccess(): bool + { + echo "\n FolderMarkedDeletedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/FolderMarkedUnDeletedResult.php b/src/Services/Landing/Site/Result/FolderMarkedUnDeletedResult.php new file mode 100644 index 00000000..df1f29df --- /dev/null +++ b/src/Services/Landing/Site/Result/FolderMarkedUnDeletedResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class FolderMarkedUnDeletedResult extends AbstractResult +{ + public function isSuccess(): bool + { + echo "\n FolderMarkedUnDeletedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/FolderPublishedResult.php b/src/Services/Landing/Site/Result/FolderPublishedResult.php new file mode 100644 index 00000000..4844328e --- /dev/null +++ b/src/Services/Landing/Site/Result/FolderPublishedResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class FolderPublishedResult extends AbstractResult +{ + public function isSuccess(): bool + { + echo "\n FolderPublishedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/FolderUnpublishedResult.php b/src/Services/Landing/Site/Result/FolderUnpublishedResult.php new file mode 100644 index 00000000..5e52044a --- /dev/null +++ b/src/Services/Landing/Site/Result/FolderUnpublishedResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class FolderUnpublishedResult extends AbstractResult +{ + public function isSuccess(): bool + { + echo "\n FolderUnpublishedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/FolderUpdatedResult.php b/src/Services/Landing/Site/Result/FolderUpdatedResult.php new file mode 100644 index 00000000..de48823a --- /dev/null +++ b/src/Services/Landing/Site/Result/FolderUpdatedResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class FolderUpdatedResult extends AbstractResult +{ + public function isSuccess(): bool + { + echo "\n FolderUpdatedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/FoldersResult.php b/src/Services/Landing/Site/Result/FoldersResult.php new file mode 100644 index 00000000..65de1b83 --- /dev/null +++ b/src/Services/Landing/Site/Result/FoldersResult.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\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class FoldersResult extends AbstractResult +{ + /** + * @return array + */ + public function getFolders(): array + { + echo "\n FoldersResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return $this->getCoreResponse()->getResponseData()->getResult(); + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SiteAddedResult.php b/src/Services/Landing/Site/Result/SiteAddedResult.php new file mode 100644 index 00000000..3aab3edd --- /dev/null +++ b/src/Services/Landing/Site/Result/SiteAddedResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SiteAddedResult extends AbstractResult +{ + public function getId(): int + { + echo "\n SiteAddedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return (int)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SiteDeletedResult.php b/src/Services/Landing/Site/Result/SiteDeletedResult.php new file mode 100644 index 00000000..4d89709a --- /dev/null +++ b/src/Services/Landing/Site/Result/SiteDeletedResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SiteDeletedResult extends AbstractResult +{ + public function isSuccess(): bool + { + echo "\n SiteDeletedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SiteItemResult.php b/src/Services/Landing/Site/Result/SiteItemResult.php new file mode 100644 index 00000000..517864bc --- /dev/null +++ b/src/Services/Landing/Site/Result/SiteItemResult.php @@ -0,0 +1,42 @@ + + * + * 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\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read int $ID Site identifier + * @property-read string|null $CODE Unique symbolic code of the site + * @property-read string $ACTIVE Site activity: Y / N + * @property-read string $TYPE Type of site (PAGE – regular site, STORE – store) + * @property-read string $DELETED Flag for deleted page: Y / N + * @property-read string $TITLE Title of the site + * @property-read string|null $XML_ID External key for developer needs + * @property-read string|null $DESCRIPTION Arbitrary description of the site + * @property-read string|null $DOMAIN_ID Domain identifier + * @property-read string|null $DOMAIN_NAME Domain of the site + * @property-read int|null $LANDING_ID_INDEX ID of the page designated as the main page of the site + * @property-read int|null $LANDING_ID_404 ID of the page designated as the site's 404 error page + * @property-read int|null $TPL_ID Identifier of the view template + * @property-read string|null $LANG Language identifier for the site + * @property-read int $CREATED_BY_ID Identifier of the user who created it + * @property-read int $MODIFIED_BY_ID Identifier of the user who modified it + * @property-read string $DATE_CREATE Creation date + * @property-read string $DATE_MODIFY Modification date + * @property-read string|null $PUBLIC_URL Public URL of the site + * @property-read string|null $PREVIEW_PICTURE Preview image of the site + */ +class SiteItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SiteMarkedDeletedResult.php b/src/Services/Landing/Site/Result/SiteMarkedDeletedResult.php new file mode 100644 index 00000000..9d469d36 --- /dev/null +++ b/src/Services/Landing/Site/Result/SiteMarkedDeletedResult.php @@ -0,0 +1,24 @@ + + * + * 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\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SiteMarkedDeletedResult extends AbstractResult +{ + public function isSuccess(): bool + { + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SiteMarkedUnDeletedResult.php b/src/Services/Landing/Site/Result/SiteMarkedUnDeletedResult.php new file mode 100644 index 00000000..9bacda6a --- /dev/null +++ b/src/Services/Landing/Site/Result/SiteMarkedUnDeletedResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SiteMarkedUnDeletedResult extends AbstractResult +{ + public function isSuccess(): bool + { + echo "\n SiteMarkedUnDeletedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SitePublishedResult.php b/src/Services/Landing/Site/Result/SitePublishedResult.php new file mode 100644 index 00000000..6e37cc03 --- /dev/null +++ b/src/Services/Landing/Site/Result/SitePublishedResult.php @@ -0,0 +1,24 @@ + + * + * 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\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SitePublishedResult extends AbstractResult +{ + public function isSuccess(): bool + { + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SiteUnpublishedResult.php b/src/Services/Landing/Site/Result/SiteUnpublishedResult.php new file mode 100644 index 00000000..c4cf0a66 --- /dev/null +++ b/src/Services/Landing/Site/Result/SiteUnpublishedResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SiteUnpublishedResult extends AbstractResult +{ + public function isSuccess(): bool + { + echo "\n SiteUnpublishedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SiteUpdatedResult.php b/src/Services/Landing/Site/Result/SiteUpdatedResult.php new file mode 100644 index 00000000..94c5e02d --- /dev/null +++ b/src/Services/Landing/Site/Result/SiteUpdatedResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SiteUpdatedResult extends AbstractResult +{ + public function isSuccess(): bool + { + echo "\n SiteUpdatedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SiteUrlResult.php b/src/Services/Landing/Site/Result/SiteUrlResult.php new file mode 100644 index 00000000..b5ee9f03 --- /dev/null +++ b/src/Services/Landing/Site/Result/SiteUrlResult.php @@ -0,0 +1,24 @@ + + * + * 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\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SiteUrlResult extends AbstractResult +{ + public function getUrl(): string + { + return (string)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} diff --git a/src/Services/Landing/Site/Result/SitesResult.php b/src/Services/Landing/Site/Result/SitesResult.php new file mode 100644 index 00000000..ff6df977 --- /dev/null +++ b/src/Services/Landing/Site/Result/SitesResult.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\Landing\Site\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SitesResult extends AbstractResult +{ + /** + * @return SiteItemResult[] + */ + public function getSites(): array + { + $result = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $site) { + $result[] = new SiteItemResult($site); + } + + return $result; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Site/Service/Site.php b/src/Services/Landing/Site/Service/Site.php new file mode 100644 index 00000000..47c7b15c --- /dev/null +++ b/src/Services/Landing/Site/Service/Site.php @@ -0,0 +1,451 @@ + + * + * 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\Landing\Site\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\Services\AbstractService; +use Bitrix24\SDK\Services\Landing\Site\Result\SiteAddedResult; +use Bitrix24\SDK\Services\Landing\Site\Result\SitesResult; +use Bitrix24\SDK\Services\Landing\Site\Result\SiteUpdatedResult; +use Bitrix24\SDK\Services\Landing\Site\Result\SiteDeletedResult; +use Bitrix24\SDK\Services\Landing\Site\Result\SiteUrlResult; +use Bitrix24\SDK\Services\Landing\Site\Result\SitePublishedResult; +use Bitrix24\SDK\Services\Landing\Site\Result\SiteUnpublishedResult; +use Bitrix24\SDK\Services\Landing\Site\Result\SiteMarkedDeletedResult; +use Bitrix24\SDK\Services\Landing\Site\Result\SiteMarkedUnDeletedResult; +use Bitrix24\SDK\Services\Landing\Site\Result\FoldersResult; +use Bitrix24\SDK\Services\Landing\Site\Result\FolderAddedResult; +use Bitrix24\SDK\Services\Landing\Site\Result\FolderUpdatedResult; +use Bitrix24\SDK\Services\Landing\Site\Result\FolderPublishedResult; +use Bitrix24\SDK\Services\Landing\Site\Result\FolderUnpublishedResult; +use Bitrix24\SDK\Services\Landing\Site\Result\FolderMarkedDeletedResult; +use Bitrix24\SDK\Services\Landing\Site\Result\FolderMarkedUnDeletedResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['landing']))] +class Site extends AbstractService +{ + public function __construct(CoreInterface $core, LoggerInterface $logger) + { + parent::__construct($core, $logger); + } + + /** + * Adds a site. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-add.html + * + * @param array $fields Field values for creating a site + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.add', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-add.html', + 'Method creates a new site.' + )] + public function add(array $fields): SiteAddedResult + { + return new SiteAddedResult( + $this->core->call('landing.site.add', ['fields' => $fields]) + ); + } + + /** + * Retrieves a list of sites. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-get-list.html + * + * @param array $select Fields to select + * @param array $filter Filter conditions + * @param array $order Sort order + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.getList', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-get-list.html', + 'Method retrieves a list of sites.' + )] + public function getList(array $select = [], array $filter = [], array $order = []): SitesResult + { + $params = []; + if (!empty($select)) { + $params['select'] = $select; + } + if (!empty($filter)) { + $params['filter'] = $filter; + } + if (!empty($order)) { + $params['order'] = $order; + } + + return new SitesResult( + $this->core->call('landing.site.getList', ['params' => $params]) + ); + } + + /** + * Updates site parameters. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-update.html + * + * @param int $id Site identifier + * @param array $fields Editable fields of the entity + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.update', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-update.html', + 'Method makes changes to the site.' + )] + public function update(int $id, array $fields): SiteUpdatedResult + { + return new SiteUpdatedResult( + $this->core->call('landing.site.update', [ + 'id' => $id, + 'fields' => $fields + ]) + ); + } + + /** + * Deletes a site. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-delete.html + * + * @param int $id Site identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.delete', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-delete.html', + 'Method deletes a site.' + )] + public function delete(int $id): SiteDeletedResult + { + return new SiteDeletedResult( + $this->core->call('landing.site.delete', ['id' => $id]) + ); + } + + /** + * Returns the full URL of the site(s). + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-get-public-url.html + * + * @param int|array $id Site identifier or array of identifiers + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.getPublicUrl', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-get-public-url.html', + 'Method returns the full URL of the site(s).' + )] + public function getPublicUrl($id): SiteUrlResult + { + return new SiteUrlResult( + $this->core->call('landing.site.getPublicUrl', ['id' => $id]) + ); + } + + /** + * Returns the preview image URL of the site. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-get-preview.html + * + * @param int $id Site identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.getPreview', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-get-preview.html', + 'Method returns the preview image URL of the site.' + )] + public function getPreview(int $id): SiteUrlResult + { + return new SiteUrlResult( + $this->core->call('landing.site.getPreview', ['id' => $id]) + ); + } + + /** + * Publishes the site and all its pages. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-publication.html + * + * @param int $id Site identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.publication', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-publication.html', + 'Method publishes the site and all its pages.' + )] + public function publication(int $id): SitePublishedResult + { + return new SitePublishedResult( + $this->core->call('landing.site.publication', ['id' => $id]) + ); + } + + /** + * Unpublishes the site and all its pages. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-unpublic.html + * + * @param int $id Site identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.unpublic', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-unpublic.html', + 'Method unpublishes the site and all its pages.' + )] + public function unpublic(int $id): SiteUnpublishedResult + { + return new SiteUnpublishedResult( + $this->core->call('landing.site.unpublic', ['id' => $id]) + ); + } + + /** + * Marks the site as deleted. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-mark-delete.html + * + * @param int $id Site identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.markDelete', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-mark-delete.html', + 'Method marks the site as deleted.' + )] + public function markDelete(int $id): SiteMarkedDeletedResult + { + return new SiteMarkedDeletedResult( + $this->core->call('landing.site.markDelete', ['id' => $id]) + ); + } + + /** + * Restores the site from the trash. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-mark-undelete.html + * + * @param int $id Site identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.markUnDelete', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-mark-undelete.html', + 'Method restores the site from the trash.' + )] + public function markUnDelete(int $id): SiteMarkedUnDeletedResult + { + return new SiteMarkedUnDeletedResult( + $this->core->call('landing.site.markUnDelete', ['id' => $id]) + ); + } + + /** + * Retrieves the site folders. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-get-folders.html + * + * @param int $siteId Site identifier + * @param array $filter Optional filter + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.getFolders', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-get-folders.html', + 'Method retrieves the site folders.' + )] + public function getFolders(int $siteId, array $filter = []): FoldersResult + { + return new FoldersResult( + $this->core->call('landing.site.getFolders', [ + 'siteId' => $siteId, + 'filter' => $filter + ]) + ); + } + + /** + * Adds a folder to the site. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-add-folder.html + * + * @param int $siteId Site identifier + * @param array $fields Folder fields + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.addFolder', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-add-folder.html', + 'Method adds a folder to the site.' + )] + public function addFolder(int $siteId, array $fields): FolderAddedResult + { + return new FolderAddedResult( + $this->core->call('landing.site.addFolder', [ + 'siteId' => $siteId, + 'fields' => $fields + ]) + ); + } + + /** + * Updates folder parameters. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-update-folder.html + * + * @param int $id Folder identifier + * @param array $fields Folder fields + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.updateFolder', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-update-folder.html', + 'Method updates folder parameters.' + )] + public function updateFolder(int $id, array $fields): FolderUpdatedResult + { + return new FolderUpdatedResult( + $this->core->call('landing.site.updateFolder', [ + 'id' => $id, + 'fields' => $fields + ]) + ); + } + + /** + * Publishes the site's folder. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-publication-folder.html + * + * @param int $id Folder identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.publicationFolder', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-publication-folder.html', + 'Method publishes the site\'s folder.' + )] + public function publicationFolder(int $id): FolderPublishedResult + { + return new FolderPublishedResult( + $this->core->call('landing.site.publicationFolder', ['id' => $id]) + ); + } + + /** + * Unpublishes the site's folder. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-unpublic-folder.html + * + * @param int $id Folder identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.unPublicFolder', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-unpublic-folder.html', + 'Method unpublishes the site\'s folder.' + )] + public function unPublicFolder(int $id): FolderUnpublishedResult + { + return new FolderUnpublishedResult( + $this->core->call('landing.site.unPublicFolder', ['id' => $id]) + ); + } + + /** + * Marks the folder as deleted. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-mark-folder-delete.html + * + * @param int $id Folder identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.markFolderDelete', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-mark-folder-delete.html', + 'Method marks the folder as deleted.' + )] + public function markFolderDelete(int $id): FolderMarkedDeletedResult + { + return new FolderMarkedDeletedResult( + $this->core->call('landing.site.markFolderDelete', ['id' => $id]) + ); + } + + /** + * Restores the folder from the trash. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-mark-folder-undelete.html + * + * @param int $id Folder identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.markFolderUnDelete', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-mark-folder-undelete.html', + 'Method restores the folder from the trash.' + )] + public function markFolderUnDelete(int $id): FolderMarkedUnDeletedResult + { + return new FolderMarkedUnDeletedResult( + $this->core->call('landing.site.markFolderUnDelete', ['id' => $id]) + ); + } +} \ No newline at end of file diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index c03dcd9d..16d7aa8c 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -32,6 +32,7 @@ use Bitrix24\SDK\Services\Placement\PlacementServiceBuilder; use Bitrix24\SDK\Services\Workflows\WorkflowsServiceBuilder; use Bitrix24\SDK\Services\Sale\SaleServiceBuilder; +use Bitrix24\SDK\Services\Landing\LandingServiceBuilder; use Psr\Log\LoggerInterface; class ServiceBuilder extends AbstractServiceBuilder @@ -59,6 +60,20 @@ public function getSaleScope(): SaleServiceBuilder return $this->serviceCache[__METHOD__]; } + public function getLandingScope(): LandingServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new LandingServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + public function getTaskScope(): TaskServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { diff --git a/tests/Integration/Services/Landing/Site/Service/SiteTest.php b/tests/Integration/Services/Landing/Site/Service/SiteTest.php new file mode 100644 index 00000000..756d9942 --- /dev/null +++ b/tests/Integration/Services/Landing/Site/Service/SiteTest.php @@ -0,0 +1,520 @@ + + * + * 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\Landing\Site\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Landing\Site\Result\SiteItemResult; +use Bitrix24\SDK\Services\Landing\Site\Service\Site; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; + +/** + * Class SiteTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\Landing\Site\Service + */ +#[CoversMethod(Site::class, 'add')] +#[CoversMethod(Site::class, 'getList')] +#[CoversMethod(Site::class, 'update')] +#[CoversMethod(Site::class, 'delete')] +#[CoversMethod(Site::class, 'getPublicUrl')] +#[CoversMethod(Site::class, 'getPreview')] +#[CoversMethod(Site::class, 'publication')] +#[CoversMethod(Site::class, 'unpublic')] +#[CoversMethod(Site::class, 'markDelete')] +#[CoversMethod(Site::class, 'markUnDelete')] +#[CoversMethod(Site::class, 'getFolders')] +#[CoversMethod(Site::class, 'addFolder')] +#[CoversMethod(Site::class, 'updateFolder')] +#[CoversMethod(Site::class, 'publicationFolder')] +#[CoversMethod(Site::class, 'unPublicFolder')] +#[CoversMethod(Site::class, 'markFolderDelete')] +#[CoversMethod(Site::class, 'markFolderUnDelete')] +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\Landing\Site\Service\Site::class)] +class SiteTest extends TestCase +{ + use CustomBitrix24Assertions; + + protected Site $siteService; + protected array $createdSiteIds = []; + protected array $createdFolderIds = []; + + protected function setUp(): void + { + $serviceBuilder = Fabric::getServiceBuilder(); + $this->siteService = $serviceBuilder->getLandingScope()->site(); + } + + protected function tearDown(): void + { + // Clean up created folders + foreach ($this->createdFolderIds as $folderId) { + try { + $this->siteService->markFolderDelete($folderId); + } catch (\Exception) { + // Ignore if folder doesn't exist + } + } + + // Clean up created sites + foreach ($this->createdSiteIds as $siteId) { + try { + $this->siteService->delete($siteId); + } catch (\Exception) { + // Ignore if site doesn't exist + } + } + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testAdd(): void + { + $siteFields = [ + 'TITLE' => 'Test Site ' . time(), + 'CODE' => 'test-site-' . time(), + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + $this->createdSiteIds[] = $siteId; + + self::assertGreaterThan(0, $siteId); + self::assertIsInt($siteId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetList(): void + { + // First create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for List ' . $timestamp, + 'CODE' => 'test-site-list-' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Test getList with no parameters + $sitesResult = $this->siteService->getList(); + $sites = $sitesResult->getSites(); + + self::assertIsArray($sites); + self::assertNotEmpty($sites); + + // Check that our created site is in the list + $foundSite = null; + foreach ($sites as $site) { + self::assertInstanceOf(SiteItemResult::class, $site); + if (intval($site->ID) === $siteId) { + $foundSite = $site; + break; + } + } + + self::assertNotNull($foundSite, 'Created site should be found in the list'); + self::assertEquals($siteFields['TITLE'], $foundSite->TITLE); + self::assertEquals($siteFields['CODE'], $foundSite->CODE); + self::assertEquals($siteFields['TYPE'], $foundSite->TYPE); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetListWithFilters(): void + { + // First create a test site with unique title + $timestamp = time(); + $uniqueTitle = 'Unique Test Site ' . $timestamp; + $siteFields = [ + 'TITLE' => $uniqueTitle, + 'CODE' => 'unique-test-site-' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Test getList with filters + $sitesResult = $this->siteService->getList( + ['ID', 'TITLE', 'CODE'], // select + ['TITLE' => $uniqueTitle], // filter + ['ID' => 'DESC'] // order + ); + $sites = $sitesResult->getSites(); + + self::assertIsArray($sites); + self::assertCount(1, $sites, 'Should find exactly one site with this unique title'); + + $foundSite = $sites[0]; + self::assertInstanceOf(SiteItemResult::class, $foundSite); + self::assertEquals($siteId, intval($foundSite->ID)); + self::assertEquals($uniqueTitle, $foundSite->TITLE); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testUpdate(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for Update ' . $timestamp, + 'CODE' => 'test-site-update-' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Update the site + $newTitle = 'Updated Test Site ' . $timestamp; + $updateResult = $this->siteService->update($siteId, [ + 'TITLE' => $newTitle + ]); + + self::assertTrue($updateResult->isSuccess(), 'Site update should be successful'); + + // Verify the update by getting the site list + $sitesResult = $this->siteService->getList( + ['ID', 'TITLE'], + ['ID' => $siteId] + ); + $sites = $sitesResult->getSites(); + + self::assertNotEmpty($sites); + $updatedSite = $sites[0]; + self::assertEquals($newTitle, $updatedSite->TITLE); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testDelete(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for Delete ' . $timestamp, + 'CODE' => 'test-site-delete-' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + + // Delete the site + $deleteResult = $this->siteService->delete($siteId); + self::assertTrue($deleteResult->isSuccess(), 'Site deletion should be successful'); + + // Remove from cleanup list since it's already deleted + $this->createdSiteIds = array_filter($this->createdSiteIds, fn($id) => $id !== $siteId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetPublicUrl(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for URL ' . $timestamp, + 'CODE' => 'test-site-url-' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Get public URL + $urlResult = $this->siteService->getPublicUrl($siteId); + $url = $urlResult->getUrl(); + + self::assertIsString($url); + // URL might be empty if site is not published, but method should work + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetPreview(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for Preview ' . $timestamp, + 'CODE' => 'test-site-preview-' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Get preview URL + $previewResult = $this->siteService->getPreview($siteId); + $previewUrl = $previewResult->getUrl(); + + self::assertIsString($previewUrl); + // Preview URL might be empty, but method should work + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testPublicationAndUnpublic(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for Publication ' . $timestamp, + 'CODE' => 'test-site-publication-' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Test publication + $publicationResult = $this->siteService->publication($siteId); + self::assertTrue($publicationResult->isSuccess(), 'Site publication should be successful'); + + // Test unpublish + $unpublicResult = $this->siteService->unpublic($siteId); + self::assertTrue($unpublicResult->isSuccess(), 'Site unpublish should be successful'); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testMarkDeleteAndMarkUnDelete(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for Mark Delete ' . $timestamp, + 'CODE' => 'test-site-mark-delete-' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Test mark delete + $markDeleteResult = $this->siteService->markDelete($siteId); + self::assertTrue($markDeleteResult->isSuccess(), 'Site mark delete should be successful'); + + // Test mark undelete + $markUnDeleteResult = $this->siteService->markUnDelete($siteId); + self::assertTrue($markUnDeleteResult->isSuccess(), 'Site mark undelete should be successful'); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetFolders(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for Folders ' . $timestamp, + 'CODE' => 'test-site-folders-' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Get folders (might be empty initially) + $foldersResult = $this->siteService->getFolders($siteId); + $folders = $foldersResult->getFolders(); + + self::assertIsArray($folders); + // Folders array might be empty for a new site, that's OK + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testAddFolder(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for Add Folder ' . $timestamp, + 'CODE' => 'test-site-add-folder-' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Add a folder + $folderFields = [ + 'TITLE' => 'Test Folder ' . $timestamp, + 'CODE' => 'test-folder-' . $timestamp, + 'ACTIVE' => 'Y' + ]; + + $folderAddedResult = $this->siteService->addFolder($siteId, $folderFields); + $folderId = $folderAddedResult->getId(); + $this->createdFolderIds[] = $folderId; + + self::assertGreaterThan(0, $folderId); + self::assertIsInt($folderId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testUpdateFolder(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for Update Folder ' . $timestamp, + 'CODE' => 'test-site-update-folder-' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Add a folder + $folderFields = [ + 'TITLE' => 'Test Folder for Update ' . $timestamp, + 'CODE' => 'test-folder-update-' . $timestamp, + 'ACTIVE' => 'Y' + ]; + + $folderAddedResult = $this->siteService->addFolder($siteId, $folderFields); + $folderId = $folderAddedResult->getId(); + $this->createdFolderIds[] = $folderId; + + // Update the folder + $updateResult = $this->siteService->updateFolder($folderId, [ + 'TITLE' => 'Updated Test Folder ' . $timestamp + ]); + + self::assertTrue($updateResult->isSuccess(), 'Folder update should be successful'); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testFolderPublicationMethods(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for Folder Publication ' . $timestamp, + 'CODE' => 'test-site-folder-pub-' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Add a folder + $folderFields = [ + 'TITLE' => 'Test Folder for Publication ' . $timestamp, + 'CODE' => 'test-folder-pub-' . $timestamp, + 'ACTIVE' => 'Y' + ]; + + $folderAddedResult = $this->siteService->addFolder($siteId, $folderFields); + $folderId = $folderAddedResult->getId(); + $this->createdFolderIds[] = $folderId; + + // Test folder publication + $publicationResult = $this->siteService->publicationFolder($folderId); + self::assertTrue($publicationResult->isSuccess(), 'Folder publication should be successful'); + + // Test folder unpublish + $unpublicResult = $this->siteService->unPublicFolder($folderId); + self::assertTrue($unpublicResult->isSuccess(), 'Folder unpublish should be successful'); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testFolderMarkDeleteAndUnDelete(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for Folder Delete ' . $timestamp, + 'CODE' => 'test-site-folder-delete-' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $siteAddedResult = $this->siteService->add($siteFields); + $siteId = $siteAddedResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Add a folder + $folderFields = [ + 'TITLE' => 'Test Folder for Delete ' . $timestamp, + 'CODE' => 'test-folder-delete-' . $timestamp, + 'ACTIVE' => 'Y' + ]; + + $folderAddedResult = $this->siteService->addFolder($siteId, $folderFields); + $folderId = $folderAddedResult->getId(); + $this->createdFolderIds[] = $folderId; + + // Test folder mark delete + $markDeleteResult = $this->siteService->markFolderDelete($folderId); + self::assertTrue($markDeleteResult->isSuccess(), 'Folder mark delete should be successful'); + + // Test folder mark undelete + $markUnDeleteResult = $this->siteService->markFolderUnDelete($folderId); + self::assertTrue($markUnDeleteResult->isSuccess(), 'Folder mark undelete should be successful'); + } +} \ No newline at end of file From b29a80f1b3c47505bb3603adbe10acd923672353 Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Tue, 30 Sep 2025 15:05:36 +0400 Subject: [PATCH 02/14] delete unused files; run tests --- .../Landing/Site/Result/FolderAddedResult.php | 28 ------------ .../Site/Result/FolderMarkedDeletedResult.php | 28 ------------ .../Result/FolderMarkedUnDeletedResult.php | 28 ------------ .../Site/Result/FolderPublishedResult.php | 6 +-- .../Site/Result/FolderUnpublishedResult.php | 6 +-- .../Site/Result/FolderUpdatedResult.php | 6 +-- .../Landing/Site/Result/FoldersResult.php | 4 -- .../Landing/Site/Result/SiteAddedResult.php | 28 ------------ .../Landing/Site/Result/SiteDeletedResult.php | 28 ------------ .../Site/Result/SiteMarkedUnDeletedResult.php | 6 +-- .../Site/Result/SiteUnpublishedResult.php | 6 +-- .../Landing/Site/Result/SiteUpdatedResult.php | 28 ------------ src/Services/Landing/Site/Service/Site.php | 43 +++++++++---------- .../Landing/Site/Service/SiteTest.php | 4 +- 14 files changed, 28 insertions(+), 221 deletions(-) delete mode 100644 src/Services/Landing/Site/Result/FolderAddedResult.php delete mode 100644 src/Services/Landing/Site/Result/FolderMarkedDeletedResult.php delete mode 100644 src/Services/Landing/Site/Result/FolderMarkedUnDeletedResult.php delete mode 100644 src/Services/Landing/Site/Result/SiteAddedResult.php delete mode 100644 src/Services/Landing/Site/Result/SiteDeletedResult.php delete mode 100644 src/Services/Landing/Site/Result/SiteUpdatedResult.php diff --git a/src/Services/Landing/Site/Result/FolderAddedResult.php b/src/Services/Landing/Site/Result/FolderAddedResult.php deleted file mode 100644 index 01880966..00000000 --- a/src/Services/Landing/Site/Result/FolderAddedResult.php +++ /dev/null @@ -1,28 +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\Services\Landing\Site\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class FolderAddedResult extends AbstractResult -{ - public function getId(): int - { - echo "\n FolderAddedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return (int)$this->getCoreResponse()->getResponseData()->getResult()[0]; - } -} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/FolderMarkedDeletedResult.php b/src/Services/Landing/Site/Result/FolderMarkedDeletedResult.php deleted file mode 100644 index 71dcd6db..00000000 --- a/src/Services/Landing/Site/Result/FolderMarkedDeletedResult.php +++ /dev/null @@ -1,28 +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\Services\Landing\Site\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class FolderMarkedDeletedResult extends AbstractResult -{ - public function isSuccess(): bool - { - echo "\n FolderMarkedDeletedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; - } -} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/FolderMarkedUnDeletedResult.php b/src/Services/Landing/Site/Result/FolderMarkedUnDeletedResult.php deleted file mode 100644 index df1f29df..00000000 --- a/src/Services/Landing/Site/Result/FolderMarkedUnDeletedResult.php +++ /dev/null @@ -1,28 +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\Services\Landing\Site\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class FolderMarkedUnDeletedResult extends AbstractResult -{ - public function isSuccess(): bool - { - echo "\n FolderMarkedUnDeletedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; - } -} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/FolderPublishedResult.php b/src/Services/Landing/Site/Result/FolderPublishedResult.php index 4844328e..9c59e4c1 100644 --- a/src/Services/Landing/Site/Result/FolderPublishedResult.php +++ b/src/Services/Landing/Site/Result/FolderPublishedResult.php @@ -19,10 +19,6 @@ class FolderPublishedResult extends AbstractResult { public function isSuccess(): bool { - echo "\n FolderPublishedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/FolderUnpublishedResult.php b/src/Services/Landing/Site/Result/FolderUnpublishedResult.php index 5e52044a..43c03cb5 100644 --- a/src/Services/Landing/Site/Result/FolderUnpublishedResult.php +++ b/src/Services/Landing/Site/Result/FolderUnpublishedResult.php @@ -19,10 +19,6 @@ class FolderUnpublishedResult extends AbstractResult { public function isSuccess(): bool { - echo "\n FolderUnpublishedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/FolderUpdatedResult.php b/src/Services/Landing/Site/Result/FolderUpdatedResult.php index de48823a..9bdfd67b 100644 --- a/src/Services/Landing/Site/Result/FolderUpdatedResult.php +++ b/src/Services/Landing/Site/Result/FolderUpdatedResult.php @@ -19,10 +19,6 @@ class FolderUpdatedResult extends AbstractResult { public function isSuccess(): bool { - echo "\n FolderUpdatedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/FoldersResult.php b/src/Services/Landing/Site/Result/FoldersResult.php index 65de1b83..e7258972 100644 --- a/src/Services/Landing/Site/Result/FoldersResult.php +++ b/src/Services/Landing/Site/Result/FoldersResult.php @@ -22,10 +22,6 @@ class FoldersResult extends AbstractResult */ public function getFolders(): array { - echo "\n FoldersResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - return $this->getCoreResponse()->getResponseData()->getResult(); } } \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SiteAddedResult.php b/src/Services/Landing/Site/Result/SiteAddedResult.php deleted file mode 100644 index 3aab3edd..00000000 --- a/src/Services/Landing/Site/Result/SiteAddedResult.php +++ /dev/null @@ -1,28 +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\Services\Landing\Site\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class SiteAddedResult extends AbstractResult -{ - public function getId(): int - { - echo "\n SiteAddedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return (int)$this->getCoreResponse()->getResponseData()->getResult()[0]; - } -} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SiteDeletedResult.php b/src/Services/Landing/Site/Result/SiteDeletedResult.php deleted file mode 100644 index 4d89709a..00000000 --- a/src/Services/Landing/Site/Result/SiteDeletedResult.php +++ /dev/null @@ -1,28 +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\Services\Landing\Site\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class SiteDeletedResult extends AbstractResult -{ - public function isSuccess(): bool - { - echo "\n SiteDeletedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; - } -} \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SiteMarkedUnDeletedResult.php b/src/Services/Landing/Site/Result/SiteMarkedUnDeletedResult.php index 9bacda6a..53d8fea2 100644 --- a/src/Services/Landing/Site/Result/SiteMarkedUnDeletedResult.php +++ b/src/Services/Landing/Site/Result/SiteMarkedUnDeletedResult.php @@ -19,10 +19,6 @@ class SiteMarkedUnDeletedResult extends AbstractResult { public function isSuccess(): bool { - echo "\n SiteMarkedUnDeletedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SiteUnpublishedResult.php b/src/Services/Landing/Site/Result/SiteUnpublishedResult.php index c4cf0a66..1d726909 100644 --- a/src/Services/Landing/Site/Result/SiteUnpublishedResult.php +++ b/src/Services/Landing/Site/Result/SiteUnpublishedResult.php @@ -19,10 +19,6 @@ class SiteUnpublishedResult extends AbstractResult { public function isSuccess(): bool { - echo "\n SiteUnpublishedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/Landing/Site/Result/SiteUpdatedResult.php b/src/Services/Landing/Site/Result/SiteUpdatedResult.php deleted file mode 100644 index 94c5e02d..00000000 --- a/src/Services/Landing/Site/Result/SiteUpdatedResult.php +++ /dev/null @@ -1,28 +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\Services\Landing\Site\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class SiteUpdatedResult extends AbstractResult -{ - public function isSuccess(): bool - { - echo "\n SiteUpdatedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return $this->getCoreResponse()->getResponseData()->getResult()[0] === true; - } -} \ No newline at end of file diff --git a/src/Services/Landing/Site/Service/Site.php b/src/Services/Landing/Site/Service/Site.php index 47c7b15c..a8b1d375 100644 --- a/src/Services/Landing/Site/Service/Site.php +++ b/src/Services/Landing/Site/Service/Site.php @@ -19,23 +19,20 @@ 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\UpdatedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; use Bitrix24\SDK\Services\AbstractService; -use Bitrix24\SDK\Services\Landing\Site\Result\SiteAddedResult; use Bitrix24\SDK\Services\Landing\Site\Result\SitesResult; -use Bitrix24\SDK\Services\Landing\Site\Result\SiteUpdatedResult; -use Bitrix24\SDK\Services\Landing\Site\Result\SiteDeletedResult; use Bitrix24\SDK\Services\Landing\Site\Result\SiteUrlResult; use Bitrix24\SDK\Services\Landing\Site\Result\SitePublishedResult; use Bitrix24\SDK\Services\Landing\Site\Result\SiteUnpublishedResult; use Bitrix24\SDK\Services\Landing\Site\Result\SiteMarkedDeletedResult; use Bitrix24\SDK\Services\Landing\Site\Result\SiteMarkedUnDeletedResult; use Bitrix24\SDK\Services\Landing\Site\Result\FoldersResult; -use Bitrix24\SDK\Services\Landing\Site\Result\FolderAddedResult; use Bitrix24\SDK\Services\Landing\Site\Result\FolderUpdatedResult; use Bitrix24\SDK\Services\Landing\Site\Result\FolderPublishedResult; use Bitrix24\SDK\Services\Landing\Site\Result\FolderUnpublishedResult; -use Bitrix24\SDK\Services\Landing\Site\Result\FolderMarkedDeletedResult; -use Bitrix24\SDK\Services\Landing\Site\Result\FolderMarkedUnDeletedResult; use Psr\Log\LoggerInterface; #[ApiServiceMetadata(new Scope(['landing']))] @@ -61,9 +58,9 @@ public function __construct(CoreInterface $core, LoggerInterface $logger) 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-add.html', 'Method creates a new site.' )] - public function add(array $fields): SiteAddedResult + public function add(array $fields): AddedItemResult { - return new SiteAddedResult( + return new AddedItemResult( $this->core->call('landing.site.add', ['fields' => $fields]) ); } @@ -119,9 +116,9 @@ public function getList(array $select = [], array $filter = [], array $order = [ 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-update.html', 'Method makes changes to the site.' )] - public function update(int $id, array $fields): SiteUpdatedResult + public function update(int $id, array $fields): UpdatedItemResult { - return new SiteUpdatedResult( + return new UpdatedItemResult( $this->core->call('landing.site.update', [ 'id' => $id, 'fields' => $fields @@ -144,9 +141,9 @@ public function update(int $id, array $fields): SiteUpdatedResult 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-delete.html', 'Method deletes a site.' )] - public function delete(int $id): SiteDeletedResult + public function delete(int $id): DeletedItemResult { - return new SiteDeletedResult( + return new DeletedItemResult( $this->core->call('landing.site.delete', ['id' => $id]) ); } @@ -325,9 +322,9 @@ public function getFolders(int $siteId, array $filter = []): FoldersResult 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-add-folder.html', 'Method adds a folder to the site.' )] - public function addFolder(int $siteId, array $fields): FolderAddedResult + public function addFolder(int $siteId, array $fields): AddedItemResult { - return new FolderAddedResult( + return new AddedItemResult( $this->core->call('landing.site.addFolder', [ 'siteId' => $siteId, 'fields' => $fields @@ -340,6 +337,7 @@ public function addFolder(int $siteId, array $fields): FolderAddedResult * * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-update-folder.html * + * @param int $siteId Site identifier * @param int $id Folder identifier * @param array $fields Folder fields * @@ -351,11 +349,12 @@ public function addFolder(int $siteId, array $fields): FolderAddedResult 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-update-folder.html', 'Method updates folder parameters.' )] - public function updateFolder(int $id, array $fields): FolderUpdatedResult + public function updateFolder(int $siteId, int $id, array $fields): FolderUpdatedResult { return new FolderUpdatedResult( $this->core->call('landing.site.updateFolder', [ - 'id' => $id, + 'siteId' => $siteId, + 'folderId' => $id, 'fields' => $fields ]) ); @@ -379,7 +378,7 @@ public function updateFolder(int $id, array $fields): FolderUpdatedResult public function publicationFolder(int $id): FolderPublishedResult { return new FolderPublishedResult( - $this->core->call('landing.site.publicationFolder', ['id' => $id]) + $this->core->call('landing.site.publicationFolder', ['folderId' => $id]) ); } @@ -401,7 +400,7 @@ public function publicationFolder(int $id): FolderPublishedResult public function unPublicFolder(int $id): FolderUnpublishedResult { return new FolderUnpublishedResult( - $this->core->call('landing.site.unPublicFolder', ['id' => $id]) + $this->core->call('landing.site.unPublicFolder', ['folderId' => $id]) ); } @@ -420,9 +419,9 @@ public function unPublicFolder(int $id): FolderUnpublishedResult 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-mark-folder-delete.html', 'Method marks the folder as deleted.' )] - public function markFolderDelete(int $id): FolderMarkedDeletedResult + public function markFolderDelete(int $id): DeletedItemResult { - return new FolderMarkedDeletedResult( + return new DeletedItemResult( $this->core->call('landing.site.markFolderDelete', ['id' => $id]) ); } @@ -442,9 +441,9 @@ public function markFolderDelete(int $id): FolderMarkedDeletedResult 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-mark-folder-undelete.html', 'Method restores the folder from the trash.' )] - public function markFolderUnDelete(int $id): FolderMarkedUnDeletedResult + public function markFolderUnDelete(int $id): DeletedItemResult { - return new FolderMarkedUnDeletedResult( + return new DeletedItemResult( $this->core->call('landing.site.markFolderUnDelete', ['id' => $id]) ); } diff --git a/tests/Integration/Services/Landing/Site/Service/SiteTest.php b/tests/Integration/Services/Landing/Site/Service/SiteTest.php index 756d9942..5819b98a 100644 --- a/tests/Integration/Services/Landing/Site/Service/SiteTest.php +++ b/tests/Integration/Services/Landing/Site/Service/SiteTest.php @@ -137,7 +137,7 @@ public function testGetList(): void self::assertNotNull($foundSite, 'Created site should be found in the list'); self::assertEquals($siteFields['TITLE'], $foundSite->TITLE); - self::assertEquals($siteFields['CODE'], $foundSite->CODE); + self::assertStringContainsString($siteFields['CODE'], $foundSite->CODE); self::assertEquals($siteFields['TYPE'], $foundSite->TYPE); } @@ -435,7 +435,7 @@ public function testUpdateFolder(): void $this->createdFolderIds[] = $folderId; // Update the folder - $updateResult = $this->siteService->updateFolder($folderId, [ + $updateResult = $this->siteService->updateFolder($siteId, $folderId, [ 'TITLE' => 'Updated Test Folder ' . $timestamp ]); From 93108a9d5c29b0e95ab0a4fd917e4aff72b5b056 Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Tue, 30 Sep 2025 15:12:58 +0400 Subject: [PATCH 03/14] run linters; update changelog --- .php-cs-fixer.php | 1 + CHANGELOG.md | 19 +++ phpstan.neon.dist | 1 + rector.php | 2 + .../Landing/LandingServiceBuilder.php | 2 +- .../Site/Result/FolderPublishedResult.php | 2 +- .../Site/Result/FolderUnpublishedResult.php | 2 +- .../Site/Result/FolderUpdatedResult.php | 2 +- .../Landing/Site/Result/FoldersResult.php | 5 +- .../Landing/Site/Result/SiteItemResult.php | 2 +- .../Site/Result/SiteMarkedDeletedResult.php | 2 +- .../Site/Result/SiteMarkedUnDeletedResult.php | 2 +- .../Site/Result/SitePublishedResult.php | 2 +- .../Site/Result/SiteUnpublishedResult.php | 2 +- .../Landing/Site/Result/SitesResult.php | 2 +- src/Services/Landing/Site/Service/Site.php | 14 ++- .../Landing/Site/Service/SiteTest.php | 116 +++++++++--------- 17 files changed, 101 insertions(+), 77 deletions(-) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index ee2ef05e..15e9664c 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -17,6 +17,7 @@ ->in(__DIR__ . '/src/Services/CRM/Timeline/') ->in(__DIR__ . '/src/Services/Entity/Section/') ->in(__DIR__ . '/src/Services/Department/') + ->in(__DIR__ . '/src/Services/Landing/') ->in(__DIR__ . '/src/Services/Sale/') ->in(__DIR__ . '/src/Services/Task/') ->in(__DIR__ . '/src/Services/Sale/') diff --git a/CHANGELOG.md b/CHANGELOG.md index 0400c512..14a19c50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,25 @@ ### Added +- 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 + - `getList` retrieves a list of sites + - `update` updates site parameters + - `delete` deletes a site + - `getPublicUrl` returns the full URL of the site(s) + - `getPreview` returns the preview image URL of the site + - `publication` publishes the site and all its pages + - `unpublic` unpublishes the site and all its pages + - `markDelete` marks the site as deleted + - `markUnDelete` restores the site from the trash + - `getFolders` retrieves the site folders + - `addFolder` adds a folder to the site + - `updateFolder` updates folder parameters + - `publicationFolder` publishes the site's folder + - `unPublicFolder` unpublishes the site's folder + - `markFolderDelete` marks the folder as deleted + - `markFolderUnDelete` restores the folder from the trash - Added service `Services\Sale\Payment\Service\Payment` with support methods, see [sale.payment.* methods](https://github.com/bitrix24/b24phpsdk/issues/248): - `add` adds a payment diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 3bead767..e9f346fd 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -29,6 +29,7 @@ parameters: - tests/Integration/Services/CRM/Requisites - tests/Integration/Services/Task - tests/Integration/Services/Sale + - tests/Integration/Services/Landing excludePaths: - tests/Integration/Services/CRM/Requisites/Service/RequisiteUserfieldUseCaseTest.php - tests/Integration/Services/CRM/Status diff --git a/rector.php b/rector.php index 4b458e5f..8c037cec 100644 --- a/rector.php +++ b/rector.php @@ -62,6 +62,8 @@ __DIR__ . '/tests/Integration/Services/Task', __DIR__ . '/src/Services/Sale', __DIR__ . '/tests/Integration/Services/Sale', + __DIR__ . '/src/Services/Landing', + __DIR__ . '/tests/Integration/Services/Landing', __DIR__ . '/tests/Unit/', ]) ->withCache(cacheDirectory: __DIR__ . '.cache/rector') diff --git a/src/Services/Landing/LandingServiceBuilder.php b/src/Services/Landing/LandingServiceBuilder.php index 3e864ff2..ca665552 100644 --- a/src/Services/Landing/LandingServiceBuilder.php +++ b/src/Services/Landing/LandingServiceBuilder.php @@ -39,4 +39,4 @@ public function site(): Site\Service\Site return $this->serviceCache[__METHOD__]; } -} \ No newline at end of file +} diff --git a/src/Services/Landing/Site/Result/FolderPublishedResult.php b/src/Services/Landing/Site/Result/FolderPublishedResult.php index 9c59e4c1..5cc9d231 100644 --- a/src/Services/Landing/Site/Result/FolderPublishedResult.php +++ b/src/Services/Landing/Site/Result/FolderPublishedResult.php @@ -21,4 +21,4 @@ public function isSuccess(): bool { return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } -} \ No newline at end of file +} diff --git a/src/Services/Landing/Site/Result/FolderUnpublishedResult.php b/src/Services/Landing/Site/Result/FolderUnpublishedResult.php index 43c03cb5..300a48ec 100644 --- a/src/Services/Landing/Site/Result/FolderUnpublishedResult.php +++ b/src/Services/Landing/Site/Result/FolderUnpublishedResult.php @@ -21,4 +21,4 @@ public function isSuccess(): bool { return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } -} \ No newline at end of file +} diff --git a/src/Services/Landing/Site/Result/FolderUpdatedResult.php b/src/Services/Landing/Site/Result/FolderUpdatedResult.php index 9bdfd67b..e7e885c1 100644 --- a/src/Services/Landing/Site/Result/FolderUpdatedResult.php +++ b/src/Services/Landing/Site/Result/FolderUpdatedResult.php @@ -21,4 +21,4 @@ public function isSuccess(): bool { return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } -} \ No newline at end of file +} diff --git a/src/Services/Landing/Site/Result/FoldersResult.php b/src/Services/Landing/Site/Result/FoldersResult.php index e7258972..84ecc73c 100644 --- a/src/Services/Landing/Site/Result/FoldersResult.php +++ b/src/Services/Landing/Site/Result/FoldersResult.php @@ -17,11 +17,8 @@ class FoldersResult extends AbstractResult { - /** - * @return array - */ public function getFolders(): array { return $this->getCoreResponse()->getResponseData()->getResult(); } -} \ No newline at end of file +} diff --git a/src/Services/Landing/Site/Result/SiteItemResult.php b/src/Services/Landing/Site/Result/SiteItemResult.php index 517864bc..b71c7e27 100644 --- a/src/Services/Landing/Site/Result/SiteItemResult.php +++ b/src/Services/Landing/Site/Result/SiteItemResult.php @@ -39,4 +39,4 @@ */ class SiteItemResult extends AbstractItem { -} \ No newline at end of file +} diff --git a/src/Services/Landing/Site/Result/SiteMarkedDeletedResult.php b/src/Services/Landing/Site/Result/SiteMarkedDeletedResult.php index 9d469d36..38dbaac5 100644 --- a/src/Services/Landing/Site/Result/SiteMarkedDeletedResult.php +++ b/src/Services/Landing/Site/Result/SiteMarkedDeletedResult.php @@ -21,4 +21,4 @@ public function isSuccess(): bool { return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } -} \ No newline at end of file +} diff --git a/src/Services/Landing/Site/Result/SiteMarkedUnDeletedResult.php b/src/Services/Landing/Site/Result/SiteMarkedUnDeletedResult.php index 53d8fea2..338fe93d 100644 --- a/src/Services/Landing/Site/Result/SiteMarkedUnDeletedResult.php +++ b/src/Services/Landing/Site/Result/SiteMarkedUnDeletedResult.php @@ -21,4 +21,4 @@ public function isSuccess(): bool { return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } -} \ No newline at end of file +} diff --git a/src/Services/Landing/Site/Result/SitePublishedResult.php b/src/Services/Landing/Site/Result/SitePublishedResult.php index 6e37cc03..ee974d3b 100644 --- a/src/Services/Landing/Site/Result/SitePublishedResult.php +++ b/src/Services/Landing/Site/Result/SitePublishedResult.php @@ -21,4 +21,4 @@ public function isSuccess(): bool { return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } -} \ No newline at end of file +} diff --git a/src/Services/Landing/Site/Result/SiteUnpublishedResult.php b/src/Services/Landing/Site/Result/SiteUnpublishedResult.php index 1d726909..d3b99684 100644 --- a/src/Services/Landing/Site/Result/SiteUnpublishedResult.php +++ b/src/Services/Landing/Site/Result/SiteUnpublishedResult.php @@ -21,4 +21,4 @@ public function isSuccess(): bool { return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } -} \ No newline at end of file +} diff --git a/src/Services/Landing/Site/Result/SitesResult.php b/src/Services/Landing/Site/Result/SitesResult.php index ff6df977..238e3168 100644 --- a/src/Services/Landing/Site/Result/SitesResult.php +++ b/src/Services/Landing/Site/Result/SitesResult.php @@ -29,4 +29,4 @@ public function getSites(): array return $result; } -} \ No newline at end of file +} diff --git a/src/Services/Landing/Site/Service/Site.php b/src/Services/Landing/Site/Service/Site.php index a8b1d375..9da0718a 100644 --- a/src/Services/Landing/Site/Service/Site.php +++ b/src/Services/Landing/Site/Service/Site.php @@ -85,13 +85,15 @@ public function add(array $fields): AddedItemResult public function getList(array $select = [], array $filter = [], array $order = []): SitesResult { $params = []; - if (!empty($select)) { + if ($select !== []) { $params['select'] = $select; } - if (!empty($filter)) { + + if ($filter !== []) { $params['filter'] = $filter; } - if (!empty($order)) { + + if ($order !== []) { $params['order'] = $order; } @@ -373,7 +375,7 @@ public function updateFolder(int $siteId, int $id, array $fields): FolderUpdated #[ApiEndpointMetadata( 'landing.site.publicationFolder', 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-publication-folder.html', - 'Method publishes the site\'s folder.' + "Method publishes the site's folder." )] public function publicationFolder(int $id): FolderPublishedResult { @@ -395,7 +397,7 @@ public function publicationFolder(int $id): FolderPublishedResult #[ApiEndpointMetadata( 'landing.site.unPublicFolder', 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-unpublic-folder.html', - 'Method unpublishes the site\'s folder.' + "Method unpublishes the site's folder." )] public function unPublicFolder(int $id): FolderUnpublishedResult { @@ -447,4 +449,4 @@ public function markFolderUnDelete(int $id): DeletedItemResult $this->core->call('landing.site.markFolderUnDelete', ['id' => $id]) ); } -} \ No newline at end of file +} diff --git a/tests/Integration/Services/Landing/Site/Service/SiteTest.php b/tests/Integration/Services/Landing/Site/Service/SiteTest.php index 5819b98a..dff4cf56 100644 --- a/tests/Integration/Services/Landing/Site/Service/SiteTest.php +++ b/tests/Integration/Services/Landing/Site/Service/SiteTest.php @@ -50,7 +50,9 @@ class SiteTest extends TestCase use CustomBitrix24Assertions; protected Site $siteService; + protected array $createdSiteIds = []; + protected array $createdFolderIds = []; protected function setUp(): void @@ -62,18 +64,18 @@ protected function setUp(): void protected function tearDown(): void { // Clean up created folders - foreach ($this->createdFolderIds as $folderId) { + foreach ($this->createdFolderIds as $createdFolderId) { try { - $this->siteService->markFolderDelete($folderId); + $this->siteService->markFolderDelete($createdFolderId); } catch (\Exception) { // Ignore if folder doesn't exist } } // Clean up created sites - foreach ($this->createdSiteIds as $siteId) { + foreach ($this->createdSiteIds as $createdSiteId) { try { - $this->siteService->delete($siteId); + $this->siteService->delete($createdSiteId); } catch (\Exception) { // Ignore if site doesn't exist } @@ -92,8 +94,8 @@ public function testAdd(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); $this->createdSiteIds[] = $siteId; self::assertGreaterThan(0, $siteId); @@ -114,8 +116,8 @@ public function testGetList(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); $this->createdSiteIds[] = $siteId; // Test getList with no parameters @@ -156,8 +158,8 @@ public function testGetListWithFilters(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); $this->createdSiteIds[] = $siteId; // Test getList with filters @@ -191,17 +193,17 @@ public function testUpdate(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); $this->createdSiteIds[] = $siteId; // Update the site $newTitle = 'Updated Test Site ' . $timestamp; - $updateResult = $this->siteService->update($siteId, [ + $updatedItemResult = $this->siteService->update($siteId, [ 'TITLE' => $newTitle ]); - self::assertTrue($updateResult->isSuccess(), 'Site update should be successful'); + self::assertTrue($updatedItemResult->isSuccess(), 'Site update should be successful'); // Verify the update by getting the site list $sitesResult = $this->siteService->getList( @@ -229,15 +231,15 @@ public function testDelete(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); // Delete the site - $deleteResult = $this->siteService->delete($siteId); - self::assertTrue($deleteResult->isSuccess(), 'Site deletion should be successful'); + $deletedItemResult = $this->siteService->delete($siteId); + self::assertTrue($deletedItemResult->isSuccess(), 'Site deletion should be successful'); // Remove from cleanup list since it's already deleted - $this->createdSiteIds = array_filter($this->createdSiteIds, fn($id) => $id !== $siteId); + $this->createdSiteIds = array_filter($this->createdSiteIds, fn($id): bool => $id !== $siteId); } /** @@ -254,13 +256,13 @@ public function testGetPublicUrl(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); $this->createdSiteIds[] = $siteId; // Get public URL - $urlResult = $this->siteService->getPublicUrl($siteId); - $url = $urlResult->getUrl(); + $siteUrlResult = $this->siteService->getPublicUrl($siteId); + $url = $siteUrlResult->getUrl(); self::assertIsString($url); // URL might be empty if site is not published, but method should work @@ -280,13 +282,13 @@ public function testGetPreview(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); $this->createdSiteIds[] = $siteId; // Get preview URL - $previewResult = $this->siteService->getPreview($siteId); - $previewUrl = $previewResult->getUrl(); + $siteUrlResult = $this->siteService->getPreview($siteId); + $previewUrl = $siteUrlResult->getUrl(); self::assertIsString($previewUrl); // Preview URL might be empty, but method should work @@ -306,17 +308,17 @@ public function testPublicationAndUnpublic(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); $this->createdSiteIds[] = $siteId; // Test publication - $publicationResult = $this->siteService->publication($siteId); - self::assertTrue($publicationResult->isSuccess(), 'Site publication should be successful'); + $sitePublishedResult = $this->siteService->publication($siteId); + self::assertTrue($sitePublishedResult->isSuccess(), 'Site publication should be successful'); // Test unpublish - $unpublicResult = $this->siteService->unpublic($siteId); - self::assertTrue($unpublicResult->isSuccess(), 'Site unpublish should be successful'); + $siteUnpublishedResult = $this->siteService->unpublic($siteId); + self::assertTrue($siteUnpublishedResult->isSuccess(), 'Site unpublish should be successful'); } /** @@ -333,17 +335,17 @@ public function testMarkDeleteAndMarkUnDelete(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); $this->createdSiteIds[] = $siteId; // Test mark delete - $markDeleteResult = $this->siteService->markDelete($siteId); - self::assertTrue($markDeleteResult->isSuccess(), 'Site mark delete should be successful'); + $siteMarkedDeletedResult = $this->siteService->markDelete($siteId); + self::assertTrue($siteMarkedDeletedResult->isSuccess(), 'Site mark delete should be successful'); // Test mark undelete - $markUnDeleteResult = $this->siteService->markUnDelete($siteId); - self::assertTrue($markUnDeleteResult->isSuccess(), 'Site mark undelete should be successful'); + $siteMarkedUnDeletedResult = $this->siteService->markUnDelete($siteId); + self::assertTrue($siteMarkedUnDeletedResult->isSuccess(), 'Site mark undelete should be successful'); } /** @@ -360,8 +362,8 @@ public function testGetFolders(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); $this->createdSiteIds[] = $siteId; // Get folders (might be empty initially) @@ -386,8 +388,8 @@ public function testAddFolder(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); $this->createdSiteIds[] = $siteId; // Add a folder @@ -419,8 +421,8 @@ public function testUpdateFolder(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); $this->createdSiteIds[] = $siteId; // Add a folder @@ -435,11 +437,11 @@ public function testUpdateFolder(): void $this->createdFolderIds[] = $folderId; // Update the folder - $updateResult = $this->siteService->updateFolder($siteId, $folderId, [ + $folderUpdatedResult = $this->siteService->updateFolder($siteId, $folderId, [ 'TITLE' => 'Updated Test Folder ' . $timestamp ]); - self::assertTrue($updateResult->isSuccess(), 'Folder update should be successful'); + self::assertTrue($folderUpdatedResult->isSuccess(), 'Folder update should be successful'); } /** @@ -456,8 +458,8 @@ public function testFolderPublicationMethods(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); $this->createdSiteIds[] = $siteId; // Add a folder @@ -472,12 +474,12 @@ public function testFolderPublicationMethods(): void $this->createdFolderIds[] = $folderId; // Test folder publication - $publicationResult = $this->siteService->publicationFolder($folderId); - self::assertTrue($publicationResult->isSuccess(), 'Folder publication should be successful'); + $folderPublishedResult = $this->siteService->publicationFolder($folderId); + self::assertTrue($folderPublishedResult->isSuccess(), 'Folder publication should be successful'); // Test folder unpublish - $unpublicResult = $this->siteService->unPublicFolder($folderId); - self::assertTrue($unpublicResult->isSuccess(), 'Folder unpublish should be successful'); + $folderUnpublishedResult = $this->siteService->unPublicFolder($folderId); + self::assertTrue($folderUnpublishedResult->isSuccess(), 'Folder unpublish should be successful'); } /** @@ -494,8 +496,8 @@ public function testFolderMarkDeleteAndUnDelete(): void 'TYPE' => 'PAGE' ]; - $siteAddedResult = $this->siteService->add($siteFields); - $siteId = $siteAddedResult->getId(); + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); $this->createdSiteIds[] = $siteId; // Add a folder @@ -510,8 +512,8 @@ public function testFolderMarkDeleteAndUnDelete(): void $this->createdFolderIds[] = $folderId; // Test folder mark delete - $markDeleteResult = $this->siteService->markFolderDelete($folderId); - self::assertTrue($markDeleteResult->isSuccess(), 'Folder mark delete should be successful'); + $deletedItemResult = $this->siteService->markFolderDelete($folderId); + self::assertTrue($deletedItemResult->isSuccess(), 'Folder mark delete should be successful'); // Test folder mark undelete $markUnDeleteResult = $this->siteService->markFolderUnDelete($folderId); From f84f33f1b2a92a37dea1e30c60ae4ee34b383ef5 Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Tue, 30 Sep 2025 17:08:41 +0400 Subject: [PATCH 04/14] add two methods --- CHANGELOG.md | 2 + .../Result/SiteAdditionalFieldsResult.php | 36 ++++ .../Landing/Site/Result/SiteExportResult.php | 36 ++++ src/Services/Landing/Site/Service/Site.php | 52 ++++++ .../Landing/Site/Service/SiteTest.php | 171 ++++++++++++++++-- 5 files changed, 278 insertions(+), 19 deletions(-) create mode 100644 src/Services/Landing/Site/Result/SiteAdditionalFieldsResult.php create mode 100644 src/Services/Landing/Site/Result/SiteExportResult.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 3beb8a58..285464cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ - `unpublic` unpublishes the site and all its pages - `markDelete` marks the site as deleted - `markUnDelete` restores the site from the trash + - `getAdditionalFields` returns additional fields of the site + - `fullExport` exports the site to ZIP archive - `getFolders` retrieves the site folders - `addFolder` adds a folder to the site - `updateFolder` updates folder parameters diff --git a/src/Services/Landing/Site/Result/SiteAdditionalFieldsResult.php b/src/Services/Landing/Site/Result/SiteAdditionalFieldsResult.php new file mode 100644 index 00000000..00d505cf --- /dev/null +++ b/src/Services/Landing/Site/Result/SiteAdditionalFieldsResult.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\Landing\Site\Result; + +use Bitrix24\SDK\Core\Response\Response; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class SiteAdditionalFieldsResult + */ +class SiteAdditionalFieldsResult extends AbstractResult +{ + public function __construct(Response $response) + { + parent::__construct($response); + } + + /** + * Get additional fields data + */ + public function getAdditionalFields(): array + { + return $this->getCoreResponse()->getResponseData()->getResult(); + } +} diff --git a/src/Services/Landing/Site/Result/SiteExportResult.php b/src/Services/Landing/Site/Result/SiteExportResult.php new file mode 100644 index 00000000..caf2f99d --- /dev/null +++ b/src/Services/Landing/Site/Result/SiteExportResult.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\Landing\Site\Result; + +use Bitrix24\SDK\Core\Response\Response; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class SiteExportResult + */ +class SiteExportResult extends AbstractResult +{ + public function __construct(Response $response) + { + parent::__construct($response); + } + + /** + * Get export data (typically contains download URL or file data) + */ + public function getExportData(): array + { + return $this->getCoreResponse()->getResponseData()->getResult(); + } +} diff --git a/src/Services/Landing/Site/Service/Site.php b/src/Services/Landing/Site/Service/Site.php index 9da0718a..bd3f2f33 100644 --- a/src/Services/Landing/Site/Service/Site.php +++ b/src/Services/Landing/Site/Service/Site.php @@ -33,6 +33,8 @@ use Bitrix24\SDK\Services\Landing\Site\Result\FolderUpdatedResult; use Bitrix24\SDK\Services\Landing\Site\Result\FolderPublishedResult; use Bitrix24\SDK\Services\Landing\Site\Result\FolderUnpublishedResult; +use Bitrix24\SDK\Services\Landing\Site\Result\SiteAdditionalFieldsResult; +use Bitrix24\SDK\Services\Landing\Site\Result\SiteExportResult; use Psr\Log\LoggerInterface; #[ApiServiceMetadata(new Scope(['landing']))] @@ -282,6 +284,56 @@ public function markUnDelete(int $id): SiteMarkedUnDeletedResult ); } + /** + * Returns additional fields of the site. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-getadditionalfields.html + * + * @param int $id Site identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.getAdditionalFields', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-getadditionalfields.html', + 'Method returns additional fields of the site.' + )] + public function getAdditionalFields(int $id): SiteAdditionalFieldsResult + { + return new SiteAdditionalFieldsResult( + $this->core->call('landing.site.getAdditionalFields', ['id' => $id]) + ); + } + + /** + * Exports the site to ZIP archive. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-fullexport.html + * + * @param int $id Site identifier + * @param array $params Optional export parameters + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.site.fullExport', + 'https://apidocs.bitrix24.com/api-reference/landing/site/landing-site-fullexport.html', + 'Method exports the site to ZIP archive.' + )] + public function fullExport(int $id, array $params = []): SiteExportResult + { + $requestParams = ['id' => $id]; + if ($params !== []) { + $requestParams['params'] = $params; + } + + return new SiteExportResult( + $this->core->call('landing.site.fullExport', $requestParams) + ); + } + /** * Retrieves the site folders. * diff --git a/tests/Integration/Services/Landing/Site/Service/SiteTest.php b/tests/Integration/Services/Landing/Site/Service/SiteTest.php index dff4cf56..83a30a2f 100644 --- a/tests/Integration/Services/Landing/Site/Service/SiteTest.php +++ b/tests/Integration/Services/Landing/Site/Service/SiteTest.php @@ -44,6 +44,8 @@ #[CoversMethod(Site::class, 'unPublicFolder')] #[CoversMethod(Site::class, 'markFolderDelete')] #[CoversMethod(Site::class, 'markFolderUnDelete')] +#[CoversMethod(Site::class, 'getAdditionalFields')] +#[CoversMethod(Site::class, 'fullExport')] #[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\Landing\Site\Service\Site::class)] class SiteTest extends TestCase { @@ -90,7 +92,7 @@ public function testAdd(): void { $siteFields = [ 'TITLE' => 'Test Site ' . time(), - 'CODE' => 'test-site-' . time(), + 'CODE' => 'testsite' . time(), 'TYPE' => 'PAGE' ]; @@ -112,7 +114,7 @@ public function testGetList(): void $timestamp = time(); $siteFields = [ 'TITLE' => 'Test Site for List ' . $timestamp, - 'CODE' => 'test-site-list-' . $timestamp, + 'CODE' => 'testsitelist' . $timestamp, 'TYPE' => 'PAGE' ]; @@ -154,7 +156,7 @@ public function testGetListWithFilters(): void $uniqueTitle = 'Unique Test Site ' . $timestamp; $siteFields = [ 'TITLE' => $uniqueTitle, - 'CODE' => 'unique-test-site-' . $timestamp, + 'CODE' => 'uniquetestsite' . $timestamp, 'TYPE' => 'PAGE' ]; @@ -189,7 +191,7 @@ public function testUpdate(): void $timestamp = time(); $siteFields = [ 'TITLE' => 'Test Site for Update ' . $timestamp, - 'CODE' => 'test-site-update-' . $timestamp, + 'CODE' => 'testsiteupdate' . $timestamp, 'TYPE' => 'PAGE' ]; @@ -227,7 +229,7 @@ public function testDelete(): void $timestamp = time(); $siteFields = [ 'TITLE' => 'Test Site for Delete ' . $timestamp, - 'CODE' => 'test-site-delete-' . $timestamp, + 'CODE' => 'testsite' . $timestamp, 'TYPE' => 'PAGE' ]; @@ -252,7 +254,7 @@ public function testGetPublicUrl(): void $timestamp = time(); $siteFields = [ 'TITLE' => 'Test Site for URL ' . $timestamp, - 'CODE' => 'test-site-url-' . $timestamp, + 'CODE' => 'testsite' . $timestamp, 'TYPE' => 'PAGE' ]; @@ -278,7 +280,7 @@ public function testGetPreview(): void $timestamp = time(); $siteFields = [ 'TITLE' => 'Test Site for Preview ' . $timestamp, - 'CODE' => 'test-site-preview-' . $timestamp, + 'CODE' => 'testsite' . $timestamp, 'TYPE' => 'PAGE' ]; @@ -304,7 +306,7 @@ public function testPublicationAndUnpublic(): void $timestamp = time(); $siteFields = [ 'TITLE' => 'Test Site for Publication ' . $timestamp, - 'CODE' => 'test-site-publication-' . $timestamp, + 'CODE' => 'testsite' . $timestamp, 'TYPE' => 'PAGE' ]; @@ -331,7 +333,7 @@ public function testMarkDeleteAndMarkUnDelete(): void $timestamp = time(); $siteFields = [ 'TITLE' => 'Test Site for Mark Delete ' . $timestamp, - 'CODE' => 'test-site-mark-delete-' . $timestamp, + 'CODE' => 'testsite' . $timestamp, 'TYPE' => 'PAGE' ]; @@ -358,7 +360,7 @@ public function testGetFolders(): void $timestamp = time(); $siteFields = [ 'TITLE' => 'Test Site for Folders ' . $timestamp, - 'CODE' => 'test-site-folders-' . $timestamp, + 'CODE' => 'testsite' . $timestamp, 'TYPE' => 'PAGE' ]; @@ -384,7 +386,7 @@ public function testAddFolder(): void $timestamp = time(); $siteFields = [ 'TITLE' => 'Test Site for Add Folder ' . $timestamp, - 'CODE' => 'test-site-add-folder-' . $timestamp, + 'CODE' => 'testsite' . $timestamp, 'TYPE' => 'PAGE' ]; @@ -395,7 +397,7 @@ public function testAddFolder(): void // Add a folder $folderFields = [ 'TITLE' => 'Test Folder ' . $timestamp, - 'CODE' => 'test-folder-' . $timestamp, + 'CODE' => 'testfolder' . $timestamp, 'ACTIVE' => 'Y' ]; @@ -417,7 +419,7 @@ public function testUpdateFolder(): void $timestamp = time(); $siteFields = [ 'TITLE' => 'Test Site for Update Folder ' . $timestamp, - 'CODE' => 'test-site-update-folder-' . $timestamp, + 'CODE' => 'testsite' . $timestamp, 'TYPE' => 'PAGE' ]; @@ -428,7 +430,7 @@ public function testUpdateFolder(): void // Add a folder $folderFields = [ 'TITLE' => 'Test Folder for Update ' . $timestamp, - 'CODE' => 'test-folder-update-' . $timestamp, + 'CODE' => 'testfolder' . $timestamp, 'ACTIVE' => 'Y' ]; @@ -454,7 +456,7 @@ public function testFolderPublicationMethods(): void $timestamp = time(); $siteFields = [ 'TITLE' => 'Test Site for Folder Publication ' . $timestamp, - 'CODE' => 'test-site-folder-pub-' . $timestamp, + 'CODE' => 'testsite' . $timestamp, 'TYPE' => 'PAGE' ]; @@ -465,7 +467,7 @@ public function testFolderPublicationMethods(): void // Add a folder $folderFields = [ 'TITLE' => 'Test Folder for Publication ' . $timestamp, - 'CODE' => 'test-folder-pub-' . $timestamp, + 'CODE' => 'testfolder' . $timestamp, 'ACTIVE' => 'Y' ]; @@ -492,7 +494,7 @@ public function testFolderMarkDeleteAndUnDelete(): void $timestamp = time(); $siteFields = [ 'TITLE' => 'Test Site for Folder Delete ' . $timestamp, - 'CODE' => 'test-site-folder-delete-' . $timestamp, + 'CODE' => 'testsite' . $timestamp, 'TYPE' => 'PAGE' ]; @@ -503,7 +505,7 @@ public function testFolderMarkDeleteAndUnDelete(): void // Add a folder $folderFields = [ 'TITLE' => 'Test Folder for Delete ' . $timestamp, - 'CODE' => 'test-folder-delete-' . $timestamp, + 'CODE' => 'testfolder' . $timestamp, 'ACTIVE' => 'Y' ]; @@ -519,4 +521,135 @@ public function testFolderMarkDeleteAndUnDelete(): void $markUnDeleteResult = $this->siteService->markFolderUnDelete($folderId); self::assertTrue($markUnDeleteResult->isSuccess(), 'Folder mark undelete should be successful'); } -} \ No newline at end of file + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetAdditionalFields(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for Additional Fields ' . $timestamp, + 'CODE' => 'testsiteadditionalfields' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Get additional fields + $siteAdditionalFieldsResult = $this->siteService->getAdditionalFields($siteId); + + // Verify result structure + self::assertInstanceOf( + \Bitrix24\SDK\Services\Landing\Site\Result\SiteAdditionalFieldsResult::class, + $siteAdditionalFieldsResult, + 'Result should be instance of SiteAdditionalFieldsResult' + ); + + // Verify response data + $additionalFields = $siteAdditionalFieldsResult->getAdditionalFields(); + self::assertIsArray($additionalFields, 'Additional fields should be an array'); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testFullExport(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for Export ' . $timestamp, + 'CODE' => 'testsiteexport' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Test 1: Export site without params + $siteExportResult = $this->siteService->fullExport($siteId); + + // Verify result structure + self::assertInstanceOf( + \Bitrix24\SDK\Services\Landing\Site\Result\SiteExportResult::class, + $siteExportResult, + 'Result should be instance of SiteExportResult' + ); + + // Verify export data + $exportData = $siteExportResult->getExportData(); + self::assertIsArray($exportData, 'Export data should be an array'); + + // Test 2: Export site with comprehensive params + $exportParams = [ + 'edit_mode' => 'Y', + 'code' => 'exportedsite' . $timestamp, + 'name' => 'Exported Test Site ' . $timestamp, + 'description' => 'Test site exported via API with comprehensive parameters', + 'hooks_disable' => ['B24BUTTON_CODE'], // Disable specific hooks + ]; + + $exportResultWithParams = $this->siteService->fullExport($siteId, $exportParams); + + // Verify result with params + self::assertInstanceOf( + \Bitrix24\SDK\Services\Landing\Site\Result\SiteExportResult::class, + $exportResultWithParams, + 'Result with params should be instance of SiteExportResult' + ); + + $exportDataWithParams = $exportResultWithParams->getExportData(); + self::assertIsArray($exportDataWithParams, 'Export data with params should be an array'); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testFullExportWithComplexParams(): void + { + // Create a test site + $timestamp = time(); + $siteFields = [ + 'TITLE' => 'Test Site for Complex Export ' . $timestamp, + 'CODE' => 'testsitecomplexexport' . $timestamp, + 'TYPE' => 'PAGE' + ]; + + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); + $this->createdSiteIds[] = $siteId; + + // Test with complex export parameters + $complexParams = [ + 'edit_mode' => 'N', + 'scope' => 'knowledge', + 'hooks_disable' => ['B24BUTTON_CODE', 'YANDEX_METRICA'], + 'code' => 'complexexportedsite' . $timestamp, + 'name' => 'Complex Exported Test Site', + 'description' => 'This is a complex test site with multiple export parameters', + 'preview' => 'https://example.com/preview.jpg', + 'preview2x' => 'https://example.com/preview@2x.jpg', + 'preview3x' => 'https://example.com/preview@3x.jpg' + ]; + + $siteExportResult = $this->siteService->fullExport($siteId, $complexParams); + + // Verify complex export + self::assertInstanceOf( + \Bitrix24\SDK\Services\Landing\Site\Result\SiteExportResult::class, + $siteExportResult, + 'Complex export result should be instance of SiteExportResult' + ); + + $exportData = $siteExportResult->getExportData(); + self::assertIsArray($exportData, 'Complex export data should be an array'); + } +} From 9c850a9a5705bb6bb454a9ef9f0ab285b847c208 Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Wed, 1 Oct 2025 13:33:05 +0400 Subject: [PATCH 05/14] add Langing Page service and tests; run tests and linters --- Makefile | 5 + phpunit.xml.dist | 3 + .../Landing/LandingServiceBuilder.php | 15 + .../Page/Result/MarkPageDeletedResult.php | 28 + .../Page/Result/MarkPageUnDeletedResult.php | 28 + .../Result/PageAdditionalFieldsResult.php | 28 + .../Landing/Page/Result/PageIdByUrlResult.php | 28 + .../Landing/Page/Result/PageItemResult.php | 60 ++ .../Landing/Page/Result/PagePreviewResult.php | 28 + .../Page/Result/PagePublicUrlResult.php | 28 + .../Landing/Page/Result/PagesResult.php | 34 ++ src/Services/Landing/Page/Service/Page.php | 484 +++++++++++++++ .../Landing/Page/Service/PageTest.php | 570 ++++++++++++++++++ 13 files changed, 1339 insertions(+) create mode 100644 src/Services/Landing/Page/Result/MarkPageDeletedResult.php create mode 100644 src/Services/Landing/Page/Result/MarkPageUnDeletedResult.php create mode 100644 src/Services/Landing/Page/Result/PageAdditionalFieldsResult.php create mode 100644 src/Services/Landing/Page/Result/PageIdByUrlResult.php create mode 100644 src/Services/Landing/Page/Result/PageItemResult.php create mode 100644 src/Services/Landing/Page/Result/PagePreviewResult.php create mode 100644 src/Services/Landing/Page/Result/PagePublicUrlResult.php create mode 100644 src/Services/Landing/Page/Result/PagesResult.php create mode 100644 src/Services/Landing/Page/Service/Page.php create mode 100644 tests/Integration/Services/Landing/Page/Service/PageTest.php diff --git a/Makefile b/Makefile index 2eaa5cd5..8d34d3d6 100644 --- a/Makefile +++ b/Makefile @@ -54,6 +54,7 @@ help: @echo "test-integration-sale-payment-item-basket - run PaymentItemBasket integration tests" @echo "test-integration-sale-payment-item-shipment - run PaymentItemShipment integration tests" @echo "test-integration-sale-property-relation - run PropertyRelation integration tests" + @echo "test-integration-landing-page - run Landing Page integration tests" .PHONY: docker-init @@ -203,6 +204,10 @@ test-integration-scope-landing: test-integration-landing-site: docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_landing_site +.PHONY: test-integration-landing-page +test-integration-landing-page: + docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_landing_page + .PHONY: test-integration-sale-status test-integration-sale-status: docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_sale_status diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 77fa3661..af28bf74 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -151,6 +151,9 @@ ./tests/Integration/Services/Landing/Site/ + + ./tests/Integration/Services/Landing/Page/ + ./tests/Integration/Services/Sale/Shipment/ diff --git a/src/Services/Landing/LandingServiceBuilder.php b/src/Services/Landing/LandingServiceBuilder.php index ca665552..02f68148 100644 --- a/src/Services/Landing/LandingServiceBuilder.php +++ b/src/Services/Landing/LandingServiceBuilder.php @@ -39,4 +39,19 @@ public function site(): Site\Service\Site return $this->serviceCache[__METHOD__]; } + + /** + * Get Page service + */ + public function page(): Page\Service\Page + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Page\Service\Page( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } } diff --git a/src/Services/Landing/Page/Result/MarkPageDeletedResult.php b/src/Services/Landing/Page/Result/MarkPageDeletedResult.php new file mode 100644 index 00000000..0d87f3f2 --- /dev/null +++ b/src/Services/Landing/Page/Result/MarkPageDeletedResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Page\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class MarkPageDeletedResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function isSuccess(): bool + { + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} diff --git a/src/Services/Landing/Page/Result/MarkPageUnDeletedResult.php b/src/Services/Landing/Page/Result/MarkPageUnDeletedResult.php new file mode 100644 index 00000000..df46c907 --- /dev/null +++ b/src/Services/Landing/Page/Result/MarkPageUnDeletedResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Page\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class MarkPageUnDeletedResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function isSuccess(): bool + { + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} diff --git a/src/Services/Landing/Page/Result/PageAdditionalFieldsResult.php b/src/Services/Landing/Page/Result/PageAdditionalFieldsResult.php new file mode 100644 index 00000000..f5ab31f4 --- /dev/null +++ b/src/Services/Landing/Page/Result/PageAdditionalFieldsResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Page\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class PageAdditionalFieldsResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getAdditionalFields(): array + { + return $this->getCoreResponse()->getResponseData()->getResult(); + } +} diff --git a/src/Services/Landing/Page/Result/PageIdByUrlResult.php b/src/Services/Landing/Page/Result/PageIdByUrlResult.php new file mode 100644 index 00000000..ff15dbda --- /dev/null +++ b/src/Services/Landing/Page/Result/PageIdByUrlResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Page\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class PageIdByUrlResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getPageId(): int + { + return (int)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} diff --git a/src/Services/Landing/Page/Result/PageItemResult.php b/src/Services/Landing/Page/Result/PageItemResult.php new file mode 100644 index 00000000..c5b94186 --- /dev/null +++ b/src/Services/Landing/Page/Result/PageItemResult.php @@ -0,0 +1,60 @@ + + * + * 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\Landing\Page\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-negative-int $ID + * @property-read string $CODE + * @property-read string $TITLE + * @property-read string $DESCRIPTION + * @property-read string $ACTIVE + * @property-read non-negative-int $SITE_ID + * @property-read string $CREATED_BY_ID + * @property-read string $MODIFIED_BY_ID + * @property-read string $DATE_CREATE + * @property-read string $DATE_MODIFY + * @property-read string $FOLDER + * @property-read string $FOLDER_ID + * @property-read string $SITEMAP + * @property-read string $IN_SITEMAP + * @property-read string $TPL_ID + * @property-read string $TPL_CODE + * @property-read string $PREVIEW_PICTURE + * @property-read string $PREVIEW_TEXT + * @property-read string $DETAIL_TEXT + * @property-read string $DETAIL_PICTURE + * @property-read string $META_TITLE + * @property-read string $META_DESCRIPTION + * @property-read string $META_KEYWORDS + * @property-read string $META_ROBOTS + * @property-read string $RULE + * @property-read string $ADDITIONAL_FIELDS + * @property-read string $XML_ID + * @property-read array $LANDING_ID_INDEX + * @property-read array $LANDING_ID_404 + * @property-read array $LANDING_ID_503 + * @property-read string $DOMAIN_ID + * @property-read string $DOMAIN_NAME + * @property-read string $DOMAIN_PROTOCOL + * @property-read string $PUBLIC_URL + * @property-read string $PREVIEW_URL + * @property-read string $VIEWS + * @property-read string $DATE_PUBLIC + * @property-read string $PUBLICATION + */ +class PageItemResult extends AbstractItem +{ +} diff --git a/src/Services/Landing/Page/Result/PagePreviewResult.php b/src/Services/Landing/Page/Result/PagePreviewResult.php new file mode 100644 index 00000000..bcfa7ea7 --- /dev/null +++ b/src/Services/Landing/Page/Result/PagePreviewResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Page\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class PagePreviewResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getPreviewPath(): string + { + return (string)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} diff --git a/src/Services/Landing/Page/Result/PagePublicUrlResult.php b/src/Services/Landing/Page/Result/PagePublicUrlResult.php new file mode 100644 index 00000000..f28d6e3a --- /dev/null +++ b/src/Services/Landing/Page/Result/PagePublicUrlResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Page\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class PagePublicUrlResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getPublicUrl(): string + { + return (string)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} diff --git a/src/Services/Landing/Page/Result/PagesResult.php b/src/Services/Landing/Page/Result/PagesResult.php new file mode 100644 index 00000000..cd95d1f6 --- /dev/null +++ b/src/Services/Landing/Page/Result/PagesResult.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\Landing\Page\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class PagesResult extends AbstractResult +{ + /** + * @return PageItemResult[] + * @throws BaseException + */ + public function getPages(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $page) { + $res[] = new PageItemResult($page); + } + + return $res; + } +} diff --git a/src/Services/Landing/Page/Service/Page.php b/src/Services/Landing/Page/Service/Page.php new file mode 100644 index 00000000..54054d1c --- /dev/null +++ b/src/Services/Landing/Page/Service/Page.php @@ -0,0 +1,484 @@ + + * + * 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\Landing\Page\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\UpdatedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Landing\Page\Result\PagesResult; +use Bitrix24\SDK\Services\Landing\Page\Result\PageAdditionalFieldsResult; +use Bitrix24\SDK\Services\Landing\Page\Result\PagePreviewResult; +use Bitrix24\SDK\Services\Landing\Page\Result\PagePublicUrlResult; +use Bitrix24\SDK\Services\Landing\Page\Result\PageIdByUrlResult; +use Bitrix24\SDK\Services\Landing\Page\Result\MarkPageDeletedResult; +use Bitrix24\SDK\Services\Landing\Page\Result\MarkPageUnDeletedResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['landing']))] +class Page extends AbstractService +{ + public function __construct(CoreInterface $core, LoggerInterface $logger) + { + parent::__construct($core, $logger); + } + + /** + * Adds a page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-add.html + * + * @param array $fields Field values for creating a page (TITLE, CODE, SITE_ID required, ADDITIONAL_FIELDS optional) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.add', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-add.html', + 'Method for adding a page.' + )] + public function add(array $fields): AddedItemResult + { + return new AddedItemResult( + $this->core->call('landing.landing.add', ['fields' => $fields]) + ); + } + + /** + * Adds a page by template. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-add-by-template.html + * + * @param int $siteId ID of the site where the page needs to be created + * @param string $code Identifier of the template to be used for creation + * @param array $fields Optional array of fields for the created page (TITLE, DESCRIPTION) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.addByTemplate', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-add-by-template.html', + 'Method for adding a page by template.' + )] + public function addByTemplate(int $siteId, string $code, array $fields = []): AddedItemResult + { + $params = [ + 'siteId' => $siteId, + 'code' => $code, + ]; + + if ($fields !== []) { + $params['fields'] = $fields; + } + + return new AddedItemResult( + $this->core->call('landing.landing.addByTemplate', $params) + ); + } + + /** + * Copies the specified page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-copy.html + * + * @param int $lid Page identifier + * @param int|null $toSiteId Optional site identifier to copy to + * @param int|null $toFolderId Optional folder identifier to copy to + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.copy', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-copy.html', + 'Method copies the specified page.' + )] + public function copy(int $lid, ?int $toSiteId = null, ?int $toFolderId = null): AddedItemResult + { + $params = ['lid' => $lid]; + + if ($toSiteId !== null) { + $params['toSiteId'] = $toSiteId; + } + + if ($toFolderId !== null) { + $params['toFolderId'] = $toFolderId; + } + + return new AddedItemResult( + $this->core->call('landing.landing.copy', $params) + ); + } + + /** + * Deletes a page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-delete.html + * + * @param int $lid Entity identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.delete', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-delete.html', + 'Method for deleting a page.' + )] + public function delete(int $lid): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call('landing.landing.delete', ['lid' => $lid]) + ); + } + + /** + * Updates a page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-update.html + * + * @param int $lid Entity identifier + * @param array $fields Editable fields of the entity + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.update', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-update.html', + 'Method for modifying a page.' + )] + public function update(int $lid, array $fields): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call('landing.landing.update', [ + 'lid' => $lid, + 'fields' => $fields + ]) + ); + } + + /** + * Retrieves a list of pages. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-get-list.html + * + * @param array $select Fields to select + * @param array $filter Filter conditions + * @param array $order Sort order + * @param array $group Group fields + * @param bool $getPreview Return page previews + * @param bool $getUrls Return public addresses of pages + * @param bool $checkArea Return flag IS_AREA indicating whether the page is an included area + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.getList', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-get-list.html', + 'Method for retrieving a list of pages.' + )] + public function getList( + array $select = [], + array $filter = [], + array $order = [], + array $group = [], + bool $getPreview = false, + bool $getUrls = false, + bool $checkArea = false + ): PagesResult { + $params = []; + + if ($select !== []) { + $params['select'] = $select; + } + + if ($filter !== []) { + $params['filter'] = $filter; + } + + if ($order !== []) { + $params['order'] = $order; + } + + if ($group !== []) { + $params['group'] = $group; + } + + if ($getPreview) { + $params['get_preview'] = 1; + } + + if ($getUrls) { + $params['get_urls'] = 1; + } + + if ($checkArea) { + $params['check_area'] = 1; + } + + return new PagesResult( + $this->core->call('landing.landing.getList', ['params' => $params]) + ); + } + + /** + * Retrieves additional fields of the page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-get-additional-fields.html + * + * @param int $lid Page identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.getadditionalfields', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-get-additional-fields.html', + 'Method for obtaining additional fields of the page.' + )] + public function getAdditionalFields(int $lid): PageAdditionalFieldsResult + { + return new PageAdditionalFieldsResult( + $this->core->call('landing.landing.getadditionalfields', ['lid' => $lid]) + ); + } + + /** + * Returns the path to the page preview. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-get-preview.html + * + * @param int $lid Page identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.getpreview', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-get-preview.html', + 'Method returns the path to the page preview.' + )] + public function getPreview(int $lid): PagePreviewResult + { + return new PagePreviewResult( + $this->core->call('landing.landing.getpreview', ['lid' => $lid]) + ); + } + + /** + * Returns the web address of the page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-get-public-url.html + * + * @param int $lid Page identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.getpublicurl', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-get-public-url.html', + 'Method returns the web address of the page.' + )] + public function getPublicUrl(int $lid): PagePublicUrlResult + { + return new PagePublicUrlResult( + $this->core->call('landing.landing.getpublicurl', ['lid' => $lid]) + ); + } + + /** + * Returns the page identifier by the provided relative URL. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-resolve-id-by-public-url.html + * + * @param string $landingUrl Relative URL of the page + * @param int $siteId Site ID + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.resolveIdByPublicUrl', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-resolve-id-by-public-url.html', + 'Method returns the page identifier by the provided relative URL of the page.' + )] + public function resolveIdByPublicUrl(string $landingUrl, int $siteId): PageIdByUrlResult + { + return new PageIdByUrlResult( + $this->core->call('landing.landing.resolveIdByPublicUrl', [ + 'landingUrl' => $landingUrl, + 'siteId' => $siteId + ]) + ); + } + + /** + * Publishes a page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-publication.html + * + * @param int $lid Page identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.publication', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-publication.html', + 'Method for publishing the page.' + )] + public function publish(int $lid): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call('landing.landing.publication', ['lid' => $lid]) + ); + } + + /** + * Unpublishes a page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-unpublic.html + * + * @param int $lid Page identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.unpublic', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-unpublic.html', + 'Method for unpublishing the page.' + )] + public function unpublish(int $lid): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call('landing.landing.unpublic', ['lid' => $lid]) + ); + } + + /** + * Marks the page as deleted. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-mark-delete.html + * + * @param int $lid Page identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.markDelete', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-mark-delete.html', + 'Method marks the page as deleted.' + )] + public function markDeleted(int $lid): MarkPageDeletedResult + { + return new MarkPageDeletedResult( + $this->core->call('landing.landing.markDelete', ['lid' => $lid]) + ); + } + + /** + * Marks the page as not deleted. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-mark-undelete.html + * + * @param int $lid Page identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.markUnDelete', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-mark-undelete.html', + 'Method marks the page as not deleted.' + )] + public function markUnDeleted(int $lid): MarkPageUnDeletedResult + { + return new MarkPageUnDeletedResult( + $this->core->call('landing.landing.markUnDelete', ['lid' => $lid]) + ); + } + + /** + * Moves the page to another site and/or folder. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-move.html + * + * @param int $lid Identifier of the page to be moved + * @param int $toSiteId Identifier of the site to which the page should be moved + * @param int|null $toFolderId Optional identifier of the site folder to which the page should be moved + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.move', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-move.html', + 'Method moves the page to another site and/or folder.' + )] + public function move(int $lid, int $toSiteId, ?int $toFolderId = null): UpdatedItemResult + { + $params = [ + 'lid' => $lid, + 'toSiteId' => $toSiteId, + ]; + + if ($toFolderId !== null) { + $params['toFolderId'] = $toFolderId; + } + + return new UpdatedItemResult( + $this->core->call('landing.landing.move', $params) + ); + } + + /** + * Removes related landing entities. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-remove-entities.html + * + * @param int $lid Identifier of the landing + * @param array $data Associative array where key 'blocks' contains blocks to be deleted, + * and key 'images' contains block-image pairs for which images need to be deleted + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.removeEntities', + 'https://apidocs.bitrix24.com/api-reference/landing/page/methods/landing-landing-remove-entities.html', + 'Method removes related landing entities.' + )] + public function removeEntities(int $lid, array $data): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call('landing.landing.removeEntities', [ + 'lid' => $lid, + 'data' => $data + ]) + ); + } +} diff --git a/tests/Integration/Services/Landing/Page/Service/PageTest.php b/tests/Integration/Services/Landing/Page/Service/PageTest.php new file mode 100644 index 00000000..570f2f10 --- /dev/null +++ b/tests/Integration/Services/Landing/Page/Service/PageTest.php @@ -0,0 +1,570 @@ + + * + * 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\Landing\Page\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Landing\Page\Result\PageItemResult; +use Bitrix24\SDK\Services\Landing\Page\Service\Page; +use Bitrix24\SDK\Services\Landing\Site\Service\Site; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; + +/** + * Class PageTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\Landing\Page\Service + */ +#[CoversMethod(Page::class, 'add')] +#[CoversMethod(Page::class, 'addByTemplate')] +#[CoversMethod(Page::class, 'copy')] +#[CoversMethod(Page::class, 'delete')] +#[CoversMethod(Page::class, 'update')] +#[CoversMethod(Page::class, 'getList')] +#[CoversMethod(Page::class, 'getAdditionalFields')] +#[CoversMethod(Page::class, 'getPreview')] +#[CoversMethod(Page::class, 'getPublicUrl')] +#[CoversMethod(Page::class, 'resolveIdByPublicUrl')] +#[CoversMethod(Page::class, 'publish')] +#[CoversMethod(Page::class, 'unpublish')] +#[CoversMethod(Page::class, 'markDeleted')] +#[CoversMethod(Page::class, 'markUnDeleted')] +#[CoversMethod(Page::class, 'move')] +#[CoversMethod(Page::class, 'removeEntities')] +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\Landing\Page\Service\Page::class)] +class PageTest extends TestCase +{ + use CustomBitrix24Assertions; + + protected Page $pageService; + + protected Site $siteService; + + protected array $createdPageIds = []; + + protected array $createdSiteIds = []; + + protected function setUp(): void + { + $serviceBuilder = Fabric::getServiceBuilder(); + $this->pageService = $serviceBuilder->getLandingScope()->page(); + $this->siteService = $serviceBuilder->getLandingScope()->site(); + } + + protected function tearDown(): void + { + // Clean up created pages + foreach ($this->createdPageIds as $createdPageId) { + try { + $this->pageService->delete($createdPageId); + } catch (\Exception) { + // Ignore if page doesn't exist + } + } + + // Clean up created sites + foreach ($this->createdSiteIds as $createdSiteId) { + try { + $this->siteService->delete($createdSiteId); + } catch (\Exception) { + // Ignore if site doesn't exist + } + } + } + + /** + * Helper method to create a test site + */ + protected function createTestSite(): int + { + $siteFields = [ + 'TITLE' => 'Test Site for Page ' . time(), + 'CODE' => 'testsitepage' . time(), + 'TYPE' => 'PAGE' + ]; + + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); + $this->createdSiteIds[] = $siteId; + + return $siteId; + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testAdd(): void + { + $siteId = $this->createTestSite(); + + $pageFields = [ + 'TITLE' => 'Test Page ' . time(), + 'CODE' => 'testpage' . time(), + 'SITE_ID' => $siteId, + 'ADDITIONAL_FIELDS' => [ + 'THEME_CODE' => 'wedding' + ] + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + self::assertGreaterThan(0, $pageId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testAddByTemplate(): void + { + $siteId = $this->createTestSite(); + + // Get available page templates from portal + $core = Fabric::getCore(); + $templatesResponse = $core->call('landing.demos.getPageList', ['type' => 'page']); + $templates = $templatesResponse->getResponseData()->getResult(); + + // Use the first available template + $templateCode = key($templates); + + $addedItemResult = $this->pageService->addByTemplate( + $siteId, + $templateCode, + [ + 'TITLE' => 'Test Page by Template ' . time(), + 'DESCRIPTION' => 'Test page description' + ] + ); + + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + self::assertGreaterThan(0, $pageId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetList(): void + { + $siteId = $this->createTestSite(); + + // First create a test page + $timestamp = time(); + $pageFields = [ + 'TITLE' => 'Test Page for List ' . $timestamp, + 'CODE' => 'testpagelist' . $timestamp, + 'SITE_ID' => $siteId + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + // Test getList with no parameters + $pagesResult = $this->pageService->getList(); + $pages = $pagesResult->getPages(); + + self::assertIsArray($pages); + self::assertNotEmpty($pages); + + // Check that our created page is in the list + $foundPage = null; + foreach ($pages as $page) { + self::assertInstanceOf(PageItemResult::class, $page); + if (intval($page->ID) === $pageId) { + $foundPage = $page; + break; + } + } + + self::assertNotNull($foundPage, 'Created page should be found in the list'); + self::assertEquals($pageFields['TITLE'], $foundPage->TITLE); + self::assertStringContainsString($pageFields['CODE'], $foundPage->CODE); + self::assertEquals($pageFields['SITE_ID'], $foundPage->SITE_ID); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetListWithFilters(): void + { + $siteId = $this->createTestSite(); + + // Create a test page + $timestamp = time(); + $pageFields = [ + 'TITLE' => 'Test Page Filter ' . $timestamp, + 'CODE' => 'testpagefilter' . $timestamp, + 'SITE_ID' => $siteId + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + // Test getList with filters + $pagesResult = $this->pageService->getList( + ['ID', 'TITLE', 'CODE', 'SITE_ID'], + ['SITE_ID' => $siteId], + ['ID' => 'DESC'] + ); + + $pages = $pagesResult->getPages(); + + self::assertIsArray($pages); + + // All pages should belong to our site + foreach ($pages as $page) { + self::assertEquals($siteId, $page->SITE_ID); + } + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testUpdate(): void + { + $siteId = $this->createTestSite(); + + // Create a test page + $pageFields = [ + 'TITLE' => 'Test Page for Update ' . time(), + 'CODE' => 'testpageupdate' . time(), + 'SITE_ID' => $siteId + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + // Update the page + $newTitle = 'Updated Page Title ' . time(); + $updatedItemResult = $this->pageService->update($pageId, [ + 'TITLE' => $newTitle + ]); + + self::assertTrue($updatedItemResult->isSuccess()); + + // Verify the update + $pagesResult = $this->pageService->getList(['ID', 'TITLE'], ['ID' => $pageId]); + $pages = $pagesResult->getPages(); + + self::assertCount(1, $pages); + self::assertEquals($newTitle, $pages[0]->TITLE); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testCopy(): void + { + $siteId = $this->createTestSite(); + + // Create a test page + $pageFields = [ + 'TITLE' => 'Test Page for Copy ' . time(), + 'CODE' => 'testpagecopy' . time(), + 'SITE_ID' => $siteId + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $originalPageId = $addedItemResult->getId(); + $this->createdPageIds[] = $originalPageId; + + // Copy the page + $copyResult = $this->pageService->copy($originalPageId); + $copiedPageId = $copyResult->getId(); + $this->createdPageIds[] = $copiedPageId; + + self::assertGreaterThan(0, $copiedPageId); + self::assertNotEquals($originalPageId, $copiedPageId); + + // Verify both pages exist + $pagesResult = $this->pageService->getList(['ID', 'TITLE'], ['SITE_ID' => $siteId]); + $pages = $pagesResult->getPages(); + + $pageIds = array_map(fn($page): int => intval($page->ID), $pages); + self::assertContains($originalPageId, $pageIds); + self::assertContains($copiedPageId, $pageIds); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetAdditionalFields(): void + { + $siteId = $this->createTestSite(); + + // Create a test page with additional fields + $pageFields = [ + 'TITLE' => 'Test Page Additional Fields ' . time(), + 'CODE' => 'testpageadditional' . time(), + 'SITE_ID' => $siteId, + 'ADDITIONAL_FIELDS' => [ + 'THEME_CODE' => 'wedding', + 'METAMAIN_TITLE' => 'Test Meta Title' + ] + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + // Get additional fields + $pageAdditionalFieldsResult = $this->pageService->getAdditionalFields($pageId); + $additionalFields = $pageAdditionalFieldsResult->getAdditionalFields(); + + self::assertIsArray($additionalFields); + // Note: The exact structure depends on API response format + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetPreview(): void + { + $siteId = $this->createTestSite(); + + // Create a test page + $pageFields = [ + 'TITLE' => 'Test Page Preview ' . time(), + 'CODE' => 'testpagepreview' . time(), + 'SITE_ID' => $siteId + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + // Get preview + $pagePreviewResult = $this->pageService->getPreview($pageId); + $previewPath = $pagePreviewResult->getPreviewPath(); + + self::assertIsString($previewPath); + // Preview path might be empty or contain URL + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetPublicUrl(): void + { + $siteId = $this->createTestSite(); + + // Create a test page + $pageFields = [ + 'TITLE' => 'Test Page Public URL ' . time(), + 'CODE' => 'testpagepublicurl' . time(), + 'SITE_ID' => $siteId + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + // Get public URL + $pagePublicUrlResult = $this->pageService->getPublicUrl($pageId); + $publicUrl = $pagePublicUrlResult->getPublicUrl(); + + self::assertIsString($publicUrl); + // Public URL might be empty until published + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testPublishAndUnpublish(): void + { + $siteId = $this->createTestSite(); + + // Create a test page + $pageFields = [ + 'TITLE' => 'Test Page Publish ' . time(), + 'CODE' => 'testpagepublish' . time(), + 'SITE_ID' => $siteId + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + // Publish the page + $updatedItemResult = $this->pageService->publish($pageId); + self::assertTrue($updatedItemResult->isSuccess()); + + // Unpublish the page + $unpublishResult = $this->pageService->unpublish($pageId); + self::assertTrue($unpublishResult->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testMarkDeletedAndUnDeleted(): void + { + $siteId = $this->createTestSite(); + + // Create a test page + $pageFields = [ + 'TITLE' => 'Test Page Mark Delete ' . time(), + 'CODE' => 'testpagemarkdelete' . time(), + 'SITE_ID' => $siteId + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + // Mark as deleted + $markPageDeletedResult = $this->pageService->markDeleted($pageId); + self::assertTrue($markPageDeletedResult->isSuccess()); + + // Mark as undeleted + $markPageUnDeletedResult = $this->pageService->markUnDeleted($pageId); + self::assertTrue($markPageUnDeletedResult->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testMove(): void + { + $sourceSiteId = $this->createTestSite(); + $targetSiteId = $this->createTestSite(); + + // Create a test page + $pageFields = [ + 'TITLE' => 'Test Page Move ' . time(), + 'CODE' => 'testpagemove' . time(), + 'SITE_ID' => $sourceSiteId + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + // Move the page to another site + $updatedItemResult = $this->pageService->move($pageId, $targetSiteId); + self::assertTrue($updatedItemResult->isSuccess()); + + // Verify the page is now in the target site + $pagesResult = $this->pageService->getList(['ID', 'SITE_ID'], ['ID' => $pageId]); + $pages = $pagesResult->getPages(); + + self::assertCount(1, $pages); + self::assertEquals($targetSiteId, $pages[0]->SITE_ID); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testRemoveEntities(): void + { + $siteId = $this->createTestSite(); + + // Create a test page + $pageFields = [ + 'TITLE' => 'Test Page Remove Entities ' . time(), + 'CODE' => 'testpageremove' . time(), + 'SITE_ID' => $siteId + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + // Remove entities (empty data for test) + $updatedItemResult = $this->pageService->removeEntities($pageId, [ + 'blocks' => [], + 'images' => [] + ]); + + self::assertTrue($updatedItemResult->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testResolveIdByPublicUrl(): void + { + $siteId = $this->createTestSite(); + + // Create a test page + $timestamp = time(); + $pageCode = 'testpageresolve' . $timestamp; + $pageFields = [ + 'TITLE' => 'Test Page Resolve ' . $timestamp, + 'CODE' => $pageCode, + 'SITE_ID' => $siteId + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + // Try to resolve ID by URL + $pageIdByUrlResult = $this->pageService->resolveIdByPublicUrl('/' . $pageCode . '/', $siteId); + $resolvedPageId = $pageIdByUrlResult->getPageId(); + self::assertEquals($pageId, $resolvedPageId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testDelete(): void + { + $siteId = $this->createTestSite(); + + // Create a test page + $pageFields = [ + 'TITLE' => 'Test Page Delete ' . time(), + 'CODE' => 'testpagedelete' . time(), + 'SITE_ID' => $siteId + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + + // Delete the page + $deletedItemResult = $this->pageService->delete($pageId); + self::assertTrue($deletedItemResult->isSuccess()); + + // Remove from cleanup list as it's already deleted + $this->createdPageIds = array_filter($this->createdPageIds, fn($id): bool => $id !== $pageId); + + // Verify page is deleted by trying to get it + $pagesResult = $this->pageService->getList(['ID'], ['ID' => $pageId]); + $pages = $pagesResult->getPages(); + self::assertEmpty($pages, 'Page should be deleted and not found in list'); + } +} \ No newline at end of file From 8fddd9f09ead4cca2e3f0bb886cf3aa793cc819c Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Wed, 1 Oct 2025 15:16:08 +0400 Subject: [PATCH 06/14] add Page Blocks methods --- .../Landing/Page/Result/BlockAddedResult.php | 33 ++ .../Landing/Page/Result/BlockCopiedResult.php | 33 ++ .../Page/Result/BlockDeletedResult.php | 33 ++ .../Page/Result/BlockFavoriteResult.php | 33 ++ .../Page/Result/BlockMarkDeletedResult.php | 33 ++ .../Page/Result/BlockMarkUnDeletedResult.php | 33 ++ .../Landing/Page/Result/BlockMovedResult.php | 33 ++ .../Page/Result/BlockVisibilityResult.php | 33 ++ src/Services/Landing/Page/Service/Page.php | 341 ++++++++++++++++++ 9 files changed, 605 insertions(+) create mode 100644 src/Services/Landing/Page/Result/BlockAddedResult.php create mode 100644 src/Services/Landing/Page/Result/BlockCopiedResult.php create mode 100644 src/Services/Landing/Page/Result/BlockDeletedResult.php create mode 100644 src/Services/Landing/Page/Result/BlockFavoriteResult.php create mode 100644 src/Services/Landing/Page/Result/BlockMarkDeletedResult.php create mode 100644 src/Services/Landing/Page/Result/BlockMarkUnDeletedResult.php create mode 100644 src/Services/Landing/Page/Result/BlockMovedResult.php create mode 100644 src/Services/Landing/Page/Result/BlockVisibilityResult.php diff --git a/src/Services/Landing/Page/Result/BlockAddedResult.php b/src/Services/Landing/Page/Result/BlockAddedResult.php new file mode 100644 index 00000000..c7a04319 --- /dev/null +++ b/src/Services/Landing/Page/Result/BlockAddedResult.php @@ -0,0 +1,33 @@ + + * + * 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\Landing\Page\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class BlockAddedResult extends AbstractResult +{ + /** + * Get block identifier + * + * @return int + */ + public function getBlockId(): int + { + echo "\n BlockAddedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return (int)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Page/Result/BlockCopiedResult.php b/src/Services/Landing/Page/Result/BlockCopiedResult.php new file mode 100644 index 00000000..37fa7447 --- /dev/null +++ b/src/Services/Landing/Page/Result/BlockCopiedResult.php @@ -0,0 +1,33 @@ + + * + * 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\Landing\Page\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class BlockCopiedResult extends AbstractResult +{ + /** + * Get copied block identifier + * + * @return int + */ + public function getBlockId(): int + { + echo "\n BlockCopiedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return (int)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Page/Result/BlockDeletedResult.php b/src/Services/Landing/Page/Result/BlockDeletedResult.php new file mode 100644 index 00000000..3abc81c5 --- /dev/null +++ b/src/Services/Landing/Page/Result/BlockDeletedResult.php @@ -0,0 +1,33 @@ + + * + * 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\Landing\Page\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class BlockDeletedResult extends AbstractResult +{ + /** + * Check if block was successfully deleted + * + * @return bool + */ + public function isSuccess(): bool + { + echo "\n BlockDeletedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Page/Result/BlockFavoriteResult.php b/src/Services/Landing/Page/Result/BlockFavoriteResult.php new file mode 100644 index 00000000..b33a2300 --- /dev/null +++ b/src/Services/Landing/Page/Result/BlockFavoriteResult.php @@ -0,0 +1,33 @@ + + * + * 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\Landing\Page\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class BlockFavoriteResult extends AbstractResult +{ + /** + * Get favorite block identifier or operation status + * + * @return int|bool + */ + public function getResult() + { + echo "\n BlockFavoriteResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Page/Result/BlockMarkDeletedResult.php b/src/Services/Landing/Page/Result/BlockMarkDeletedResult.php new file mode 100644 index 00000000..527d58ed --- /dev/null +++ b/src/Services/Landing/Page/Result/BlockMarkDeletedResult.php @@ -0,0 +1,33 @@ + + * + * 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\Landing\Page\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class BlockMarkDeletedResult extends AbstractResult +{ + /** + * Check if block mark as deleted operation was successful + * + * @return bool + */ + public function isSuccess(): bool + { + echo "\n BlockMarkDeletedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Page/Result/BlockMarkUnDeletedResult.php b/src/Services/Landing/Page/Result/BlockMarkUnDeletedResult.php new file mode 100644 index 00000000..9fadeb25 --- /dev/null +++ b/src/Services/Landing/Page/Result/BlockMarkUnDeletedResult.php @@ -0,0 +1,33 @@ + + * + * 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\Landing\Page\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class BlockMarkUnDeletedResult extends AbstractResult +{ + /** + * Check if block mark as undeleted operation was successful + * + * @return bool + */ + public function isSuccess(): bool + { + echo "\n BlockMarkUnDeletedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Page/Result/BlockMovedResult.php b/src/Services/Landing/Page/Result/BlockMovedResult.php new file mode 100644 index 00000000..9147b67a --- /dev/null +++ b/src/Services/Landing/Page/Result/BlockMovedResult.php @@ -0,0 +1,33 @@ + + * + * 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\Landing\Page\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class BlockMovedResult extends AbstractResult +{ + /** + * Check if block move operation was successful + * + * @return bool + */ + public function isSuccess(): bool + { + echo "\n BlockMovedResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Page/Result/BlockVisibilityResult.php b/src/Services/Landing/Page/Result/BlockVisibilityResult.php new file mode 100644 index 00000000..f5f2f377 --- /dev/null +++ b/src/Services/Landing/Page/Result/BlockVisibilityResult.php @@ -0,0 +1,33 @@ + + * + * 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\Landing\Page\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class BlockVisibilityResult extends AbstractResult +{ + /** + * Check if block visibility operation was successful + * + * @return bool + */ + public function isSuccess(): bool + { + echo "\n BlockVisibilityResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Landing/Page/Service/Page.php b/src/Services/Landing/Page/Service/Page.php index 54054d1c..597ac806 100644 --- a/src/Services/Landing/Page/Service/Page.php +++ b/src/Services/Landing/Page/Service/Page.php @@ -30,6 +30,14 @@ use Bitrix24\SDK\Services\Landing\Page\Result\PageIdByUrlResult; use Bitrix24\SDK\Services\Landing\Page\Result\MarkPageDeletedResult; use Bitrix24\SDK\Services\Landing\Page\Result\MarkPageUnDeletedResult; +use Bitrix24\SDK\Services\Landing\Page\Result\BlockAddedResult; +use Bitrix24\SDK\Services\Landing\Page\Result\BlockCopiedResult; +use Bitrix24\SDK\Services\Landing\Page\Result\BlockDeletedResult; +use Bitrix24\SDK\Services\Landing\Page\Result\BlockMovedResult; +use Bitrix24\SDK\Services\Landing\Page\Result\BlockVisibilityResult; +use Bitrix24\SDK\Services\Landing\Page\Result\BlockMarkDeletedResult; +use Bitrix24\SDK\Services\Landing\Page\Result\BlockMarkUnDeletedResult; +use Bitrix24\SDK\Services\Landing\Page\Result\BlockFavoriteResult; use Psr\Log\LoggerInterface; #[ApiServiceMetadata(new Scope(['landing']))] @@ -481,4 +489,337 @@ public function removeEntities(int $lid, array $data): UpdatedItemResult ]) ); } + + /** + * Adds a new block to the page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-add-block.html + * + * @param int $lid Page identifier + * @param array $fields Array of block fields: + * - CODE: Symbolic code of the block (required) + * - AFTER_ID: After which block ID the new block should be added (optional) + * - ACTIVE: Block activity Y/N (optional) + * - CONTENT: Entirely different content of the block (optional) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.addblock', + 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-add-block.html', + 'Method for adding a new block to the page.' + )] + public function addBlock(int $lid, array $fields): BlockAddedResult + { + return new BlockAddedResult( + $this->core->call('landing.landing.addblock', [ + 'lid' => $lid, + 'fields' => $fields + ]) + ); + } + + /** + * Copies a block from one page to another. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-copy-block.html + * + * @param int $lid Identifier of the page where the block should be copied + * @param int $block Identifier of the block which may be on another page + * @param array $params Array of parameters, currently supporting AFTER_ID - after which block to insert the new one + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.copyblock', + 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-copy-block.html', + 'Method copies a block from one page to another.' + )] + public function copyBlock(int $lid, int $block, array $params = []): BlockCopiedResult + { + $callParams = [ + 'lid' => $lid, + 'block' => $block, + ]; + + if ($params !== []) { + $callParams['params'] = $params; + } + + return new BlockCopiedResult( + $this->core->call('landing.landing.copyblock', $callParams) + ); + } + + /** + * Completely removes a block from the page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-delete-block.html + * + * @param int $lid Page identifier + * @param int $block Block identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.deleteblock', + 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-delete-block.html', + 'Method for deleting a block from the page.' + )] + public function deleteBlock(int $lid, int $block): BlockDeletedResult + { + return new BlockDeletedResult( + $this->core->call('landing.landing.deleteblock', [ + 'lid' => $lid, + 'block' => $block + ]) + ); + } + + /** + * Moves a block down one position on the page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-down-block.html + * + * @param int $lid Page identifier + * @param int $block Block identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.downblock', + 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-down-block.html', + 'Method moves a block down one position on the page.' + )] + public function moveBlockDown(int $lid, int $block): BlockMovedResult + { + return new BlockMovedResult( + $this->core->call('landing.landing.downblock', [ + 'lid' => $lid, + 'block' => $block + ]) + ); + } + + /** + * Moves a block up one position on the page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-up-block.html + * + * @param int $lid Page identifier + * @param int $block Block identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.upblock', + 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-up-block.html', + 'Method moves a block up one position on the page.' + )] + public function moveBlockUp(int $lid, int $block): BlockMovedResult + { + return new BlockMovedResult( + $this->core->call('landing.landing.upblock', [ + 'lid' => $lid, + 'block' => $block + ]) + ); + } + + /** + * Moves a block from one page to another. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-move-block.html + * + * @param int $lid Identifier of the page to which the block should be moved + * @param int $block Identifier of the block which may be on another page + * @param array $params Array of parameters, currently supporting AFTER_ID - after which block to insert the new one + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.moveblock', + 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-move-block.html', + 'Method moves a block from one page to another.' + )] + public function moveBlock(int $lid, int $block, array $params = []): BlockMovedResult + { + $callParams = [ + 'lid' => $lid, + 'block' => $block, + ]; + + if ($params !== []) { + $callParams['params'] = $params; + } + + return new BlockMovedResult( + $this->core->call('landing.landing.moveblock', $callParams) + ); + } + + /** + * Hides a block from the page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-hide-block.html + * + * @param int $lid Page identifier + * @param int $block Block identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.hideblock', + 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-hide-block.html', + 'Method hides a block from the page.' + )] + public function hideBlock(int $lid, int $block): BlockVisibilityResult + { + return new BlockVisibilityResult( + $this->core->call('landing.landing.hideblock', [ + 'lid' => $lid, + 'block' => $block + ]) + ); + } + + /** + * Displays a block on the page. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-show-block.html + * + * @param int $lid Page identifier + * @param int $block Block identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.showblock', + 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-show-block.html', + 'Method displays a block on the page.' + )] + public function showBlock(int $lid, int $block): BlockVisibilityResult + { + return new BlockVisibilityResult( + $this->core->call('landing.landing.showblock', [ + 'lid' => $lid, + 'block' => $block + ]) + ); + } + + /** + * Marks a block as deleted but does not physically remove it. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-mark-deleted-block.html + * + * @param int $lid Page identifier + * @param int $block Block identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.markdeletedblock', + 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-mark-deleted-block.html', + 'Method marks a block as deleted but does not physically remove it.' + )] + public function markBlockDeleted(int $lid, int $block): BlockMarkDeletedResult + { + return new BlockMarkDeletedResult( + $this->core->call('landing.landing.markdeletedblock', [ + 'lid' => $lid, + 'block' => $block + ]) + ); + } + + /** + * Restores a block that has been marked as deleted. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-mark-undeleted-block.html + * + * @param int $lid Page identifier + * @param int $block Block identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.markundeletedblock', + 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-mark-undeleted-block.html', + 'Method restores a block that has been marked as deleted.' + )] + public function markBlockUnDeleted(int $lid, int $block): BlockMarkUnDeletedResult + { + return new BlockMarkUnDeletedResult( + $this->core->call('landing.landing.markundeletedblock', [ + 'lid' => $lid, + 'block' => $block + ]) + ); + } + + /** + * Saves an existing block on the page to "My Blocks". + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-favorite-block.html + * + * @param int $lid Page identifier + * @param int $block Block identifier + * @param array $meta Object containing information to save the block: + * - name: Name of the block + * - section: Array of categories to save the block to + * - preview: Image of the block + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.favoriteBlock', + 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-favorite-block.html', + 'Method saves an existing block on the page to My Blocks.' + )] + public function addBlockToFavorites(int $lid, int $block, array $meta): BlockFavoriteResult + { + return new BlockFavoriteResult( + $this->core->call('landing.landing.favoriteBlock', [ + 'lid' => $lid, + 'block' => $block, + 'meta' => $meta + ]) + ); + } + + /** + * Removes a block that was saved in "My Blocks". + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-unfavorite-block.html + * + * @param int $blockId Block identifier + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.landing.unFavoriteBlock', + 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-unfavorite-block.html', + 'Method removes a block that was saved in My Blocks.' + )] + public function removeBlockFromFavorites(int $blockId): BlockFavoriteResult + { + return new BlockFavoriteResult( + $this->core->call('landing.landing.unFavoriteBlock', [ + 'blockId' => $blockId + ]) + ); + } } From 0aea135886eddc10c7615f03567275f4cb164d4f Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Thu, 2 Oct 2025 13:25:10 +0400 Subject: [PATCH 07/14] add Page Blocks tests; run tests --- .../Landing/Page/Result/BlockAddedResult.php | 33 -- .../Landing/Page/Result/BlockCopiedResult.php | 33 -- .../Page/Result/BlockDeletedResult.php | 33 -- .../Page/Result/BlockFavoriteResult.php | 33 -- .../Page/Result/BlockMarkDeletedResult.php | 33 -- .../Page/Result/BlockMarkUnDeletedResult.php | 33 -- .../Page/Result/BlockVisibilityResult.php | 33 -- src/Services/Landing/Page/Service/Page.php | 43 +-- .../Landing/Page/Service/PageTest.php | 319 ++++++++++++++++++ 9 files changed, 337 insertions(+), 256 deletions(-) delete mode 100644 src/Services/Landing/Page/Result/BlockAddedResult.php delete mode 100644 src/Services/Landing/Page/Result/BlockCopiedResult.php delete mode 100644 src/Services/Landing/Page/Result/BlockDeletedResult.php delete mode 100644 src/Services/Landing/Page/Result/BlockFavoriteResult.php delete mode 100644 src/Services/Landing/Page/Result/BlockMarkDeletedResult.php delete mode 100644 src/Services/Landing/Page/Result/BlockMarkUnDeletedResult.php delete mode 100644 src/Services/Landing/Page/Result/BlockVisibilityResult.php diff --git a/src/Services/Landing/Page/Result/BlockAddedResult.php b/src/Services/Landing/Page/Result/BlockAddedResult.php deleted file mode 100644 index c7a04319..00000000 --- a/src/Services/Landing/Page/Result/BlockAddedResult.php +++ /dev/null @@ -1,33 +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\Services\Landing\Page\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class BlockAddedResult extends AbstractResult -{ - /** - * Get block identifier - * - * @return int - */ - public function getBlockId(): int - { - echo "\n BlockAddedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return (int)$this->getCoreResponse()->getResponseData()->getResult()[0]; - } -} \ No newline at end of file diff --git a/src/Services/Landing/Page/Result/BlockCopiedResult.php b/src/Services/Landing/Page/Result/BlockCopiedResult.php deleted file mode 100644 index 37fa7447..00000000 --- a/src/Services/Landing/Page/Result/BlockCopiedResult.php +++ /dev/null @@ -1,33 +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\Services\Landing\Page\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class BlockCopiedResult extends AbstractResult -{ - /** - * Get copied block identifier - * - * @return int - */ - public function getBlockId(): int - { - echo "\n BlockCopiedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return (int)$this->getCoreResponse()->getResponseData()->getResult()[0]; - } -} \ No newline at end of file diff --git a/src/Services/Landing/Page/Result/BlockDeletedResult.php b/src/Services/Landing/Page/Result/BlockDeletedResult.php deleted file mode 100644 index 3abc81c5..00000000 --- a/src/Services/Landing/Page/Result/BlockDeletedResult.php +++ /dev/null @@ -1,33 +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\Services\Landing\Page\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class BlockDeletedResult extends AbstractResult -{ - /** - * Check if block was successfully deleted - * - * @return bool - */ - public function isSuccess(): bool - { - echo "\n BlockDeletedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; - } -} \ No newline at end of file diff --git a/src/Services/Landing/Page/Result/BlockFavoriteResult.php b/src/Services/Landing/Page/Result/BlockFavoriteResult.php deleted file mode 100644 index b33a2300..00000000 --- a/src/Services/Landing/Page/Result/BlockFavoriteResult.php +++ /dev/null @@ -1,33 +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\Services\Landing\Page\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class BlockFavoriteResult extends AbstractResult -{ - /** - * Get favorite block identifier or operation status - * - * @return int|bool - */ - public function getResult() - { - echo "\n BlockFavoriteResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return $this->getCoreResponse()->getResponseData()->getResult()[0]; - } -} \ No newline at end of file diff --git a/src/Services/Landing/Page/Result/BlockMarkDeletedResult.php b/src/Services/Landing/Page/Result/BlockMarkDeletedResult.php deleted file mode 100644 index 527d58ed..00000000 --- a/src/Services/Landing/Page/Result/BlockMarkDeletedResult.php +++ /dev/null @@ -1,33 +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\Services\Landing\Page\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class BlockMarkDeletedResult extends AbstractResult -{ - /** - * Check if block mark as deleted operation was successful - * - * @return bool - */ - public function isSuccess(): bool - { - echo "\n BlockMarkDeletedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; - } -} \ No newline at end of file diff --git a/src/Services/Landing/Page/Result/BlockMarkUnDeletedResult.php b/src/Services/Landing/Page/Result/BlockMarkUnDeletedResult.php deleted file mode 100644 index 9fadeb25..00000000 --- a/src/Services/Landing/Page/Result/BlockMarkUnDeletedResult.php +++ /dev/null @@ -1,33 +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\Services\Landing\Page\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class BlockMarkUnDeletedResult extends AbstractResult -{ - /** - * Check if block mark as undeleted operation was successful - * - * @return bool - */ - public function isSuccess(): bool - { - echo "\n BlockMarkUnDeletedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; - } -} \ No newline at end of file diff --git a/src/Services/Landing/Page/Result/BlockVisibilityResult.php b/src/Services/Landing/Page/Result/BlockVisibilityResult.php deleted file mode 100644 index f5f2f377..00000000 --- a/src/Services/Landing/Page/Result/BlockVisibilityResult.php +++ /dev/null @@ -1,33 +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\Services\Landing\Page\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class BlockVisibilityResult extends AbstractResult -{ - /** - * Check if block visibility operation was successful - * - * @return bool - */ - public function isSuccess(): bool - { - echo "\n BlockVisibilityResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; - } -} \ No newline at end of file diff --git a/src/Services/Landing/Page/Service/Page.php b/src/Services/Landing/Page/Service/Page.php index 597ac806..c6e99420 100644 --- a/src/Services/Landing/Page/Service/Page.php +++ b/src/Services/Landing/Page/Service/Page.php @@ -30,14 +30,7 @@ use Bitrix24\SDK\Services\Landing\Page\Result\PageIdByUrlResult; use Bitrix24\SDK\Services\Landing\Page\Result\MarkPageDeletedResult; use Bitrix24\SDK\Services\Landing\Page\Result\MarkPageUnDeletedResult; -use Bitrix24\SDK\Services\Landing\Page\Result\BlockAddedResult; -use Bitrix24\SDK\Services\Landing\Page\Result\BlockCopiedResult; -use Bitrix24\SDK\Services\Landing\Page\Result\BlockDeletedResult; use Bitrix24\SDK\Services\Landing\Page\Result\BlockMovedResult; -use Bitrix24\SDK\Services\Landing\Page\Result\BlockVisibilityResult; -use Bitrix24\SDK\Services\Landing\Page\Result\BlockMarkDeletedResult; -use Bitrix24\SDK\Services\Landing\Page\Result\BlockMarkUnDeletedResult; -use Bitrix24\SDK\Services\Landing\Page\Result\BlockFavoriteResult; use Psr\Log\LoggerInterface; #[ApiServiceMetadata(new Scope(['landing']))] @@ -510,9 +503,9 @@ public function removeEntities(int $lid, array $data): UpdatedItemResult 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-add-block.html', 'Method for adding a new block to the page.' )] - public function addBlock(int $lid, array $fields): BlockAddedResult + public function addBlock(int $lid, array $fields): AddedItemResult { - return new BlockAddedResult( + return new AddedItemResult( $this->core->call('landing.landing.addblock', [ 'lid' => $lid, 'fields' => $fields @@ -537,7 +530,7 @@ public function addBlock(int $lid, array $fields): BlockAddedResult 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-copy-block.html', 'Method copies a block from one page to another.' )] - public function copyBlock(int $lid, int $block, array $params = []): BlockCopiedResult + public function copyBlock(int $lid, int $block, array $params = []): AddedItemResult { $callParams = [ 'lid' => $lid, @@ -548,7 +541,7 @@ public function copyBlock(int $lid, int $block, array $params = []): BlockCopied $callParams['params'] = $params; } - return new BlockCopiedResult( + return new AddedItemResult( $this->core->call('landing.landing.copyblock', $callParams) ); } @@ -569,9 +562,9 @@ public function copyBlock(int $lid, int $block, array $params = []): BlockCopied 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-delete-block.html', 'Method for deleting a block from the page.' )] - public function deleteBlock(int $lid, int $block): BlockDeletedResult + public function deleteBlock(int $lid, int $block): DeletedItemResult { - return new BlockDeletedResult( + return new DeletedItemResult( $this->core->call('landing.landing.deleteblock', [ 'lid' => $lid, 'block' => $block @@ -680,9 +673,9 @@ public function moveBlock(int $lid, int $block, array $params = []): BlockMovedR 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-hide-block.html', 'Method hides a block from the page.' )] - public function hideBlock(int $lid, int $block): BlockVisibilityResult + public function hideBlock(int $lid, int $block): UpdatedItemResult { - return new BlockVisibilityResult( + return new UpdatedItemResult( $this->core->call('landing.landing.hideblock', [ 'lid' => $lid, 'block' => $block @@ -706,9 +699,9 @@ public function hideBlock(int $lid, int $block): BlockVisibilityResult 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-show-block.html', 'Method displays a block on the page.' )] - public function showBlock(int $lid, int $block): BlockVisibilityResult + public function showBlock(int $lid, int $block): UpdatedItemResult { - return new BlockVisibilityResult( + return new UpdatedItemResult( $this->core->call('landing.landing.showblock', [ 'lid' => $lid, 'block' => $block @@ -732,9 +725,9 @@ public function showBlock(int $lid, int $block): BlockVisibilityResult 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-mark-deleted-block.html', 'Method marks a block as deleted but does not physically remove it.' )] - public function markBlockDeleted(int $lid, int $block): BlockMarkDeletedResult + public function markBlockDeleted(int $lid, int $block): UpdatedItemResult { - return new BlockMarkDeletedResult( + return new UpdatedItemResult( $this->core->call('landing.landing.markdeletedblock', [ 'lid' => $lid, 'block' => $block @@ -758,9 +751,9 @@ public function markBlockDeleted(int $lid, int $block): BlockMarkDeletedResult 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-mark-undeleted-block.html', 'Method restores a block that has been marked as deleted.' )] - public function markBlockUnDeleted(int $lid, int $block): BlockMarkUnDeletedResult + public function markBlockUnDeleted(int $lid, int $block): UpdatedItemResult { - return new BlockMarkUnDeletedResult( + return new UpdatedItemResult( $this->core->call('landing.landing.markundeletedblock', [ 'lid' => $lid, 'block' => $block @@ -788,9 +781,9 @@ public function markBlockUnDeleted(int $lid, int $block): BlockMarkUnDeletedResu 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-favorite-block.html', 'Method saves an existing block on the page to My Blocks.' )] - public function addBlockToFavorites(int $lid, int $block, array $meta): BlockFavoriteResult + public function addBlockToFavorites(int $lid, int $block, array $meta): AddedItemResult { - return new BlockFavoriteResult( + return new AddedItemResult( $this->core->call('landing.landing.favoriteBlock', [ 'lid' => $lid, 'block' => $block, @@ -814,9 +807,9 @@ public function addBlockToFavorites(int $lid, int $block, array $meta): BlockFav 'https://apidocs.bitrix24.com/api-reference/landing/page/block-methods/landing-landing-unfavorite-block.html', 'Method removes a block that was saved in My Blocks.' )] - public function removeBlockFromFavorites(int $blockId): BlockFavoriteResult + public function removeBlockFromFavorites(int $blockId): UpdatedItemResult { - return new BlockFavoriteResult( + return new UpdatedItemResult( $this->core->call('landing.landing.unFavoriteBlock', [ 'blockId' => $blockId ]) diff --git a/tests/Integration/Services/Landing/Page/Service/PageTest.php b/tests/Integration/Services/Landing/Page/Service/PageTest.php index 570f2f10..bfad355c 100644 --- a/tests/Integration/Services/Landing/Page/Service/PageTest.php +++ b/tests/Integration/Services/Landing/Page/Service/PageTest.php @@ -44,6 +44,18 @@ #[CoversMethod(Page::class, 'markUnDeleted')] #[CoversMethod(Page::class, 'move')] #[CoversMethod(Page::class, 'removeEntities')] +#[CoversMethod(Page::class, 'addBlock')] +#[CoversMethod(Page::class, 'copyBlock')] +#[CoversMethod(Page::class, 'deleteBlock')] +#[CoversMethod(Page::class, 'moveBlockDown')] +#[CoversMethod(Page::class, 'moveBlockUp')] +#[CoversMethod(Page::class, 'moveBlock')] +#[CoversMethod(Page::class, 'hideBlock')] +#[CoversMethod(Page::class, 'showBlock')] +#[CoversMethod(Page::class, 'markBlockDeleted')] +#[CoversMethod(Page::class, 'markBlockUnDeleted')] +#[CoversMethod(Page::class, 'addBlockToFavorites')] +#[CoversMethod(Page::class, 'removeBlockFromFavorites')] #[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\Landing\Page\Service\Page::class)] class PageTest extends TestCase { @@ -567,4 +579,311 @@ public function testDelete(): void $pages = $pagesResult->getPages(); self::assertEmpty($pages, 'Page should be deleted and not found in list'); } + + /** + * Helper method to create a test page with blocks + */ + protected function createTestPageWithBlocks(): int + { + $siteId = $this->createTestSite(); + + $pageFields = [ + 'TITLE' => 'Test Page for Blocks ' . time(), + 'CODE' => 'testpageblocks' . time(), + 'SITE_ID' => $siteId + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + + $this->createdPageIds[] = $pageId; + + return $pageId; + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testAddBlock(): void + { + $pageId = $this->createTestPageWithBlocks(); + + $blockFields = [ + 'CODE' => '01.big_with_text_blocks', + 'ACTIVE' => 'Y' + ]; + + $blockAddedResult = $this->pageService->addBlock($pageId, $blockFields); + $blockId = $blockAddedResult->getId(); + + self::assertGreaterThan(0, $blockId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testCopyBlock(): void + { + $pageId1 = $this->createTestPageWithBlocks(); + $pageId2 = $this->createTestPageWithBlocks(); + + // First add a block to the first page + $blockFields = [ + 'CODE' => '01.big_with_text_blocks', + 'ACTIVE' => 'Y' + ]; + + $blockAddedResult = $this->pageService->addBlock($pageId1, $blockFields); + $originalBlockId = $blockAddedResult->getId(); + + // Copy the block to the second page + $blockCopiedResult = $this->pageService->copyBlock($pageId2, $originalBlockId); + $copiedBlockId = $blockCopiedResult->getId(); + + self::assertGreaterThan(0, $copiedBlockId); + self::assertNotEquals($originalBlockId, $copiedBlockId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testHideAndShowBlock(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Add a block + $blockFields = [ + 'CODE' => '01.big_with_text_blocks', + 'ACTIVE' => 'Y' + ]; + + $blockAddedResult = $this->pageService->addBlock($pageId, $blockFields); + $blockId = $blockAddedResult->getId(); + + // Hide the block + $hideResult = $this->pageService->hideBlock($pageId, $blockId); + self::assertTrue($hideResult->isSuccess()); + + // Show the block + $showResult = $this->pageService->showBlock($pageId, $blockId); + self::assertTrue($showResult->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testMoveBlockUpAndDown(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Add two blocks + $blockFields1 = [ + 'CODE' => '01.big_with_text_blocks', + 'ACTIVE' => 'Y' + ]; + + $block1Result = $this->pageService->addBlock($pageId, $blockFields1); + $block1Id = $block1Result->getId(); + + $blockFields2 = [ + //'CODE' => '02.three_cols_text_big', + 'CODE' => '02.three_cols_big_1', + 'ACTIVE' => 'Y', + 'AFTER_ID' => $block1Id, + ]; + + $block2Result = $this->pageService->addBlock($pageId, $blockFields2); + $block2Id = $block2Result->getId(); + + // Move first block down + $moveDownResult = $this->pageService->moveBlockDown($pageId, $block1Id); + self::assertTrue($moveDownResult->isSuccess()); + + + // Move second block up + $moveUpResult = $this->pageService->moveBlockUp($pageId, $block1Id); + self::assertTrue($moveUpResult->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testMoveBlockBetweenPages(): void + { + $pageId1 = $this->createTestPageWithBlocks(); + $pageId2 = $this->createTestPageWithBlocks(); + + // Add a block to the first page + $blockFields = [ + 'CODE' => '01.big_with_text_blocks', + 'ACTIVE' => 'Y' + ]; + + $blockAddedResult = $this->pageService->addBlock($pageId1, $blockFields); + $blockId = $blockAddedResult->getId(); + + // Move the block to the second page + $moveResult = $this->pageService->moveBlock($pageId2, $blockId); + self::assertTrue($moveResult->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testMarkBlockDeletedAndUnDeleted(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Add a block + $blockFields = [ + 'CODE' => '01.big_with_text_blocks', + 'ACTIVE' => 'Y' + ]; + + $blockAddedResult = $this->pageService->addBlock($pageId, $blockFields); + $blockId = $blockAddedResult->getId(); + + // Mark block as deleted + $markDeletedResult = $this->pageService->markBlockDeleted($pageId, $blockId); + self::assertTrue($markDeletedResult->isSuccess()); + + // Mark block as undeleted + $markUnDeletedResult = $this->pageService->markBlockUnDeleted($pageId, $blockId); + self::assertTrue($markUnDeletedResult->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testAddAndRemoveBlockFromFavorites(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Add a block + $blockFields = [ + 'CODE' => '01.big_with_text_blocks', + 'ACTIVE' => 'Y' + ]; + + $blockAddedResult = $this->pageService->addBlock($pageId, $blockFields); + $blockId = $blockAddedResult->getId(); + + // Add block to favorites + $meta = [ + 'name' => 'Test Favorite Block', + 'section' => ['text'], + 'preview' => 'https://example.com/preview.jpg' + ]; + + $favoriteResult = $this->pageService->addBlockToFavorites($pageId, $blockId, $meta); + $favoriteBlockId = $favoriteResult->getId(); + + // Verify it was added (should return a number) + self::assertGreaterThan(0, $favoriteBlockId); + + // Remove block from favorites + $removeFavoriteResult = $this->pageService->removeBlockFromFavorites($favoriteBlockId); + self::assertTrue($removeFavoriteResult->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testDeleteBlock(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Add a block + $blockFields = [ + 'CODE' => '01.big_with_text_blocks', + 'ACTIVE' => 'Y' + ]; + + $blockAddedResult = $this->pageService->addBlock($pageId, $blockFields); + $blockId = $blockAddedResult->getId(); + + // Delete the block + $deleteResult = $this->pageService->deleteBlock($pageId, $blockId); + self::assertTrue($deleteResult->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testCopyBlockWithParameters(): void + { + $pageId1 = $this->createTestPageWithBlocks(); + $pageId2 = $this->createTestPageWithBlocks(); + + // Add two blocks to the first page + $blockFields1 = [ + 'CODE' => '01.big_with_text_blocks', + 'ACTIVE' => 'Y' + ]; + + + $block1Result = $this->pageService->addBlock($pageId1, $blockFields1); + $block1Id = $block1Result->getId(); + + $blockFields2 = [ + 'CODE' => '02.three_cols_big_1', + 'ACTIVE' => 'Y', + 'AFTER_ID' => $block1Id, + ]; + $block2Result = $this->pageService->addBlock($pageId1, $blockFields2); + $block2Id = $block2Result->getId(); + + // Copy block with AFTER_ID parameter + $params = ['AFTER_ID' => $block1Id]; + $blockCopiedResult = $this->pageService->copyBlock($pageId2, $block2Id, $params); + $copiedBlockId = $blockCopiedResult->getId(); + + self::assertGreaterThan(0, $copiedBlockId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testMoveBlockWithParameters(): void + { + $pageId1 = $this->createTestPageWithBlocks(); + $pageId2 = $this->createTestPageWithBlocks(); + + // Add two blocks to the first page + $blockFields1 = [ + 'CODE' => '01.big_with_text_blocks', + 'ACTIVE' => 'Y' + ]; + + + $block1Result = $this->pageService->addBlock($pageId1, $blockFields1); + $block1Id = $block1Result->getId(); + + $blockFields2 = [ + 'CODE' => '02.three_cols_big_1', + 'ACTIVE' => 'Y', + 'AFTER_ID' => $block1Id, + ]; + $block2Result = $this->pageService->addBlock($pageId1, $blockFields2); + $block2Id = $block2Result->getId(); + + // Add a block to the second page to use as reference + $block3Result = $this->pageService->addBlock($pageId2, $blockFields1); + $block3Id = $block3Result->getId(); + + // Move block with AFTER_ID parameter + $params = ['AFTER_ID' => $block3Id]; + $moveResult = $this->pageService->moveBlock($pageId2, $block2Id, $params); + self::assertTrue($moveResult->isSuccess()); + } } \ No newline at end of file From 7f7681ceab55916800562915ce9ebfa580372060 Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Thu, 2 Oct 2025 15:29:49 +0400 Subject: [PATCH 08/14] add SysPage service --- .../Landing/LandingServiceBuilder.php | 15 ++ .../Landing/Page/Result/BlockMovedResult.php | 4 - .../SysPage/Result/SysPageItemResult.php | 32 ++++ .../SysPage/Result/SysPageListResult.php | 38 ++++ .../Landing/SysPage/Result/SysPageResult.php | 44 +++++ .../SysPage/Result/SysPageUrlResult.php | 32 ++++ .../Landing/SysPage/Service/SysPage.php | 181 ++++++++++++++++++ src/Services/Landing/SysPage/SysPageType.php | 25 +++ 8 files changed, 367 insertions(+), 4 deletions(-) create mode 100644 src/Services/Landing/SysPage/Result/SysPageItemResult.php create mode 100644 src/Services/Landing/SysPage/Result/SysPageListResult.php create mode 100644 src/Services/Landing/SysPage/Result/SysPageResult.php create mode 100644 src/Services/Landing/SysPage/Result/SysPageUrlResult.php create mode 100644 src/Services/Landing/SysPage/Service/SysPage.php create mode 100644 src/Services/Landing/SysPage/SysPageType.php diff --git a/src/Services/Landing/LandingServiceBuilder.php b/src/Services/Landing/LandingServiceBuilder.php index 02f68148..08d48b7a 100644 --- a/src/Services/Landing/LandingServiceBuilder.php +++ b/src/Services/Landing/LandingServiceBuilder.php @@ -54,4 +54,19 @@ public function page(): Page\Service\Page return $this->serviceCache[__METHOD__]; } + + /** + * Get SysPage service + */ + public function sysPage(): SysPage\Service\SysPage + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new SysPage\Service\SysPage( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } } diff --git a/src/Services/Landing/Page/Result/BlockMovedResult.php b/src/Services/Landing/Page/Result/BlockMovedResult.php index 9147b67a..a3e17ab5 100644 --- a/src/Services/Landing/Page/Result/BlockMovedResult.php +++ b/src/Services/Landing/Page/Result/BlockMovedResult.php @@ -24,10 +24,6 @@ class BlockMovedResult extends AbstractResult */ public function isSuccess(): bool { - echo "\n BlockMovedResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/Landing/SysPage/Result/SysPageItemResult.php b/src/Services/Landing/SysPage/Result/SysPageItemResult.php new file mode 100644 index 00000000..a3066bda --- /dev/null +++ b/src/Services/Landing/SysPage/Result/SysPageItemResult.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\Landing\SysPage\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * SysPage item result. Represents a system page with its type and configuration. + * Based on the documentation, each system page item contains: + * + * @property-read non-negative-int $id System page ID + * @property-read string $type Type of system page (mainpage, catalog, personal, cart, order, payment, compare) + * @property-read non-negative-int $siteId Site ID where this system page is configured + * @property-read non-negative-int $pageId Landing page ID that serves as this system page type + * @property-read string $active Whether the system page is active (Y/N) + * @property-read string $url URL of the system page + * @property-read string $title Title of the system page + */ +class SysPageItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Landing/SysPage/Result/SysPageListResult.php b/src/Services/Landing/SysPage/Result/SysPageListResult.php new file mode 100644 index 00000000..f46eef8e --- /dev/null +++ b/src/Services/Landing/SysPage/Result/SysPageListResult.php @@ -0,0 +1,38 @@ + + * + * 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\Landing\SysPage\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SysPageListResult extends AbstractResult +{ + /** + * @return SysPageItemResult[] + * @throws BaseException + */ + public function getSysPages(): array + { + echo "\n SysPageListResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $sysPage) { + $res[] = new SysPageItemResult($sysPage); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Landing/SysPage/Result/SysPageResult.php b/src/Services/Landing/SysPage/Result/SysPageResult.php new file mode 100644 index 00000000..0508d1a8 --- /dev/null +++ b/src/Services/Landing/SysPage/Result/SysPageResult.php @@ -0,0 +1,44 @@ + + * + * 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\Landing\SysPage\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SysPageResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function isSuccess(): bool + { + echo "\n SysPageResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + $result = $this->getCoreResponse()->getResponseData()->getResult(); + + // If result is boolean true or array with success status + if (is_bool($result)) { + return $result; + } + + if (is_array($result) && isset($result['success'])) { + return (bool)$result['success']; + } + + // Default to true if no explicit result (void operations) + return true; + } +} \ No newline at end of file diff --git a/src/Services/Landing/SysPage/Result/SysPageUrlResult.php b/src/Services/Landing/SysPage/Result/SysPageUrlResult.php new file mode 100644 index 00000000..efa653f9 --- /dev/null +++ b/src/Services/Landing/SysPage/Result/SysPageUrlResult.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\Landing\SysPage\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SysPageUrlResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getUrl(): string + { + echo "\n SysPageUrlResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return (string)$this->getCoreResponse()->getResponseData()->getResult(); + } +} \ No newline at end of file diff --git a/src/Services/Landing/SysPage/Service/SysPage.php b/src/Services/Landing/SysPage/Service/SysPage.php new file mode 100644 index 00000000..cc00ce48 --- /dev/null +++ b/src/Services/Landing/SysPage/Service/SysPage.php @@ -0,0 +1,181 @@ + + * + * 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\Landing\SysPage\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\Services\AbstractService; +use Bitrix24\SDK\Services\Landing\SysPage\Result\SysPageResult; +use Bitrix24\SDK\Services\Landing\SysPage\Result\SysPageListResult; +use Bitrix24\SDK\Services\Landing\SysPage\Result\SysPageUrlResult; +use Bitrix24\SDK\Services\Landing\SysPage\SysPageType; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['landing']))] +class SysPage extends AbstractService +{ + public function __construct(CoreInterface $core, LoggerInterface $logger) + { + parent::__construct($core, $logger); + } + + /** + * Sets a special page for the site. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/special-pages/landing-syspage-set.html + * + * @param int $siteId Site ID + * @param SysPageType|string $type Type of special page + * @param int|null $pageId Page ID that will be considered of this type within the site. If not provided, the page type will be removed. + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.syspage.set', + 'https://apidocs.bitrix24.com/api-reference/landing/page/special-pages/landing-syspage-set.html', + 'Sets a special page for the site.' + )] + public function set(int $siteId, SysPageType|string $type, ?int $pageId = null): SysPageResult + { + $typeValue = $type instanceof SysPageType ? $type->value : $type; + + $params = [ + 'id' => $siteId, + 'type' => $typeValue, + ]; + + if ($pageId !== null) { + $params['lid'] = $pageId; + } + + return new SysPageResult( + $this->core->call('landing.syspage.set', $params) + ); + } + + /** + * Retrieves the list of special pages. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/special-pages/landing-syspage-get.html + * + * @param int $siteId Site ID + * @param bool|null $active If true, only active site pages will be returned (default is all) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.syspage.get', + 'https://apidocs.bitrix24.com/api-reference/landing/page/special-pages/landing-syspage-get.html', + 'Returns a list of site pages that are set as special.' + )] + public function get(int $siteId, ?bool $active = null): SysPageListResult + { + $params = [ + 'id' => $siteId, + ]; + + if ($active !== null) { + $params['active'] = $active; + } + + return new SysPageListResult( + $this->core->call('landing.syspage.get', $params) + ); + } + + /** + * Retrieves the address of the special page on the site. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/special-pages/landing-syspage-get-special-page.html + * + * @param int $siteId Site ID + * @param SysPageType|string $type Type of special page + * @param array|null $additional Optional array of additional parameters to be added to the URL + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.syspage.getSpecialPage', + 'https://apidocs.bitrix24.com/api-reference/landing/page/special-pages/landing-syspage-get-special-page.html', + 'Returns the address of a special page on the site.' + )] + public function getSpecialPage(int $siteId, SysPageType|string $type, ?array $additional = null): SysPageUrlResult + { + $typeValue = $type instanceof SysPageType ? $type->value : $type; + + $params = [ + 'siteId' => $siteId, + 'type' => $typeValue, + ]; + + if ($additional !== null) { + $params['additional'] = $additional; + } + + return new SysPageUrlResult( + $this->core->call('landing.syspage.getSpecialPage', $params) + ); + } + + /** + * Deletes all mentions of the page as a special one. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/special-pages/landing-syspage-delete-for-landing.html + * + * @param int $pageId Page ID + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.syspage.deleteForLanding', + 'https://apidocs.bitrix24.com/api-reference/landing/page/special-pages/landing-syspage-delete-for-landing.html', + 'Deletes all mentions of the page as a special one.' + )] + public function deleteForLanding(int $pageId): SysPageResult + { + return new SysPageResult( + $this->core->call('landing.syspage.deleteForLanding', ['id' => $pageId]) + ); + } + + /** + * Deletes all special pages. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/page/special-pages/landing-syspage-delete-for-site.html + * + * @param int $siteId Site ID + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.syspage.deleteForSite', + 'https://apidocs.bitrix24.com/api-reference/landing/page/special-pages/landing-syspage-delete-for-site.html', + 'Deletes all special pages of the site.' + )] + public function deleteForSite(int $siteId): SysPageResult + { + return new SysPageResult( + $this->core->call('landing.syspage.deleteForSite', ['id' => $siteId]) + ); + } +} \ No newline at end of file diff --git a/src/Services/Landing/SysPage/SysPageType.php b/src/Services/Landing/SysPage/SysPageType.php new file mode 100644 index 00000000..4c8428bd --- /dev/null +++ b/src/Services/Landing/SysPage/SysPageType.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\Landing\SysPage; + +enum SysPageType: string +{ + case mainpage = 'mainpage'; + case catalog = 'catalog'; + case personal = 'personal'; + case cart = 'cart'; + case order = 'order'; + case payment = 'payment'; + case compare = 'compare'; +} \ No newline at end of file From 77ed3ba6f956de867adb8a189f12b5c0eb7a1b10 Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Thu, 2 Oct 2025 15:58:16 +0400 Subject: [PATCH 09/14] add SysPage tests; run tests and linters --- Makefile | 5 + phpunit.xml.dist | 3 + .../Landing/Page/Result/BlockMovedResult.php | 4 +- .../SysPage/Result/SysPageItemResult.php | 4 +- .../SysPage/Result/SysPageListResult.php | 6 +- .../Landing/SysPage/Result/SysPageResult.php | 20 +- .../SysPage/Result/SysPageUrlResult.php | 8 +- .../Landing/SysPage/Service/SysPage.php | 18 +- src/Services/Landing/SysPage/SysPageType.php | 2 +- .../Landing/Page/Service/PageTest.php | 70 ++-- .../Landing/SysPage/Service/SysPageTest.php | 332 ++++++++++++++++++ 11 files changed, 393 insertions(+), 79 deletions(-) create mode 100644 tests/Integration/Services/Landing/SysPage/Service/SysPageTest.php diff --git a/Makefile b/Makefile index 8d34d3d6..a46be211 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,7 @@ help: @echo "test-integration-sale-payment-item-shipment - run PaymentItemShipment integration tests" @echo "test-integration-sale-property-relation - run PropertyRelation integration tests" @echo "test-integration-landing-page - run Landing Page integration tests" + @echo "test-integration-landing-syspage - run Landing SysPage integration tests" .PHONY: docker-init @@ -208,6 +209,10 @@ test-integration-landing-site: test-integration-landing-page: docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_landing_page +.PHONY: test-integration-landing-syspage +test-integration-landing-syspage: + docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_landing_syspage + .PHONY: test-integration-sale-status test-integration-sale-status: docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_sale_status diff --git a/phpunit.xml.dist b/phpunit.xml.dist index af28bf74..58e8df5b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -154,6 +154,9 @@ ./tests/Integration/Services/Landing/Page/ + + ./tests/Integration/Services/Landing/SysPage/ + ./tests/Integration/Services/Sale/Shipment/ diff --git a/src/Services/Landing/Page/Result/BlockMovedResult.php b/src/Services/Landing/Page/Result/BlockMovedResult.php index a3e17ab5..8e13a509 100644 --- a/src/Services/Landing/Page/Result/BlockMovedResult.php +++ b/src/Services/Landing/Page/Result/BlockMovedResult.php @@ -19,11 +19,9 @@ class BlockMovedResult extends AbstractResult { /** * Check if block move operation was successful - * - * @return bool */ public function isSuccess(): bool { return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } -} \ No newline at end of file +} diff --git a/src/Services/Landing/SysPage/Result/SysPageItemResult.php b/src/Services/Landing/SysPage/Result/SysPageItemResult.php index a3066bda..122d74e2 100644 --- a/src/Services/Landing/SysPage/Result/SysPageItemResult.php +++ b/src/Services/Landing/SysPage/Result/SysPageItemResult.php @@ -18,7 +18,7 @@ /** * SysPage item result. Represents a system page with its type and configuration. * Based on the documentation, each system page item contains: - * + * * @property-read non-negative-int $id System page ID * @property-read string $type Type of system page (mainpage, catalog, personal, cart, order, payment, compare) * @property-read non-negative-int $siteId Site ID where this system page is configured @@ -29,4 +29,4 @@ */ class SysPageItemResult extends AbstractItem { -} \ No newline at end of file +} diff --git a/src/Services/Landing/SysPage/Result/SysPageListResult.php b/src/Services/Landing/SysPage/Result/SysPageListResult.php index f46eef8e..ffae7428 100644 --- a/src/Services/Landing/SysPage/Result/SysPageListResult.php +++ b/src/Services/Landing/SysPage/Result/SysPageListResult.php @@ -24,10 +24,6 @@ class SysPageListResult extends AbstractResult */ public function getSysPages(): array { - echo "\n SysPageListResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - $res = []; foreach ($this->getCoreResponse()->getResponseData()->getResult() as $sysPage) { $res[] = new SysPageItemResult($sysPage); @@ -35,4 +31,4 @@ public function getSysPages(): array return $res; } -} \ No newline at end of file +} diff --git a/src/Services/Landing/SysPage/Result/SysPageResult.php b/src/Services/Landing/SysPage/Result/SysPageResult.php index 0508d1a8..d34e4730 100644 --- a/src/Services/Landing/SysPage/Result/SysPageResult.php +++ b/src/Services/Landing/SysPage/Result/SysPageResult.php @@ -23,22 +23,6 @@ class SysPageResult extends AbstractResult */ public function isSuccess(): bool { - echo "\n SysPageResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - $result = $this->getCoreResponse()->getResponseData()->getResult(); - - // If result is boolean true or array with success status - if (is_bool($result)) { - return $result; - } - - if (is_array($result) && isset($result['success'])) { - return (bool)$result['success']; - } - - // Default to true if no explicit result (void operations) - return true; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } -} \ No newline at end of file +} diff --git a/src/Services/Landing/SysPage/Result/SysPageUrlResult.php b/src/Services/Landing/SysPage/Result/SysPageUrlResult.php index efa653f9..aef8d58c 100644 --- a/src/Services/Landing/SysPage/Result/SysPageUrlResult.php +++ b/src/Services/Landing/SysPage/Result/SysPageUrlResult.php @@ -23,10 +23,6 @@ class SysPageUrlResult extends AbstractResult */ public function getUrl(): string { - echo "\n SysPageUrlResult \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - return (string)$this->getCoreResponse()->getResponseData()->getResult(); + return (string)$this->getCoreResponse()->getResponseData()->getResult()[0]; } -} \ No newline at end of file +} diff --git a/src/Services/Landing/SysPage/Service/SysPage.php b/src/Services/Landing/SysPage/Service/SysPage.php index cc00ce48..01f2257b 100644 --- a/src/Services/Landing/SysPage/Service/SysPage.php +++ b/src/Services/Landing/SysPage/Service/SysPage.php @@ -54,16 +54,16 @@ public function __construct(CoreInterface $core, LoggerInterface $logger) public function set(int $siteId, SysPageType|string $type, ?int $pageId = null): SysPageResult { $typeValue = $type instanceof SysPageType ? $type->value : $type; - + $params = [ 'id' => $siteId, 'type' => $typeValue, ]; - + if ($pageId !== null) { $params['lid'] = $pageId; } - + return new SysPageResult( $this->core->call('landing.syspage.set', $params) ); @@ -90,11 +90,11 @@ public function get(int $siteId, ?bool $active = null): SysPageListResult $params = [ 'id' => $siteId, ]; - + if ($active !== null) { $params['active'] = $active; } - + return new SysPageListResult( $this->core->call('landing.syspage.get', $params) ); @@ -120,16 +120,16 @@ public function get(int $siteId, ?bool $active = null): SysPageListResult public function getSpecialPage(int $siteId, SysPageType|string $type, ?array $additional = null): SysPageUrlResult { $typeValue = $type instanceof SysPageType ? $type->value : $type; - + $params = [ 'siteId' => $siteId, 'type' => $typeValue, ]; - + if ($additional !== null) { $params['additional'] = $additional; } - + return new SysPageUrlResult( $this->core->call('landing.syspage.getSpecialPage', $params) ); @@ -178,4 +178,4 @@ public function deleteForSite(int $siteId): SysPageResult $this->core->call('landing.syspage.deleteForSite', ['id' => $siteId]) ); } -} \ No newline at end of file +} diff --git a/src/Services/Landing/SysPage/SysPageType.php b/src/Services/Landing/SysPage/SysPageType.php index 4c8428bd..52e9b8d4 100644 --- a/src/Services/Landing/SysPage/SysPageType.php +++ b/src/Services/Landing/SysPage/SysPageType.php @@ -22,4 +22,4 @@ enum SysPageType: string case order = 'order'; case payment = 'payment'; case compare = 'compare'; -} \ No newline at end of file +} diff --git a/tests/Integration/Services/Landing/Page/Service/PageTest.php b/tests/Integration/Services/Landing/Page/Service/PageTest.php index bfad355c..bb52556c 100644 --- a/tests/Integration/Services/Landing/Page/Service/PageTest.php +++ b/tests/Integration/Services/Landing/Page/Service/PageTest.php @@ -614,8 +614,8 @@ public function testAddBlock(): void 'ACTIVE' => 'Y' ]; - $blockAddedResult = $this->pageService->addBlock($pageId, $blockFields); - $blockId = $blockAddedResult->getId(); + $addedItemResult = $this->pageService->addBlock($pageId, $blockFields); + $blockId = $addedItemResult->getId(); self::assertGreaterThan(0, $blockId); } @@ -635,8 +635,8 @@ public function testCopyBlock(): void 'ACTIVE' => 'Y' ]; - $blockAddedResult = $this->pageService->addBlock($pageId1, $blockFields); - $originalBlockId = $blockAddedResult->getId(); + $addedItemResult = $this->pageService->addBlock($pageId1, $blockFields); + $originalBlockId = $addedItemResult->getId(); // Copy the block to the second page $blockCopiedResult = $this->pageService->copyBlock($pageId2, $originalBlockId); @@ -660,12 +660,12 @@ public function testHideAndShowBlock(): void 'ACTIVE' => 'Y' ]; - $blockAddedResult = $this->pageService->addBlock($pageId, $blockFields); - $blockId = $blockAddedResult->getId(); + $addedItemResult = $this->pageService->addBlock($pageId, $blockFields); + $blockId = $addedItemResult->getId(); // Hide the block - $hideResult = $this->pageService->hideBlock($pageId, $blockId); - self::assertTrue($hideResult->isSuccess()); + $updatedItemResult = $this->pageService->hideBlock($pageId, $blockId); + self::assertTrue($updatedItemResult->isSuccess()); // Show the block $showResult = $this->pageService->showBlock($pageId, $blockId); @@ -686,8 +686,8 @@ public function testMoveBlockUpAndDown(): void 'ACTIVE' => 'Y' ]; - $block1Result = $this->pageService->addBlock($pageId, $blockFields1); - $block1Id = $block1Result->getId(); + $addedItemResult = $this->pageService->addBlock($pageId, $blockFields1); + $block1Id = $addedItemResult->getId(); $blockFields2 = [ //'CODE' => '02.three_cols_text_big', @@ -697,11 +697,11 @@ public function testMoveBlockUpAndDown(): void ]; $block2Result = $this->pageService->addBlock($pageId, $blockFields2); - $block2Id = $block2Result->getId(); + $block2Result->getId(); // Move first block down - $moveDownResult = $this->pageService->moveBlockDown($pageId, $block1Id); - self::assertTrue($moveDownResult->isSuccess()); + $blockMovedResult = $this->pageService->moveBlockDown($pageId, $block1Id); + self::assertTrue($blockMovedResult->isSuccess()); // Move second block up @@ -724,12 +724,12 @@ public function testMoveBlockBetweenPages(): void 'ACTIVE' => 'Y' ]; - $blockAddedResult = $this->pageService->addBlock($pageId1, $blockFields); - $blockId = $blockAddedResult->getId(); + $addedItemResult = $this->pageService->addBlock($pageId1, $blockFields); + $blockId = $addedItemResult->getId(); // Move the block to the second page - $moveResult = $this->pageService->moveBlock($pageId2, $blockId); - self::assertTrue($moveResult->isSuccess()); + $blockMovedResult = $this->pageService->moveBlock($pageId2, $blockId); + self::assertTrue($blockMovedResult->isSuccess()); } /** @@ -746,12 +746,12 @@ public function testMarkBlockDeletedAndUnDeleted(): void 'ACTIVE' => 'Y' ]; - $blockAddedResult = $this->pageService->addBlock($pageId, $blockFields); - $blockId = $blockAddedResult->getId(); + $addedItemResult = $this->pageService->addBlock($pageId, $blockFields); + $blockId = $addedItemResult->getId(); // Mark block as deleted - $markDeletedResult = $this->pageService->markBlockDeleted($pageId, $blockId); - self::assertTrue($markDeletedResult->isSuccess()); + $updatedItemResult = $this->pageService->markBlockDeleted($pageId, $blockId); + self::assertTrue($updatedItemResult->isSuccess()); // Mark block as undeleted $markUnDeletedResult = $this->pageService->markBlockUnDeleted($pageId, $blockId); @@ -772,8 +772,8 @@ public function testAddAndRemoveBlockFromFavorites(): void 'ACTIVE' => 'Y' ]; - $blockAddedResult = $this->pageService->addBlock($pageId, $blockFields); - $blockId = $blockAddedResult->getId(); + $addedItemResult = $this->pageService->addBlock($pageId, $blockFields); + $blockId = $addedItemResult->getId(); // Add block to favorites $meta = [ @@ -789,8 +789,8 @@ public function testAddAndRemoveBlockFromFavorites(): void self::assertGreaterThan(0, $favoriteBlockId); // Remove block from favorites - $removeFavoriteResult = $this->pageService->removeBlockFromFavorites($favoriteBlockId); - self::assertTrue($removeFavoriteResult->isSuccess()); + $updatedItemResult = $this->pageService->removeBlockFromFavorites($favoriteBlockId); + self::assertTrue($updatedItemResult->isSuccess()); } /** @@ -807,12 +807,12 @@ public function testDeleteBlock(): void 'ACTIVE' => 'Y' ]; - $blockAddedResult = $this->pageService->addBlock($pageId, $blockFields); - $blockId = $blockAddedResult->getId(); + $addedItemResult = $this->pageService->addBlock($pageId, $blockFields); + $blockId = $addedItemResult->getId(); // Delete the block - $deleteResult = $this->pageService->deleteBlock($pageId, $blockId); - self::assertTrue($deleteResult->isSuccess()); + $deletedItemResult = $this->pageService->deleteBlock($pageId, $blockId); + self::assertTrue($deletedItemResult->isSuccess()); } /** @@ -831,8 +831,8 @@ public function testCopyBlockWithParameters(): void ]; - $block1Result = $this->pageService->addBlock($pageId1, $blockFields1); - $block1Id = $block1Result->getId(); + $addedItemResult = $this->pageService->addBlock($pageId1, $blockFields1); + $block1Id = $addedItemResult->getId(); $blockFields2 = [ 'CODE' => '02.three_cols_big_1', @@ -866,8 +866,8 @@ public function testMoveBlockWithParameters(): void ]; - $block1Result = $this->pageService->addBlock($pageId1, $blockFields1); - $block1Id = $block1Result->getId(); + $addedItemResult = $this->pageService->addBlock($pageId1, $blockFields1); + $block1Id = $addedItemResult->getId(); $blockFields2 = [ 'CODE' => '02.three_cols_big_1', @@ -883,7 +883,7 @@ public function testMoveBlockWithParameters(): void // Move block with AFTER_ID parameter $params = ['AFTER_ID' => $block3Id]; - $moveResult = $this->pageService->moveBlock($pageId2, $block2Id, $params); - self::assertTrue($moveResult->isSuccess()); + $blockMovedResult = $this->pageService->moveBlock($pageId2, $block2Id, $params); + self::assertTrue($blockMovedResult->isSuccess()); } } \ No newline at end of file diff --git a/tests/Integration/Services/Landing/SysPage/Service/SysPageTest.php b/tests/Integration/Services/Landing/SysPage/Service/SysPageTest.php new file mode 100644 index 00000000..922c56da --- /dev/null +++ b/tests/Integration/Services/Landing/SysPage/Service/SysPageTest.php @@ -0,0 +1,332 @@ + + * + * 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\Landing\SysPage\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Landing\SysPage\Service\SysPage; +use Bitrix24\SDK\Services\Landing\SysPage\SysPageType; +use Bitrix24\SDK\Services\Landing\Site\Service\Site; +use Bitrix24\SDK\Services\Landing\Page\Service\Page; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; + +/** + * Class SysPageTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\Landing\SysPage\Service + */ +#[CoversMethod(SysPage::class, 'set')] +#[CoversMethod(SysPage::class, 'get')] +#[CoversMethod(SysPage::class, 'getSpecialPage')] +#[CoversMethod(SysPage::class, 'deleteForLanding')] +#[CoversMethod(SysPage::class, 'deleteForSite')] +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\Landing\SysPage\Service\SysPage::class)] +class SysPageTest extends TestCase +{ + use CustomBitrix24Assertions; + + protected SysPage $sysPageService; + + protected Site $siteService; + + protected Page $pageService; + + protected array $createdPageIds = []; + + protected array $createdSiteIds = []; + + protected function setUp(): void + { + $serviceBuilder = Fabric::getServiceBuilder(); + $this->sysPageService = $serviceBuilder->getLandingScope()->sysPage(); + $this->siteService = $serviceBuilder->getLandingScope()->site(); + $this->pageService = $serviceBuilder->getLandingScope()->page(); + } + + protected function tearDown(): void + { + // Clean up system page settings before deleting pages and sites + foreach ($this->createdSiteIds as $siteId) { + try { + $this->sysPageService->deleteForSite($siteId); + } catch (\Exception) { + // Ignore if site or system pages don't exist + } + } + + // Clean up created pages + foreach ($this->createdPageIds as $createdPageId) { + try { + $this->pageService->delete($createdPageId); + } catch (\Exception) { + // Ignore if page doesn't exist + } + } + + // Clean up created sites + foreach ($this->createdSiteIds as $createdSiteId) { + try { + $this->siteService->delete($createdSiteId); + } catch (\Exception) { + // Ignore if site doesn't exist + } + } + } + + /** + * Helper method to create a test site + */ + protected function createTestSite(): int + { + $siteFields = [ + 'TITLE' => 'Test Site for SysPage ' . time(), + 'CODE' => 'testsitesyspage' . time(), + 'TYPE' => 'PAGE' + ]; + + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); + $this->createdSiteIds[] = $siteId; + + return $siteId; + } + + /** + * Helper method to create a test page + */ + protected function createTestPage(int $siteId): int + { + $pageFields = [ + 'TITLE' => 'Test Page for SysPage ' . time(), + 'CODE' => 'testpagesyspage' . time(), + 'SITE_ID' => $siteId, + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + return $pageId; + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testSetWithEnum(): void + { + $siteId = $this->createTestSite(); + $pageId = $this->createTestPage($siteId); + + $sysPageResult = $this->sysPageService->set($siteId, SysPageType::personal, $pageId); + + self::assertTrue($sysPageResult->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testSetWithString(): void + { + $siteId = $this->createTestSite(); + $pageId = $this->createTestPage($siteId); + + $sysPageResult = $this->sysPageService->set($siteId, 'cart', $pageId); + + self::assertTrue($sysPageResult->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testSetWithoutPageId(): void + { + $siteId = $this->createTestSite(); + + // First set a system page + $pageId = $this->createTestPage($siteId); + $this->sysPageService->set($siteId, SysPageType::catalog, $pageId); + + // Then remove it by calling set without pageId + $sysPageResult = $this->sysPageService->set($siteId, SysPageType::catalog); + + self::assertTrue($sysPageResult->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGet(): void + { + $siteId = $this->createTestSite(); + $pageId = $this->createTestPage($siteId); + + // Set a system page first + $this->sysPageService->set($siteId, SysPageType::personal, $pageId); + + $sysPageListResult = $this->sysPageService->get($siteId); + $sysPages = $sysPageListResult->getSysPages(); + + self::assertIsArray($sysPages); + // At least one system page should be set + self::assertGreaterThanOrEqual(1, count($sysPages)); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetWithActiveFilter(): void + { + $siteId = $this->createTestSite(); + $pageId = $this->createTestPage($siteId); + + // Set a system page first + $this->sysPageService->set($siteId, SysPageType::personal, $pageId); + + $sysPageListResult = $this->sysPageService->get($siteId, true); + $sysPages = $sysPageListResult->getSysPages(); + + self::assertIsArray($sysPages); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetSpecialPageWithEnum(): void + { + $siteId = $this->createTestSite(); + $pageId = $this->createTestPage($siteId); + + // Set a system page first + $this->sysPageService->set($siteId, SysPageType::personal, $pageId); + + $sysPageUrlResult = $this->sysPageService->getSpecialPage($siteId, SysPageType::personal); + $url = $sysPageUrlResult->getUrl(); + + self::assertIsString($url); + self::assertNotEmpty($url); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetSpecialPageWithString(): void + { + $siteId = $this->createTestSite(); + $pageId = $this->createTestPage($siteId); + + // Set a system page first + $this->sysPageService->set($siteId, 'cart', $pageId); + + $sysPageUrlResult = $this->sysPageService->getSpecialPage($siteId, 'cart'); + $url = $sysPageUrlResult->getUrl(); + + self::assertIsString($url); + self::assertNotEmpty($url); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetSpecialPageWithAdditionalParams(): void + { + $siteId = $this->createTestSite(); + $pageId = $this->createTestPage($siteId); + + // Set a system page first + $this->sysPageService->set($siteId, SysPageType::personal, $pageId); + + $additional = ['SECTION' => 'private']; + $sysPageUrlResult = $this->sysPageService->getSpecialPage($siteId, SysPageType::personal, $additional); + $url = $sysPageUrlResult->getUrl(); + + self::assertIsString($url); + self::assertNotEmpty($url); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testDeleteForLanding(): void + { + $siteId = $this->createTestSite(); + $pageId = $this->createTestPage($siteId); + + // Set a system page first + $this->sysPageService->set($siteId, SysPageType::personal, $pageId); + + $sysPageResult = $this->sysPageService->deleteForLanding($pageId); + + self::assertTrue($sysPageResult->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testDeleteForSite(): void + { + $siteId = $this->createTestSite(); + $pageId = $this->createTestPage($siteId); + + // Set multiple system pages + $this->sysPageService->set($siteId, SysPageType::personal, $pageId); + $this->sysPageService->set($siteId, SysPageType::cart, $pageId); + + $sysPageResult = $this->sysPageService->deleteForSite($siteId); + + self::assertTrue($sysPageResult->isSuccess()); + } + + /** + * Test that all enum values are valid + * + * @throws BaseException + * @throws TransportException + */ + public function testAllSysPageTypes(): void + { + $siteId = $this->createTestSite(); + $pageId = $this->createTestPage($siteId); + + $types = [ + SysPageType::mainpage, + SysPageType::catalog, + SysPageType::personal, + SysPageType::cart, + SysPageType::order, + SysPageType::payment, + SysPageType::compare, + ]; + + foreach ($types as $type) { + $result = $this->sysPageService->set($siteId, $type, $pageId); + self::assertTrue($result->isSuccess(), 'Failed to set system page type: ' . $type->value); + } + + // Clean up - remove all system pages + $this->sysPageService->deleteForSite($siteId); + } +} From 914a48c9214ed091e681db70a07ac4e56f8353b3 Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Thu, 2 Oct 2025 16:02:21 +0400 Subject: [PATCH 10/14] update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 285464cb..2eb36057 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,13 @@ - `unPublicFolder` unpublishes the site's folder - `markFolderDelete` marks the folder as deleted - `markFolderUnDelete` restores the folder from the trash +- Added service `Services\Landing\SysPage\Service\SysPage` with support methods, + see [landing.syspage.* methods](https://github.com/bitrix24/b24phpsdk/issues/267): + - `set` sets a special page for the site + - `get` retrieves the list of special pages + - `getSpecialPage` retrieves the address of the special page on the site + - `deleteForLanding` deletes all mentions of the page as a special one + - `deleteForSite` deletes all special pages of the site - Added service `Services\Sale\Shipment\Service\Shipment` with support methods, see [sale.shipment.* methods](https://github.com/bitrix24/b24phpsdk/issues/250): - `add` adds a shipment From c27866b14330b26dbda08300939a2eb73085236d Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Thu, 2 Oct 2025 17:14:43 +0400 Subject: [PATCH 11/14] add Template service and tests; run tests --- CHANGELOG.md | 7 + Makefile | 5 + phpunit.xml.dist | 3 + .../Landing/LandingServiceBuilder.php | 15 + .../Template/Result/TemplateItemResult.php | 33 ++ .../Template/Result/TemplateRefSetResult.php | 31 ++ .../Template/Result/TemplateRefsResult.php | 31 ++ .../Template/Result/TemplatesResult.php | 34 +++ .../Landing/Template/Service/Template.php | 180 +++++++++++ .../Landing/Template/Service/TemplateTest.php | 287 ++++++++++++++++++ 10 files changed, 626 insertions(+) create mode 100644 src/Services/Landing/Template/Result/TemplateItemResult.php create mode 100644 src/Services/Landing/Template/Result/TemplateRefSetResult.php create mode 100644 src/Services/Landing/Template/Result/TemplateRefsResult.php create mode 100644 src/Services/Landing/Template/Result/TemplatesResult.php create mode 100644 src/Services/Landing/Template/Service/Template.php create mode 100644 tests/Integration/Services/Landing/Template/Service/TemplateTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 622e7372..6ff728e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,13 @@ - `getSpecialPage` retrieves the address of the special page on the site - `deleteForLanding` deletes all mentions of the page as a special one - `deleteForSite` deletes all special pages of the site +- Added service `Services\Landing\Template\Service\Template` with support methods, + see [landing.template.* methods](https://github.com/bitrix24/b24phpsdk/issues/267): + - `getList` retrieves a list of templates + - `getLandingRef` retrieves a list of included areas for the page + - `getSiteRef` retrieves a list of included areas for the site + - `setLandingRef` sets the included areas for the page + - `setSiteRef` sets the included areas for the site - Added service `Services\Paysystem\Handler\Service\Handler` with support methods, see [pay_system.handler.* methods](https://github.com/bitrix24/b24phpsdk/issues/260): - `add` adds a payment system handler diff --git a/Makefile b/Makefile index 02785159..582799ea 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,7 @@ help: @echo "test-integration-sale-property-relation - run PropertyRelation integration tests" @echo "test-integration-landing-page - run Landing Page integration tests" @echo "test-integration-landing-syspage - run Landing SysPage integration tests" + @echo "test-integration-scope-landing-template - run Landing Template integration tests" .PHONY: docker-init @@ -218,6 +219,10 @@ test-integration-scope-sale: test-integration-scope-landing: docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_scope_landing +.PHONY: test-integration-scope-landing-template +test-integration-scope-landing-template: + docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_scope_landing_template + .PHONY: test-integration-landing-site test-integration-landing-site: docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_landing_site diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 6f51adb4..5cdcbec0 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -181,6 +181,9 @@ ./tests/Integration/Services/Sale/ShipmentItem/ + + ./tests/Integration/Services/Landing/Template/ + diff --git a/src/Services/Landing/LandingServiceBuilder.php b/src/Services/Landing/LandingServiceBuilder.php index 08d48b7a..1e9ad42c 100644 --- a/src/Services/Landing/LandingServiceBuilder.php +++ b/src/Services/Landing/LandingServiceBuilder.php @@ -69,4 +69,19 @@ public function sysPage(): SysPage\Service\SysPage return $this->serviceCache[__METHOD__]; } + + /** + * Get Template service + */ + public function template(): Template\Service\Template + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Template\Service\Template( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } } diff --git a/src/Services/Landing/Template/Result/TemplateItemResult.php b/src/Services/Landing/Template/Result/TemplateItemResult.php new file mode 100644 index 00000000..d01f5466 --- /dev/null +++ b/src/Services/Landing/Template/Result/TemplateItemResult.php @@ -0,0 +1,33 @@ + + * + * 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\Landing\Template\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-negative-int $ID Template identifier + * @property-read string $ACTIVE Template activity: Y / N + * @property-read non-negative-int $AREA_COUNT Number of areas besides content + * @property-read non-negative-int $SORT Sorting + * @property-read string $TITLE Title + * @property-read string $XML_ID External code + * @property-read string $CONTENT Template markup + * @property-read non-negative-int $CREATED_BY_ID Identifier of the user who created the template + * @property-read non-negative-int $MODIFIED_BY_ID Identifier of the user who modified the template + * @property-read string $DATE_CREATE Creation date + * @property-read string $DATE_MODIFY Modification date + */ +class TemplateItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Landing/Template/Result/TemplateRefSetResult.php b/src/Services/Landing/Template/Result/TemplateRefSetResult.php new file mode 100644 index 00000000..a5c08036 --- /dev/null +++ b/src/Services/Landing/Template/Result/TemplateRefSetResult.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\Landing\Template\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class TemplateRefSetResult extends AbstractResult +{ + /** + * Returns true on success or error on failure + * + * @return bool + * @throws BaseException + */ + public function isSuccess(): bool + { + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} diff --git a/src/Services/Landing/Template/Result/TemplateRefsResult.php b/src/Services/Landing/Template/Result/TemplateRefsResult.php new file mode 100644 index 00000000..795220fd --- /dev/null +++ b/src/Services/Landing/Template/Result/TemplateRefsResult.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\Landing\Template\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class TemplateRefsResult extends AbstractResult +{ + /** + * Returns array where keys are included area identifiers and values are page identifiers + * + * @return array + * @throws BaseException + */ + public function getRefs(): array + { + return (array)$this->getCoreResponse()->getResponseData()->getResult(); + } +} \ No newline at end of file diff --git a/src/Services/Landing/Template/Result/TemplatesResult.php b/src/Services/Landing/Template/Result/TemplatesResult.php new file mode 100644 index 00000000..7808344f --- /dev/null +++ b/src/Services/Landing/Template/Result/TemplatesResult.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\Landing\Template\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class TemplatesResult extends AbstractResult +{ + /** + * @return TemplateItemResult[] + * @throws BaseException + */ + public function getTemplates(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $template) { + $res[] = new TemplateItemResult($template); + } + + return $res; + } +} diff --git a/src/Services/Landing/Template/Service/Template.php b/src/Services/Landing/Template/Service/Template.php new file mode 100644 index 00000000..6ae113e7 --- /dev/null +++ b/src/Services/Landing/Template/Service/Template.php @@ -0,0 +1,180 @@ + + * + * 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\Landing\Template\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\Services\AbstractService; +use Bitrix24\SDK\Services\Landing\Template\Result\TemplatesResult; +use Bitrix24\SDK\Services\Landing\Template\Result\TemplateRefsResult; +use Bitrix24\SDK\Services\Landing\Template\Result\TemplateRefSetResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['landing']))] +class Template extends AbstractService +{ + public function __construct(CoreInterface $core, LoggerInterface $logger) + { + parent::__construct($core, $logger); + } + + /** + * Retrieves a list of templates + * + * @link https://apidocs.bitrix24.com/api-reference/landing/template/landing-template-get-list.html + * + * @param array $select Optional array of fields to select + * @param array $filter Optional array of filter conditions + * @param array $order Optional array of order conditions + * + * @return TemplatesResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.template.getlist', + 'https://apidocs.bitrix24.com/api-reference/landing/template/landing-template-get-list.html', + 'Method retrieves a list of templates.' + )] + public function getList(array $select = [], array $filter = [], array $order = []): TemplatesResult + { + $params = []; + if ($select !== []) { + $params['select'] = $select; + } + if ($filter !== []) { + $params['filter'] = $filter; + } + if ($order !== []) { + $params['order'] = $order; + } + + $requestParams = []; + if ($params !== []) { + $requestParams['params'] = $params; + } + + return new TemplatesResult( + $this->core->call('landing.template.getlist', $requestParams) + ); + } + + /** + * Retrieves a list of included areas for the page + * + * @link https://apidocs.bitrix24.com/api-reference/landing/template/landing-template-get-landing-ref.html + * + * @param int $id Page identifier + * + * @return TemplateRefsResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.template.getLandingRef', + 'https://apidocs.bitrix24.com/api-reference/landing/template/landing-template-get-landing-ref.html', + 'Method retrieves a list of included areas for the page. The keys of the returned array are the identifiers of the included areas, and the values are the identifiers of the pages.' + )] + public function getLandingRef(int $id): TemplateRefsResult + { + return new TemplateRefsResult( + $this->core->call('landing.template.getLandingRef', ['id' => $id]) + ); + } + + /** + * Retrieves a list of included areas for the site + * + * @link https://apidocs.bitrix24.com/api-reference/landing/template/landing-template-get-site-ref.html + * + * @param int $id Site identifier + * + * @return TemplateRefsResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.template.getSiteRef', + 'https://apidocs.bitrix24.com/api-reference/landing/template/landing-template-get-site-ref.html', + 'Method retrieves a list of included areas for the site. The keys of the returned array are the identifiers of the included areas, and the values are the page identifiers.' + )] + public function getSiteRef(int $id): TemplateRefsResult + { + return new TemplateRefsResult( + $this->core->call('landing.template.getSiteRef', ['id' => $id]) + ); + } + + /** + * Sets the included areas for the page + * + * @link https://apidocs.bitrix24.com/api-reference/landing/template/landing-template-set-landing-ref.html + * + * @param int $id Identifier of the page + * @param array $data Array of data to set (if the array is empty or not provided, the included areas will be reset). The keys of the array are the identifiers of the areas, and the values are the identifiers of the pages that need to be set as the area + * + * @return TemplateRefSetResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.template.setLandingRef', + 'https://apidocs.bitrix24.com/api-reference/landing/template/landing-template-set-landing-ref.html', + 'Method sets the included areas for the page within a specific template (the page must already be linked to the template via the TPL_ID field). It will return true on success or an error.' + )] + public function setLandingRef(int $id, array $data = []): TemplateRefSetResult + { + $params = ['id' => $id]; + if ($data !== []) { + $params['data'] = $data; + } + + return new TemplateRefSetResult( + $this->core->call('landing.template.setLandingRef', $params) + ); + } + + /** + * Sets the included areas for the site + * + * @link https://apidocs.bitrix24.com/api-reference/landing/template/landing-template-set-site-ref.html + * + * @param int $id Site identifier + * @param array $data Array of data to set (if the array is empty or not provided, the included areas will be reset). The keys of the array are the area identifiers, and the values are the identifiers of the pages that need to be set as the area + * + * @return TemplateRefSetResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.template.setSiteRef', + 'https://apidocs.bitrix24.com/api-reference/landing/template/landing-template-set-site-ref.html', + 'Method sets the included areas for the site within a specific template (the site or page must already be linked to the template via the TPL_ID field). It will return true on success or an error.' + )] + public function setSiteRef(int $id, array $data = []): TemplateRefSetResult + { + $params = ['id' => $id]; + if ($data !== []) { + $params['data'] = $data; + } + + return new TemplateRefSetResult( + $this->core->call('landing.template.setSiteRef', $params) + ); + } +} diff --git a/tests/Integration/Services/Landing/Template/Service/TemplateTest.php b/tests/Integration/Services/Landing/Template/Service/TemplateTest.php new file mode 100644 index 00000000..85987cf2 --- /dev/null +++ b/tests/Integration/Services/Landing/Template/Service/TemplateTest.php @@ -0,0 +1,287 @@ + + * + * 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\Landing\Template\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Landing\Template\Service\Template; +use Bitrix24\SDK\Services\Landing\Site\Service\Site; +use Bitrix24\SDK\Services\Landing\Page\Service\Page; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; + +/** + * Class TemplateTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\Landing\Template\Service + */ +#[CoversMethod(Template::class, 'getList')] +#[CoversMethod(Template::class, 'getLandingRef')] +#[CoversMethod(Template::class, 'getSiteRef')] +#[CoversMethod(Template::class, 'setLandingRef')] +#[CoversMethod(Template::class, 'setSiteRef')] +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\Landing\Template\Service\Template::class)] +class TemplateTest extends TestCase +{ + use CustomBitrix24Assertions; + + protected Template $templateService; + protected Site $siteService; + protected Page $pageService; + + protected array $createdPageIds = []; + protected array $createdSiteIds = []; + + protected function setUp(): void + { + $serviceBuilder = Fabric::getServiceBuilder(); + $this->templateService = $serviceBuilder->getLandingScope()->template(); + $this->siteService = $serviceBuilder->getLandingScope()->site(); + $this->pageService = $serviceBuilder->getLandingScope()->page(); + } + + protected function tearDown(): void + { + // Clean up created pages + foreach ($this->createdPageIds as $createdPageId) { + try { + $this->pageService->delete($createdPageId); + } catch (\Exception) { + // Ignore if page doesn't exist + } + } + + // Clean up created sites + foreach ($this->createdSiteIds as $createdSiteId) { + try { + $this->siteService->delete($createdSiteId); + } catch (\Exception) { + // Ignore if site doesn't exist + } + } + } + + /** + * Helper method to create a test site + */ + protected function createTestSite(): int + { + $siteFields = [ + 'TITLE' => 'Test Site for Template ' . time(), + 'CODE' => 'testsitetemplate' . time(), + 'TYPE' => 'PAGE' + ]; + + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); + $this->createdSiteIds[] = $siteId; + + return $siteId; + } + + /** + * Helper method to create a test page + */ + protected function createTestPage(int $siteId): int + { + $pageFields = [ + 'TITLE' => 'Test Page for Template ' . time(), + 'CODE' => 'testpagetemplate' . time(), + 'SITE_ID' => $siteId, + ]; + + $addedItemResult = $this->pageService->add($pageFields); + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + return $pageId; + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetList(): void + { + $templatesResult = $this->templateService->getList(); + $templates = $templatesResult->getTemplates(); + + self::assertIsArray($templates); + self::assertNotEmpty($templates, 'There should be at least some predefined templates'); + + // Test first template structure + $firstTemplate = $templates[0]; + self::assertGreaterThan(0, $firstTemplate->ID); + self::assertIsString($firstTemplate->TITLE); + self::assertIsString($firstTemplate->XML_ID); + self::assertIsString($firstTemplate->ACTIVE); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetListWithParameters(): void + { + $select = ['ID', 'TITLE', 'XML_ID']; + $filter = ['>ID' => 0]; + $order = ['ID' => 'DESC']; + + $templatesResult = $this->templateService->getList($select, $filter, $order); + $templates = $templatesResult->getTemplates(); + + self::assertIsArray($templates); + self::assertNotEmpty($templates); + + // Verify that templates are ordered by ID in descending order + if (count($templates) > 1) { + self::assertGreaterThanOrEqual($templates[1]->ID, $templates[0]->ID); + } + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetLandingRef(): void + { + $siteId = $this->createTestSite(); + $pageId = $this->createTestPage($siteId); + + $refsResult = $this->templateService->getLandingRef($pageId); + $refs = $refsResult->getRefs(); + + self::assertIsArray($refs); + // The refs array might be empty if no template areas are configured for this page + // This is expected behavior for a newly created page + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetSiteRef(): void + { + $siteId = $this->createTestSite(); + + $refsResult = $this->templateService->getSiteRef($siteId); + $refs = $refsResult->getRefs(); + + self::assertIsArray($refs); + // The refs array might be empty if no template areas are configured for this site + // This is expected behavior for a newly created site + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testSetLandingRef(): void + { + $siteId = $this->createTestSite(); + $pageId = $this->createTestPage($siteId); + + // Test setting empty data (should reset included areas) + $setResult = $this->templateService->setLandingRef($pageId, []); + self::assertTrue($setResult->isSuccess()); + + // Verify that refs are now empty + $refsResult = $this->templateService->getLandingRef($pageId); + $refs = $refsResult->getRefs(); + self::assertIsArray($refs); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testSetSiteRef(): void + { + $siteId = $this->createTestSite(); + + // Test setting empty data (should reset included areas) + $setResult = $this->templateService->setSiteRef($siteId, []); + self::assertTrue($setResult->isSuccess()); + + // Verify that refs are now empty + $refsResult = $this->templateService->getSiteRef($siteId); + $refs = $refsResult->getRefs(); + self::assertIsArray($refs); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testSetLandingRefWithData(): void + { + $siteId = $this->createTestSite(); + $pageId = $this->createTestPage($siteId); + + // Create additional pages to use as template areas + $headerPageId = $this->createTestPage($siteId); + $footerPageId = $this->createTestPage($siteId); + + // Test setting template areas data + $data = [ + 1 => $headerPageId, // Area 1 -> header page + 2 => $footerPageId // Area 2 -> footer page + ]; + + $setResult = $this->templateService->setLandingRef($pageId, $data); + self::assertTrue($setResult->isSuccess()); + + // Verify that refs are set correctly + $refsResult = $this->templateService->getLandingRef($pageId); + $refs = $refsResult->getRefs(); + self::assertIsArray($refs); + + // Note: The actual refs might not match exactly what we set + // because the page might not be linked to a template that supports these areas + // This is expected behavior according to the API documentation + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testSetSiteRefWithData(): void + { + $siteId = $this->createTestSite(); + + // Create pages to use as template areas + $headerPageId = $this->createTestPage($siteId); + $footerPageId = $this->createTestPage($siteId); + + // Test setting template areas data + $data = [ + 1 => $headerPageId, // Area 1 -> header page + 2 => $footerPageId // Area 2 -> footer page + ]; + + $setResult = $this->templateService->setSiteRef($siteId, $data); + self::assertTrue($setResult->isSuccess()); + + // Verify that refs are set correctly + $refsResult = $this->templateService->getSiteRef($siteId); + $refs = $refsResult->getRefs(); + self::assertIsArray($refs); + + // Note: The actual refs might not match exactly what we set + // because the site might not be linked to a template that supports these areas + // This is expected behavior according to the API documentation + } +} \ No newline at end of file From cb7cf719cb06144ba209c426ebdd2329d93f1ea9 Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Fri, 3 Oct 2025 09:39:59 +0400 Subject: [PATCH 12/14] run linters --- .../Template/Result/TemplateItemResult.php | 2 +- .../Template/Result/TemplateRefSetResult.php | 3 +- .../Template/Result/TemplateRefsResult.php | 7 ++- .../Landing/Template/Service/Template.php | 7 +-- .../Landing/Template/Service/TemplateTest.php | 51 ++++++++++--------- 5 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/Services/Landing/Template/Result/TemplateItemResult.php b/src/Services/Landing/Template/Result/TemplateItemResult.php index d01f5466..dc8ca4ba 100644 --- a/src/Services/Landing/Template/Result/TemplateItemResult.php +++ b/src/Services/Landing/Template/Result/TemplateItemResult.php @@ -30,4 +30,4 @@ */ class TemplateItemResult extends AbstractItem { -} \ No newline at end of file +} diff --git a/src/Services/Landing/Template/Result/TemplateRefSetResult.php b/src/Services/Landing/Template/Result/TemplateRefSetResult.php index a5c08036..64924f5c 100644 --- a/src/Services/Landing/Template/Result/TemplateRefSetResult.php +++ b/src/Services/Landing/Template/Result/TemplateRefSetResult.php @@ -20,8 +20,7 @@ class TemplateRefSetResult extends AbstractResult { /** * Returns true on success or error on failure - * - * @return bool + * * @throws BaseException */ public function isSuccess(): bool diff --git a/src/Services/Landing/Template/Result/TemplateRefsResult.php b/src/Services/Landing/Template/Result/TemplateRefsResult.php index 795220fd..6947a7f9 100644 --- a/src/Services/Landing/Template/Result/TemplateRefsResult.php +++ b/src/Services/Landing/Template/Result/TemplateRefsResult.php @@ -20,12 +20,11 @@ class TemplateRefsResult extends AbstractResult { /** * Returns array where keys are included area identifiers and values are page identifiers - * - * @return array + * * @throws BaseException */ public function getRefs(): array { - return (array)$this->getCoreResponse()->getResponseData()->getResult(); + return $this->getCoreResponse()->getResponseData()->getResult(); } -} \ No newline at end of file +} diff --git a/src/Services/Landing/Template/Service/Template.php b/src/Services/Landing/Template/Service/Template.php index 6ae113e7..a3c31927 100644 --- a/src/Services/Landing/Template/Service/Template.php +++ b/src/Services/Landing/Template/Service/Template.php @@ -42,7 +42,6 @@ public function __construct(CoreInterface $core, LoggerInterface $logger) * @param array $filter Optional array of filter conditions * @param array $order Optional array of order conditions * - * @return TemplatesResult * @throws BaseException * @throws TransportException */ @@ -57,9 +56,11 @@ public function getList(array $select = [], array $filter = [], array $order = [ if ($select !== []) { $params['select'] = $select; } + if ($filter !== []) { $params['filter'] = $filter; } + if ($order !== []) { $params['order'] = $order; } @@ -81,7 +82,6 @@ public function getList(array $select = [], array $filter = [], array $order = [ * * @param int $id Page identifier * - * @return TemplateRefsResult * @throws BaseException * @throws TransportException */ @@ -104,7 +104,6 @@ public function getLandingRef(int $id): TemplateRefsResult * * @param int $id Site identifier * - * @return TemplateRefsResult * @throws BaseException * @throws TransportException */ @@ -128,7 +127,6 @@ public function getSiteRef(int $id): TemplateRefsResult * @param int $id Identifier of the page * @param array $data Array of data to set (if the array is empty or not provided, the included areas will be reset). The keys of the array are the identifiers of the areas, and the values are the identifiers of the pages that need to be set as the area * - * @return TemplateRefSetResult * @throws BaseException * @throws TransportException */ @@ -157,7 +155,6 @@ public function setLandingRef(int $id, array $data = []): TemplateRefSetResult * @param int $id Site identifier * @param array $data Array of data to set (if the array is empty or not provided, the included areas will be reset). The keys of the array are the area identifiers, and the values are the identifiers of the pages that need to be set as the area * - * @return TemplateRefSetResult * @throws BaseException * @throws TransportException */ diff --git a/tests/Integration/Services/Landing/Template/Service/TemplateTest.php b/tests/Integration/Services/Landing/Template/Service/TemplateTest.php index 85987cf2..1227f9a7 100644 --- a/tests/Integration/Services/Landing/Template/Service/TemplateTest.php +++ b/tests/Integration/Services/Landing/Template/Service/TemplateTest.php @@ -39,10 +39,13 @@ class TemplateTest extends TestCase use CustomBitrix24Assertions; protected Template $templateService; + protected Site $siteService; + protected Page $pageService; protected array $createdPageIds = []; + protected array $createdSiteIds = []; protected function setUp(): void @@ -161,8 +164,8 @@ public function testGetLandingRef(): void $siteId = $this->createTestSite(); $pageId = $this->createTestPage($siteId); - $refsResult = $this->templateService->getLandingRef($pageId); - $refs = $refsResult->getRefs(); + $templateRefsResult = $this->templateService->getLandingRef($pageId); + $refs = $templateRefsResult->getRefs(); self::assertIsArray($refs); // The refs array might be empty if no template areas are configured for this page @@ -177,8 +180,8 @@ public function testGetSiteRef(): void { $siteId = $this->createTestSite(); - $refsResult = $this->templateService->getSiteRef($siteId); - $refs = $refsResult->getRefs(); + $templateRefsResult = $this->templateService->getSiteRef($siteId); + $refs = $templateRefsResult->getRefs(); self::assertIsArray($refs); // The refs array might be empty if no template areas are configured for this site @@ -195,12 +198,12 @@ public function testSetLandingRef(): void $pageId = $this->createTestPage($siteId); // Test setting empty data (should reset included areas) - $setResult = $this->templateService->setLandingRef($pageId, []); - self::assertTrue($setResult->isSuccess()); + $templateRefSetResult = $this->templateService->setLandingRef($pageId, []); + self::assertTrue($templateRefSetResult->isSuccess()); // Verify that refs are now empty - $refsResult = $this->templateService->getLandingRef($pageId); - $refs = $refsResult->getRefs(); + $templateRefsResult = $this->templateService->getLandingRef($pageId); + $refs = $templateRefsResult->getRefs(); self::assertIsArray($refs); } @@ -213,12 +216,12 @@ public function testSetSiteRef(): void $siteId = $this->createTestSite(); // Test setting empty data (should reset included areas) - $setResult = $this->templateService->setSiteRef($siteId, []); - self::assertTrue($setResult->isSuccess()); + $templateRefSetResult = $this->templateService->setSiteRef($siteId, []); + self::assertTrue($templateRefSetResult->isSuccess()); // Verify that refs are now empty - $refsResult = $this->templateService->getSiteRef($siteId); - $refs = $refsResult->getRefs(); + $templateRefsResult = $this->templateService->getSiteRef($siteId); + $refs = $templateRefsResult->getRefs(); self::assertIsArray($refs); } @@ -230,7 +233,7 @@ public function testSetLandingRefWithData(): void { $siteId = $this->createTestSite(); $pageId = $this->createTestPage($siteId); - + // Create additional pages to use as template areas $headerPageId = $this->createTestPage($siteId); $footerPageId = $this->createTestPage($siteId); @@ -241,14 +244,14 @@ public function testSetLandingRefWithData(): void 2 => $footerPageId // Area 2 -> footer page ]; - $setResult = $this->templateService->setLandingRef($pageId, $data); - self::assertTrue($setResult->isSuccess()); + $templateRefSetResult = $this->templateService->setLandingRef($pageId, $data); + self::assertTrue($templateRefSetResult->isSuccess()); // Verify that refs are set correctly - $refsResult = $this->templateService->getLandingRef($pageId); - $refs = $refsResult->getRefs(); + $templateRefsResult = $this->templateService->getLandingRef($pageId); + $refs = $templateRefsResult->getRefs(); self::assertIsArray($refs); - + // Note: The actual refs might not match exactly what we set // because the page might not be linked to a template that supports these areas // This is expected behavior according to the API documentation @@ -261,7 +264,7 @@ public function testSetLandingRefWithData(): void public function testSetSiteRefWithData(): void { $siteId = $this->createTestSite(); - + // Create pages to use as template areas $headerPageId = $this->createTestPage($siteId); $footerPageId = $this->createTestPage($siteId); @@ -272,14 +275,14 @@ public function testSetSiteRefWithData(): void 2 => $footerPageId // Area 2 -> footer page ]; - $setResult = $this->templateService->setSiteRef($siteId, $data); - self::assertTrue($setResult->isSuccess()); + $templateRefSetResult = $this->templateService->setSiteRef($siteId, $data); + self::assertTrue($templateRefSetResult->isSuccess()); // Verify that refs are set correctly - $refsResult = $this->templateService->getSiteRef($siteId); - $refs = $refsResult->getRefs(); + $templateRefsResult = $this->templateService->getSiteRef($siteId); + $refs = $templateRefsResult->getRefs(); self::assertIsArray($refs); - + // Note: The actual refs might not match exactly what we set // because the site might not be linked to a template that supports these areas // This is expected behavior according to the API documentation From af565f988b9f94b6f62a5dacba4ab5bed1bf107d Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Fri, 3 Oct 2025 15:26:28 +0400 Subject: [PATCH 13/14] add Landing Block tests; run tests and linters --- CHANGELOG.md | 50 ++ Makefile | 4 + phpunit.xml.dist | 3 + .../Block/Result/BlockContentItemResult.php | 38 ++ .../Block/Result/BlockContentResult.php | 28 + .../Landing/Block/Result/BlockItemResult.php | 28 + .../Block/Result/BlockManifestItemResult.php | 35 ++ .../Block/Result/BlockManifestResult.php | 28 + .../Landing/Block/Result/BlockResult.php | 28 + .../Landing/Block/Result/BlocksResult.php | 34 + .../Result/RepositoryBlockItemResult.php | 30 + .../Result/RepositoryBlockItemsResult.php | 38 ++ .../Block/Result/RepositoryBlocksResult.php | 40 ++ .../Block/Result/RepositoryContentResult.php | 29 + .../Block/Result/RepositoryItemResult.php | 30 + .../Landing/Block/Result/RepositoryResult.php | 28 + .../Landing/Block/Result/UpdateResult.php | 29 + .../Landing/Block/Result/UploadFileResult.php | 73 +++ src/Services/Landing/Block/Service/Block.php | 586 ++++++++++++++++++ .../Landing/LandingServiceBuilder.php | 15 + .../Landing/Block/Service/BlockTest.php | 431 +++++++++++++ 21 files changed, 1605 insertions(+) create mode 100644 src/Services/Landing/Block/Result/BlockContentItemResult.php create mode 100644 src/Services/Landing/Block/Result/BlockContentResult.php create mode 100644 src/Services/Landing/Block/Result/BlockItemResult.php create mode 100644 src/Services/Landing/Block/Result/BlockManifestItemResult.php create mode 100644 src/Services/Landing/Block/Result/BlockManifestResult.php create mode 100644 src/Services/Landing/Block/Result/BlockResult.php create mode 100644 src/Services/Landing/Block/Result/BlocksResult.php create mode 100644 src/Services/Landing/Block/Result/RepositoryBlockItemResult.php create mode 100644 src/Services/Landing/Block/Result/RepositoryBlockItemsResult.php create mode 100644 src/Services/Landing/Block/Result/RepositoryBlocksResult.php create mode 100644 src/Services/Landing/Block/Result/RepositoryContentResult.php create mode 100644 src/Services/Landing/Block/Result/RepositoryItemResult.php create mode 100644 src/Services/Landing/Block/Result/RepositoryResult.php create mode 100644 src/Services/Landing/Block/Result/UpdateResult.php create mode 100644 src/Services/Landing/Block/Result/UploadFileResult.php create mode 100644 src/Services/Landing/Block/Service/Block.php create mode 100644 tests/Integration/Services/Landing/Block/Service/BlockTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ff728e4..63621562 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,56 @@ - `getSpecialPage` retrieves the address of the special page on the site - `deleteForLanding` deletes all mentions of the page as a special one - `deleteForSite` deletes all special pages of the site +- Added service `Services\Landing\Page\Service\Page` with support methods, + see [landing.landing.* methods](https://github.com/bitrix24/b24phpsdk/issues/267): + - `add` adds a page + - `addByTemplate` creates a page from a template + - `copy` copies a page + - `delete` deletes a page + - `update` updates page parameters + - `getList` retrieves a list of pages + - `getAdditionalFields` returns additional fields of the page + - `getPreview` returns the preview image URL of the page + - `getPublicUrl` returns the full URL of the page + - `resolveIdByPublicUrl` resolves page ID by its public URL + - `publish` publishes the page + - `unpublish` unpublishes the page + - `markDeleted` marks the page as deleted + - `markUnDeleted` restores the page from the trash + - `move` moves a page to another site or folder + - `removeEntities` removes entities from the page + - `addBlock` adds a block to the page + - `copyBlock` copies a block within the page + - `deleteBlock` deletes a block from the page + - `moveBlockDown` moves a block down on the page + - `moveBlockUp` moves a block up on the page + - `moveBlock` moves a block to a specific position + - `hideBlock` hides a block on the page + - `showBlock` shows a block on the page + - `markBlockDeleted` marks a block as deleted + - `markBlockUnDeleted` restores a block from the trash + - `addBlockToFavorites` adds a block to favorites + - `removeBlockFromFavorites` removes a block from favorites +- Added service `Services\Landing\Block\Service\Block` with support methods, + see [landing.block.* methods](https://github.com/bitrix24/b24phpsdk/issues/267): + - `list` retrieves a list of page blocks + - `getById` retrieves a block by its identifier + - `getContent` retrieves the content of a block + - `getManifest` retrieves the manifest of a block + - `getRepository` retrieves blocks from the repository + - `getManifestFile` retrieves block manifest from repository + - `getContentFromRepository` retrieves block content from repository + - `updateNodes` updates block content + - `updateAttrs` updates block node attributes + - `updateStyles` updates block styles + - `updateContent` updates block content with arbitrary content + - `updateCards` bulk updates block cards + - `cloneCard` clones a block card + - `addCard` adds a card with modified content + - `removeCard` removes a block card + - `uploadFile` uploads and attaches image to block + - `changeAnchor` changes anchor symbol code + - `changeNodeName` changes tag name - Added service `Services\Landing\Template\Service\Template` with support methods, see [landing.template.* methods](https://github.com/bitrix24/b24phpsdk/issues/267): - `getList` retrieves a list of templates diff --git a/Makefile b/Makefile index 582799ea..e462958a 100644 --- a/Makefile +++ b/Makefile @@ -223,6 +223,10 @@ test-integration-scope-landing: test-integration-scope-landing-template: docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_scope_landing_template +.PHONY: test-integration-landing-block +test-integration-landing-block: + docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_landing_block + .PHONY: test-integration-landing-site test-integration-landing-site: docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_landing_site diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 5cdcbec0..3e5a979f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -184,6 +184,9 @@ ./tests/Integration/Services/Landing/Template/ + + ./tests/Integration/Services/Landing/Block/ + diff --git a/src/Services/Landing/Block/Result/BlockContentItemResult.php b/src/Services/Landing/Block/Result/BlockContentItemResult.php new file mode 100644 index 00000000..b8405fe3 --- /dev/null +++ b/src/Services/Landing/Block/Result/BlockContentItemResult.php @@ -0,0 +1,38 @@ + + * + * 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\Landing\Block\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-negative-int $id + * @property-read string $sections + * @property-read string $active + * @property-read string $access + * @property-read string $anchor + * @property-read string $php + * @property-read string $designed + * @property-read string $repoId + * @property-read string $content + * @property-read string $content_ext + * @property-read array $css + * @property-read array $js + * @property-read array $assetStrings + * @property-read array $lang + * @property-read array $manifest + * @property-read array $dynamicParams + */ +class BlockContentItemResult extends AbstractItem +{ +} diff --git a/src/Services/Landing/Block/Result/BlockContentResult.php b/src/Services/Landing/Block/Result/BlockContentResult.php new file mode 100644 index 00000000..901fe915 --- /dev/null +++ b/src/Services/Landing/Block/Result/BlockContentResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Block\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class BlockContentResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getContent(): BlockContentItemResult + { + return new BlockContentItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} diff --git a/src/Services/Landing/Block/Result/BlockItemResult.php b/src/Services/Landing/Block/Result/BlockItemResult.php new file mode 100644 index 00000000..0837dcc7 --- /dev/null +++ b/src/Services/Landing/Block/Result/BlockItemResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Block\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-negative-int $id + * @property-read non-negative-int $lid + * @property-read string $code + * @property-read string $name + * @property-read string $active + * @property-read array $meta + */ +class BlockItemResult extends AbstractItem +{ +} diff --git a/src/Services/Landing/Block/Result/BlockManifestItemResult.php b/src/Services/Landing/Block/Result/BlockManifestItemResult.php new file mode 100644 index 00000000..33716047 --- /dev/null +++ b/src/Services/Landing/Block/Result/BlockManifestItemResult.php @@ -0,0 +1,35 @@ + + * + * 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\Landing\Block\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read array $block + * @property-read array $cards + * @property-read array $nodes + * @property-read array $style + * @property-read array $assets + * @property-read array $groups + * @property-read int $timestamp + * @property-read array $attrs + * @property-read array $callbacks + * @property-read array $menu + * @property-read string $namespace + * @property-read string $code + * @property-read string $preview + */ +class BlockManifestItemResult extends AbstractItem +{ +} diff --git a/src/Services/Landing/Block/Result/BlockManifestResult.php b/src/Services/Landing/Block/Result/BlockManifestResult.php new file mode 100644 index 00000000..ee3ecf70 --- /dev/null +++ b/src/Services/Landing/Block/Result/BlockManifestResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Block\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class BlockManifestResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getManifest(): BlockManifestItemResult + { + return new BlockManifestItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} diff --git a/src/Services/Landing/Block/Result/BlockResult.php b/src/Services/Landing/Block/Result/BlockResult.php new file mode 100644 index 00000000..11e39e84 --- /dev/null +++ b/src/Services/Landing/Block/Result/BlockResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Block\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class BlockResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getBlock(): BlockItemResult + { + return new BlockItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} diff --git a/src/Services/Landing/Block/Result/BlocksResult.php b/src/Services/Landing/Block/Result/BlocksResult.php new file mode 100644 index 00000000..eaf61d20 --- /dev/null +++ b/src/Services/Landing/Block/Result/BlocksResult.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\Landing\Block\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class BlocksResult extends AbstractResult +{ + /** + * @return BlockItemResult[] + * @throws BaseException + */ + public function getBlocks(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $block) { + $res[] = new BlockItemResult($block); + } + + return $res; + } +} diff --git a/src/Services/Landing/Block/Result/RepositoryBlockItemResult.php b/src/Services/Landing/Block/Result/RepositoryBlockItemResult.php new file mode 100644 index 00000000..aee946ce --- /dev/null +++ b/src/Services/Landing/Block/Result/RepositoryBlockItemResult.php @@ -0,0 +1,30 @@ + + * + * 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\Landing\Block\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $name + * @property-read array $meta + * @property-read string $new + * @property-read array $type + * @property-read string $specialType + * @property-read string $separator + * @property-read string $app_code + * @property-read array $items + */ +class RepositoryBlockItemResult extends AbstractItem +{ +} diff --git a/src/Services/Landing/Block/Result/RepositoryBlockItemsResult.php b/src/Services/Landing/Block/Result/RepositoryBlockItemsResult.php new file mode 100644 index 00000000..2c6a2ad9 --- /dev/null +++ b/src/Services/Landing/Block/Result/RepositoryBlockItemsResult.php @@ -0,0 +1,38 @@ + + * + * 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\Landing\Block\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $code + * @property-read string $id + * @property-read string $name + * @property-read string $namespace + * @property-read string $new + * @property-read string $version + * @property-read array $type + * @property-read array $section + * @property-read string $system + * @property-read string $description + * @property-read string $preview + * @property-read string $restricted + * @property-read string $repo_id + * @property-read string $app_code + * @property-read string $only_for_license + * @property-read string $requires_updates + */ +class RepositoryBlockItemsResult extends AbstractItem +{ +} diff --git a/src/Services/Landing/Block/Result/RepositoryBlocksResult.php b/src/Services/Landing/Block/Result/RepositoryBlocksResult.php new file mode 100644 index 00000000..8ae31f06 --- /dev/null +++ b/src/Services/Landing/Block/Result/RepositoryBlocksResult.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\Landing\Block\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class RepositoryBlocksResult extends AbstractResult +{ + /** + * @return RepositoryBlockItemResult[] + * @throws BaseException + */ + public function getRepositoryBlocks(): array + { + echo "\n getRepositoryBlocks \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + $result = []; + $rawData = $this->getCoreResponse()->getResponseData()->getResult(); + + foreach ($rawData as $sectionData) { + $result[] = new RepositoryBlockItemResult($sectionData); + } + + return $result; + } +} diff --git a/src/Services/Landing/Block/Result/RepositoryContentResult.php b/src/Services/Landing/Block/Result/RepositoryContentResult.php new file mode 100644 index 00000000..48fe8e23 --- /dev/null +++ b/src/Services/Landing/Block/Result/RepositoryContentResult.php @@ -0,0 +1,29 @@ + + * + * 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\Landing\Block\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class RepositoryContentResult extends AbstractResult +{ + /** + * @return string HTML content from repository block + * @throws BaseException + */ + public function getContent(): string + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} diff --git a/src/Services/Landing/Block/Result/RepositoryItemResult.php b/src/Services/Landing/Block/Result/RepositoryItemResult.php new file mode 100644 index 00000000..e3524df5 --- /dev/null +++ b/src/Services/Landing/Block/Result/RepositoryItemResult.php @@ -0,0 +1,30 @@ + + * + * 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\Landing\Block\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $name + * @property-read array $meta + * @property-read string $new + * @property-read array $type + * @property-read string $specialType + * @property-read string $separator + * @property-read string $app_code + * @property-read array $items + */ +class RepositoryItemResult extends AbstractItem +{ +} diff --git a/src/Services/Landing/Block/Result/RepositoryResult.php b/src/Services/Landing/Block/Result/RepositoryResult.php new file mode 100644 index 00000000..b231cb2d --- /dev/null +++ b/src/Services/Landing/Block/Result/RepositoryResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Landing\Block\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class RepositoryResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getRepository(): RepositoryItemResult + { + return new RepositoryItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} diff --git a/src/Services/Landing/Block/Result/UpdateResult.php b/src/Services/Landing/Block/Result/UpdateResult.php new file mode 100644 index 00000000..0d23a674 --- /dev/null +++ b/src/Services/Landing/Block/Result/UpdateResult.php @@ -0,0 +1,29 @@ + + * + * 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\Landing\Block\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class UpdateResult extends AbstractResult +{ + /** + * @return bool True on success + * @throws BaseException + */ + public function isSuccess(): bool + { + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} diff --git a/src/Services/Landing/Block/Result/UploadFileResult.php b/src/Services/Landing/Block/Result/UploadFileResult.php new file mode 100644 index 00000000..d3cb5a3d --- /dev/null +++ b/src/Services/Landing/Block/Result/UploadFileResult.php @@ -0,0 +1,73 @@ + + * + * 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\Landing\Block\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class UploadFileResult extends AbstractResult +{ + /** + * @return array Contains file ID and URL + * @throws BaseException + */ + public function getUploadFileData(): array + { + echo "\n UploadFileResult \n"; + print_r($this->getCoreResponse()->getResponseData()->getResult()); + echo "\n"; + + return $this->getCoreResponse()->getResponseData()->getResult(); + } + + /** + * @return int File ID + * @throws BaseException + */ + public function getId(): int + { + $result = $this->getCoreResponse()->getResponseData()->getResult(); + return (int)$result['id']; + } + + /** + * @return string File URL + * @throws BaseException + */ + public function getUrl(): string + { + $result = $this->getCoreResponse()->getResponseData()->getResult(); + return $result['src']; + } + + /** + * @deprecated Use getId() instead + * @return int|null File ID + * @throws BaseException + */ + public function getFileId(): ?int + { + return $this->getId(); + } + + /** + * @deprecated Use getUrl() instead + * @return string Direct path to uploaded file + * @throws BaseException + */ + public function getFilePath(): string + { + return $this->getUrl(); + } +} diff --git a/src/Services/Landing/Block/Service/Block.php b/src/Services/Landing/Block/Service/Block.php new file mode 100644 index 00000000..717a6259 --- /dev/null +++ b/src/Services/Landing/Block/Service/Block.php @@ -0,0 +1,586 @@ + + * + * 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\Landing\Block\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\Services\AbstractService; +use Bitrix24\SDK\Services\Landing\Block\Result\BlocksResult; +use Bitrix24\SDK\Services\Landing\Block\Result\BlockResult; +use Bitrix24\SDK\Services\Landing\Block\Result\BlockContentResult; +use Bitrix24\SDK\Services\Landing\Block\Result\BlockManifestResult; +use Bitrix24\SDK\Services\Landing\Block\Result\RepositoryResult; +use Bitrix24\SDK\Services\Landing\Block\Result\RepositoryContentResult; +use Bitrix24\SDK\Services\Landing\Block\Result\UploadFileResult; +use Bitrix24\SDK\Services\Landing\Block\Result\UpdateResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['landing']))] +class Block extends AbstractService +{ + public function __construct(CoreInterface $core, LoggerInterface $logger) + { + parent::__construct($core, $logger); + } + + /** + * Get list of page blocks. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-list.html + * + * @param int|array $lid Page identifier or array of identifiers + * @param array $params Parameters: edit_mode (0|1), deleted (0|1) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.getlist', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-list.html', + 'Method retrieves a list of page blocks.' + )] + public function list($lid, array $params = []): BlocksResult + { + return new BlocksResult( + $this->core->call( + 'landing.block.getlist', + [ + 'lid' => $lid, + 'params' => $params, + ] + ) + ); + } + + /** + * Get block by ID. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-by-id.html + * + * @param int $blockId Block identifier + * @param array $params Parameters: edit_mode (0|1) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.getbyid', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-by-id.html', + 'Method retrieves a block by its identifier.' + )] + public function getById(int $blockId, array $params = []): BlockResult + { + return new BlockResult( + $this->core->call( + 'landing.block.getbyid', + [ + 'block' => $blockId, + 'params' => $params, + ] + ) + ); + } + + /** + * Get content of block. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-content.html + * + * @param int $lid Page identifier + * @param int $blockId Block identifier + * @param int $editMode Editing mode (1) or not (0) + * @param array $params Additional parameters: wrapper_show (0|1) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.getcontent', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-content.html', + 'Method retrieves the content of a block.' + )] + public function getContent(int $lid, int $blockId, int $editMode = 0, array $params = []): BlockContentResult + { + return new BlockContentResult( + $this->core->call( + 'landing.block.getcontent', + [ + 'lid' => $lid, + 'block' => $blockId, + 'editMode' => $editMode, + 'params' => $params, + ] + ) + ); + } + + /** + * Get block manifest. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-manifest.html + * + * @param int $lid Page identifier + * @param int $blockId Block identifier + * @param array $params Parameters: edit_mode (0|1) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.getmanifest', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-manifest.html', + 'Method retrieves the manifest of a specific block already placed on the page.' + )] + public function getManifest(int $lid, int $blockId, array $params = []): BlockManifestResult + { + return new BlockManifestResult( + $this->core->call( + 'landing.block.getmanifest', + [ + 'lid' => $lid, + 'block' => $blockId, + 'params' => $params, + ] + ) + ); + } + + /** + * Get list of blocks from repository. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-repository.html + * + * @param string $section Section code of the repository + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.getrepository', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-repository.html', + 'Method returns a list of blocks from the repository.' + )] + public function getRepository(string $section): RepositoryResult + { + return new RepositoryResult( + $this->core->call( + 'landing.block.getrepository', + [ + 'section' => $section, + ] + ) + ); + } + + /** + * Get block manifest from repository. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-manifest-file.html + * + * @param string $blockCode Block code + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.getmanifestfile', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-manifest-file.html', + 'Method retrieves the manifest of a block from the repository.' + )] + public function getManifestFile(string $blockCode): BlockManifestResult + { + return new BlockManifestResult( + $this->core->call( + 'landing.block.getmanifestfile', + [ + 'code' => $blockCode, + ] + ) + ); + } + + /** + * Get block content from repository. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-content-from-repository.html + * + * @param string $blockCode Block code + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.getcontentfromrepository', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-get-content-from-repository.html', + 'Method retrieves the content of a block from the repository "as is" before adding the block to any page.' + )] + public function getContentFromRepository(string $blockCode): RepositoryContentResult + { + return new RepositoryContentResult( + $this->core->call( + 'landing.block.getcontentfromrepository', + [ + 'code' => $blockCode, + ] + ) + ); + } + + /** + * Update block content. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-update-nodes.html + * + * @param int $lid Page identifier + * @param int $blockId Block identifier + * @param array $data Array of selectors and new values + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.updatenodes', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-update-nodes.html', + 'Method changes the content of the block.' + )] + public function updateNodes(int $lid, int $blockId, array $data): UpdateResult + { + return new UpdateResult( + $this->core->call( + 'landing.block.updatenodes', + [ + 'lid' => $lid, + 'block' => $blockId, + 'data' => $data, + ] + ) + ); + } + + /** + * Update block node attributes. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-update-attrs.html + * + * @param int $lid Page identifier + * @param int $blockId Block identifier + * @param array $data Data for changing node attributes + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.updateattrs', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-update-attrs.html', + 'Method for changing the attributes of a block node.' + )] + public function updateAttrs(int $lid, int $blockId, array $data): UpdateResult + { + return new UpdateResult( + $this->core->call( + 'landing.block.updateattrs', + [ + 'lid' => $lid, + 'block' => $blockId, + 'data' => $data, + ] + ) + ); + } + + /** + * Update block styles. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-update-styles.html + * + * @param int $lid Page identifier + * @param int $blockId Block identifier + * @param array $data Array of selectors with classList and affect parameters + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.updatestyles', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-update-styles.html', + 'Method changes the styles of the block.' + )] + public function updateStyles(int $lid, int $blockId, array $data): UpdateResult + { + return new UpdateResult( + $this->core->call( + 'landing.block.updatestyles', + [ + 'lid' => $lid, + 'block' => $blockId, + 'data' => $data, + ] + ) + ); + } + + /** + * Update block content with arbitrary content. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-update-content.html + * + * @param int $lid Page identifier + * @param int $blockId Block identifier + * @param string $content New content for the block + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.updatecontent', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-update-content.html', + 'Method updates the content of a block already placed on the page to any arbitrary content.' + )] + public function updateContent(int $lid, int $blockId, string $content): UpdateResult + { + return new UpdateResult( + $this->core->call( + 'landing.block.updatecontent', + [ + 'lid' => $lid, + 'block' => $blockId, + 'content' => $content, + ] + ) + ); + } + + /** + * Bulk update block cards. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-update-cards.html + * + * @param int $lid Page identifier + * @param int $blockId Block identifier + * @param array $data Data for bulk updating cards + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.updatecards', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-update-cards.html', + 'Method for bulk updating block cards.' + )] + public function updateCards(int $lid, int $blockId, array $data): UpdateResult + { + return new UpdateResult( + $this->core->call( + 'landing.block.updatecards', + [ + 'lid' => $lid, + 'block' => $blockId, + 'data' => $data, + ] + ) + ); + } + + /** + * Clone block card. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-clone-card.html + * + * @param int $lid Page identifier + * @param int $blockId Block identifier + * @param string $selector Card selector (e.g., '.landing-block-card@0') + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.clonecard', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-clone-card.html', + 'Method clones a block card.' + )] + public function cloneCard(int $lid, int $blockId, string $selector): UpdateResult + { + return new UpdateResult( + $this->core->call( + 'landing.block.clonecard', + [ + 'lid' => $lid, + 'block' => $blockId, + 'selector' => $selector, + ] + ) + ); + } + + /** + * Add card with modified content. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-add-card.html + * + * @param int $lid Page identifier + * @param int $blockId Block identifier + * @param string $selector Card selector (e.g., '.landing-block-card@0') + * @param string $content Content of the new card + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.addcard', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-add-card.html', + 'Method fully replicates the work of landing.block.clonecard but allows inserting a card with modified content right away.' + )] + public function addCard(int $lid, int $blockId, string $selector, string $content): UpdateResult + { + return new UpdateResult( + $this->core->call( + 'landing.block.addcard', + [ + 'lid' => $lid, + 'block' => $blockId, + 'selector' => $selector, + 'content' => $content, + ] + ) + ); + } + + /** + * Remove block card. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-remove-card.html + * + * @param int $lid Page identifier + * @param int $blockId Block identifier + * @param string $selector Card selector (e.g., '.landing-block-card@0') + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.removecard', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-remove-card.html', + 'Method removes a block card.' + )] + public function removeCard(int $lid, int $blockId, string $selector): UpdateResult + { + return new UpdateResult( + $this->core->call( + 'landing.block.removecard', + [ + 'lid' => $lid, + 'block' => $blockId, + 'selector' => $selector, + ] + ) + ); + } + + /** + * Upload and attach image to block. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-upload-file.html + * + * @param int $blockId Block identifier + * @param mixed $picture Image data (URL string, file element, or array with name and base64 content) + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.uploadfile', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-upload-file.html', + 'Method uploads an image and associates it with the specified block.' + )] + public function uploadFile(int $blockId, mixed $picture): UploadFileResult + { + return new UploadFileResult( + $this->core->call( + 'landing.block.uploadfile', + [ + 'block' => $blockId, + 'picture' => $picture, + ] + ) + ); + } + + /** + * Change anchor symbol code. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-change-anchor.html + * + * @param int $lid Page identifier + * @param int $blockId Block identifier + * @param string $anchor New anchor code + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.changeanchor', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-change-anchor.html', + 'Method changes the symbolic code of the anchor.' + )] + public function changeAnchor(int $lid, int $blockId, string $anchor): UpdateResult + { + return new UpdateResult( + $this->core->call( + 'landing.block.changeanchor', + [ + 'lid' => $lid, + 'block' => $blockId, + 'data' => $anchor, + ] + ) + ); + } + + /** + * Change tag name. + * + * @link https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-change-node-name.html + * + * @param int $lid Page identifier + * @param int $blockId Block identifier + * @param string $selector Node selector + * @param string $tagName New tag name + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'landing.block.changenodename', + 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-change-node-name.html', + 'Method for changing the tag name.' + )] + public function changeNodeName(int $lid, int $blockId, string $selector, string $tagName): UpdateResult + { + return new UpdateResult( + $this->core->call( + 'landing.block.changenodename', + [ + 'lid' => $lid, + 'block' => $blockId, + 'selector' => $selector, + 'tagName' => $tagName, + ] + ) + ); + } +} diff --git a/src/Services/Landing/LandingServiceBuilder.php b/src/Services/Landing/LandingServiceBuilder.php index 1e9ad42c..a31c9c2f 100644 --- a/src/Services/Landing/LandingServiceBuilder.php +++ b/src/Services/Landing/LandingServiceBuilder.php @@ -84,4 +84,19 @@ public function template(): Template\Service\Template return $this->serviceCache[__METHOD__]; } + + /** + * Get Block service + */ + public function block(): Block\Service\Block + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Block\Service\Block( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } } diff --git a/tests/Integration/Services/Landing/Block/Service/BlockTest.php b/tests/Integration/Services/Landing/Block/Service/BlockTest.php new file mode 100644 index 00000000..9b9f6bc3 --- /dev/null +++ b/tests/Integration/Services/Landing/Block/Service/BlockTest.php @@ -0,0 +1,431 @@ + + * + * 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\Landing\Block\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Landing\Block\Result\BlockContentItemResult; +use Bitrix24\SDK\Services\Landing\Block\Result\BlockItemResult; +use Bitrix24\SDK\Services\Landing\Block\Result\BlockManifestItemResult; +use Bitrix24\SDK\Services\Landing\Block\Service\Block; +use Bitrix24\SDK\Services\Landing\Page\Service\Page; +use Bitrix24\SDK\Services\Landing\Site\Service\Site; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; + +/** + * Class BlockTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\Landing\Block\Service + */ +#[CoversMethod(Block::class, 'list')] +#[CoversMethod(Block::class, 'getById')] +#[CoversMethod(Block::class, 'getContent')] +#[CoversMethod(Block::class, 'getManifest')] +#[CoversMethod(Block::class, 'getRepository')] +#[CoversMethod(Block::class, 'getManifestFile')] +#[CoversMethod(Block::class, 'getContentFromRepository')] +#[CoversMethod(Block::class, 'updateNodes')] +#[CoversMethod(Block::class, 'updateAttrs')] +#[CoversMethod(Block::class, 'updateStyles')] +#[CoversMethod(Block::class, 'updateContent')] +#[CoversMethod(Block::class, 'updateCards')] +#[CoversMethod(Block::class, 'cloneCard')] +#[CoversMethod(Block::class, 'addCard')] +#[CoversMethod(Block::class, 'removeCard')] +#[CoversMethod(Block::class, 'uploadFile')] +#[CoversMethod(Block::class, 'changeAnchor')] +#[CoversMethod(Block::class, 'changeNodeName')] +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\Landing\Block\Service\Block::class)] +class BlockTest extends TestCase +{ + use CustomBitrix24Assertions; + + protected Block $blockService; + + protected Page $pageService; + + protected Site $siteService; + + protected array $createdPageIds = []; + + protected array $createdSiteIds = []; + + protected function setUp(): void + { + $serviceBuilder = Fabric::getServiceBuilder(); + $this->blockService = $serviceBuilder->getLandingScope()->block(); + $this->pageService = $serviceBuilder->getLandingScope()->page(); + $this->siteService = $serviceBuilder->getLandingScope()->site(); + } + + protected function tearDown(): void + { + // Clean up created pages + foreach ($this->createdPageIds as $createdPageId) { + try { + $this->pageService->delete($createdPageId); + } catch (\Exception) { + // Ignore if page doesn't exist + } + } + + // Clean up created sites + foreach ($this->createdSiteIds as $createdSiteId) { + try { + $this->siteService->delete($createdSiteId); + } catch (\Exception) { + // Ignore if site doesn't exist + } + } + } + + /** + * Helper method to create a test site + */ + protected function createTestSite(): int + { + $siteFields = [ + 'TITLE' => 'Test Site for Block ' . time(), + 'CODE' => 'testsiteblock' . time(), + 'TYPE' => 'PAGE' + ]; + + $addedItemResult = $this->siteService->add($siteFields); + $siteId = $addedItemResult->getId(); + $this->createdSiteIds[] = $siteId; + + return $siteId; + } + + /** + * Helper method to create a test page with blocks + */ + protected function createTestPageWithBlocks(): int + { + $siteId = $this->createTestSite(); + + // Get available page templates + $core = Fabric::getCore(); + $templatesResponse = $core->call('landing.demos.getPageList', ['type' => 'page']); + $templates = $templatesResponse->getResponseData()->getResult(); + + // Use the first available template to get a page with blocks + $templateCode = key($templates); + + $addedItemResult = $this->pageService->addByTemplate( + $siteId, + $templateCode, + [ + 'TITLE' => 'Test Page with Blocks ' . time(), + 'DESCRIPTION' => 'Test page for block operations' + ] + ); + + $pageId = $addedItemResult->getId(); + $this->createdPageIds[] = $pageId; + + return $pageId; + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testList(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Test getting blocks list for the page + $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); + $blocks = $blocksResult->getBlocks(); + + self::assertIsArray($blocks); + + if ($blocks !== []) { + $firstBlock = $blocks[0]; + self::assertInstanceOf(BlockItemResult::class, $firstBlock); + self::assertGreaterThan(0, $firstBlock->id); + self::assertEquals($pageId, $firstBlock->lid); + } + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetById(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Get blocks list first to get a block ID + $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); + $blocks = $blocksResult->getBlocks(); + + self::assertNotEmpty($blocks, 'Page must have blocks for this test'); + + $blockId = $blocks[0]->id; + + // Test getting block by ID + $blockResult = $this->blockService->getById($blockId, ['edit_mode' => 1]); + $blockItemResult = $blockResult->getBlock(); + + self::assertInstanceOf(BlockItemResult::class, $blockItemResult); + self::assertEquals($blockId, $blockItemResult->id); + self::assertEquals($pageId, $blockItemResult->lid); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetContent(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Get blocks list first to get a block ID + $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); + $blocks = $blocksResult->getBlocks(); + + self::assertNotEmpty($blocks, 'Page must have blocks for this test'); + + $blockId = $blocks[0]->id; + + // Test getting block content + $blockContentResult = $this->blockService->getContent($pageId, $blockId, 1, ['wrapper_show' => 1]); + $blockContentItemResult = $blockContentResult->getContent(); + + // Check that a typed object is returned + self::assertInstanceOf(BlockContentItemResult::class, $blockContentItemResult); + + // Check required fields + self::assertIsInt($blockContentItemResult->id); + self::assertIsString($blockContentItemResult->sections); + self::assertIsBool($blockContentItemResult->active); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetManifest(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Get blocks list first to get a block ID + $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); + $blocks = $blocksResult->getBlocks(); + + self::assertNotEmpty($blocks, 'Page must have blocks for this test'); + + $blockId = $blocks[0]->id; + + // Test getting block manifest + $blockManifestResult = $this->blockService->getManifest($pageId, $blockId, ['edit_mode' => 1]); + $blockManifestItemResult = $blockManifestResult->getManifest(); + + // Check that a typed object is returned + self::assertInstanceOf(BlockManifestItemResult::class, $blockManifestItemResult); + + // Check required fields + self::assertIsArray($blockManifestItemResult->block); + self::assertIsArray($blockManifestItemResult->cards); + self::assertIsArray($blockManifestItemResult->nodes); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetRepository(): void + { + // Test getting blocks from repository + $repositoryResult = $this->blockService->getRepository('about'); + $repositoryItemResult = $repositoryResult->getRepository(); + + self::assertInstanceOf(\Bitrix24\SDK\Services\Landing\Block\Result\RepositoryItemResult::class, $repositoryItemResult); + self::assertNotEmpty($repositoryItemResult->name, 'Repository name must not be empty'); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetManifestFile(): void + { + // Get repository blocks + $repositoryResult = $this->blockService->getRepository('about'); + $repositoryItemResult = $repositoryResult->getRepository(); + + self::assertInstanceOf(\Bitrix24\SDK\Services\Landing\Block\Result\RepositoryItemResult::class, $repositoryItemResult); + + // Get block code from first item in the repository + self::assertNotEmpty($repositoryItemResult->items, 'Repository must have items'); + $blockCode = key($repositoryItemResult->items); + if ($blockCode === null) { + $blockCode = 'bitrix:landing.blocks.html_text'; + } + + // Test getting manifest from repository + $blockManifestResult = $this->blockService->getManifestFile($blockCode); + $blockManifestItemResult = $blockManifestResult->getManifest(); + + self::assertInstanceOf(\Bitrix24\SDK\Services\Landing\Block\Result\BlockManifestItemResult::class, $blockManifestItemResult); + self::assertNotEmpty($blockManifestItemResult->block, 'Manifest block must not be empty'); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetContentFromRepository(): void + { + // Get repository blocks first + $repositoryResult = $this->blockService->getRepository('about'); + $repositoryItemResult = $repositoryResult->getRepository(); + + self::assertInstanceOf(\Bitrix24\SDK\Services\Landing\Block\Result\RepositoryItemResult::class, $repositoryItemResult); + + // Get block code from first item in the repository + self::assertNotEmpty($repositoryItemResult->items, 'Repository must have items'); + $blockCode = key($repositoryItemResult->items); + if ($blockCode === null) { + $blockCode = 'bitrix:landing.blocks.html_text'; + } + + // Test getting content from repository + $repositoryContentResult = $this->blockService->getContentFromRepository($blockCode); + $content = $repositoryContentResult->getContent(); + + self::assertIsString($content); + self::assertNotEmpty($content, 'Content must not be empty'); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testUpdateNodes(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Get blocks list first to get a block ID + $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); + $blocks = $blocksResult->getBlocks(); + + self::assertNotEmpty($blocks, 'Page must have blocks for this test'); + + $blockId = $blocks[0]->id; + + // Test updating block nodes + $updateData = [ + '.landing-block-node-text' => 'Updated text content ' . time() + ]; + + $updateResult = $this->blockService->updateNodes($pageId, $blockId, $updateData); + $isSuccess = $updateResult->isSuccess(); + + self::assertTrue($isSuccess); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testUpdateStyles(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Get blocks list first to get a block ID + $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); + $blocks = $blocksResult->getBlocks(); + + self::assertNotEmpty($blocks, 'Page must have blocks for this test'); + + $blockId = $blocks[0]->id; + + // Test updating block styles + $styleData = [ + '.landing-block-node-text' => [ + 'classList' => ['landing-block-node-text', 'g-color-primary'], + 'affect' => ['color'] + ] + ]; + + $updateResult = $this->blockService->updateStyles($pageId, $blockId, $styleData); + $isSuccess = $updateResult->isSuccess(); + + self::assertTrue($isSuccess); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testUploadFile(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Get blocks list first to get a block ID + $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); + $blocks = $blocksResult->getBlocks(); + + self::assertNotEmpty($blocks, 'Page must have blocks for this test'); + + $blockId = $blocks[0]->id; + + // Test uploading a file (using a simple base64 encoded 1x1 pixel image) + $imageData = [ + 'test.png', + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChAI9jgvKNQAAAABJRU5ErkJggg==' + ]; + + $uploadFileResult = $this->blockService->uploadFile($blockId, $imageData); + + // Check new typed methods + self::assertIsInt($uploadFileResult->getId()); + self::assertIsString($uploadFileResult->getUrl()); + self::assertNotEmpty($uploadFileResult->getUrl()); + + // Check deprecated methods for backward compatibility + self::assertEquals($uploadFileResult->getId(), $uploadFileResult->getFileId()); + self::assertEquals($uploadFileResult->getUrl(), $uploadFileResult->getFilePath()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testChangeAnchor(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Get blocks list first to get a block ID + $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); + $blocks = $blocksResult->getBlocks(); + + self::assertNotEmpty($blocks, 'Page must have blocks for this test'); + + $blockId = $blocks[0]->id; + + // Test changing anchor + $newAnchor = 'test-anchor-' . time(); + $updateResult = $this->blockService->changeAnchor($pageId, $blockId, $newAnchor); + $isSuccess = $updateResult->isSuccess(); + + self::assertTrue($isSuccess); + } +} From 503eeeaea65eb72937914a9854fb3bc15ec12dbd Mon Sep 17 00:00:00 2001 From: Sally Fancen Date: Fri, 3 Oct 2025 16:31:17 +0400 Subject: [PATCH 14/14] add skipped methods; run tests and linters --- .../Result/RepositoryBlockItemResult.php | 30 -- .../Result/RepositoryBlockItemsResult.php | 38 -- .../Block/Result/RepositoryBlocksResult.php | 40 -- src/Services/Landing/Block/Service/Block.php | 8 +- .../Landing/Block/Service/BlockTest.php | 393 +++++++++++++++++- 5 files changed, 380 insertions(+), 129 deletions(-) delete mode 100644 src/Services/Landing/Block/Result/RepositoryBlockItemResult.php delete mode 100644 src/Services/Landing/Block/Result/RepositoryBlockItemsResult.php delete mode 100644 src/Services/Landing/Block/Result/RepositoryBlocksResult.php diff --git a/src/Services/Landing/Block/Result/RepositoryBlockItemResult.php b/src/Services/Landing/Block/Result/RepositoryBlockItemResult.php deleted file mode 100644 index aee946ce..00000000 --- a/src/Services/Landing/Block/Result/RepositoryBlockItemResult.php +++ /dev/null @@ -1,30 +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\Services\Landing\Block\Result; - -use Bitrix24\SDK\Core\Result\AbstractItem; - -/** - * @property-read string $name - * @property-read array $meta - * @property-read string $new - * @property-read array $type - * @property-read string $specialType - * @property-read string $separator - * @property-read string $app_code - * @property-read array $items - */ -class RepositoryBlockItemResult extends AbstractItem -{ -} diff --git a/src/Services/Landing/Block/Result/RepositoryBlockItemsResult.php b/src/Services/Landing/Block/Result/RepositoryBlockItemsResult.php deleted file mode 100644 index 2c6a2ad9..00000000 --- a/src/Services/Landing/Block/Result/RepositoryBlockItemsResult.php +++ /dev/null @@ -1,38 +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\Services\Landing\Block\Result; - -use Bitrix24\SDK\Core\Result\AbstractItem; - -/** - * @property-read string $code - * @property-read string $id - * @property-read string $name - * @property-read string $namespace - * @property-read string $new - * @property-read string $version - * @property-read array $type - * @property-read array $section - * @property-read string $system - * @property-read string $description - * @property-read string $preview - * @property-read string $restricted - * @property-read string $repo_id - * @property-read string $app_code - * @property-read string $only_for_license - * @property-read string $requires_updates - */ -class RepositoryBlockItemsResult extends AbstractItem -{ -} diff --git a/src/Services/Landing/Block/Result/RepositoryBlocksResult.php b/src/Services/Landing/Block/Result/RepositoryBlocksResult.php deleted file mode 100644 index 8ae31f06..00000000 --- a/src/Services/Landing/Block/Result/RepositoryBlocksResult.php +++ /dev/null @@ -1,40 +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\Services\Landing\Block\Result; - -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Result\AbstractResult; - -class RepositoryBlocksResult extends AbstractResult -{ - /** - * @return RepositoryBlockItemResult[] - * @throws BaseException - */ - public function getRepositoryBlocks(): array - { - echo "\n getRepositoryBlocks \n"; - print_r($this->getCoreResponse()->getResponseData()->getResult()); - echo "\n"; - - $result = []; - $rawData = $this->getCoreResponse()->getResponseData()->getResult(); - - foreach ($rawData as $sectionData) { - $result[] = new RepositoryBlockItemResult($sectionData); - } - - return $result; - } -} diff --git a/src/Services/Landing/Block/Service/Block.php b/src/Services/Landing/Block/Service/Block.php index 717a6259..5472206e 100644 --- a/src/Services/Landing/Block/Service/Block.php +++ b/src/Services/Landing/Block/Service/Block.php @@ -558,8 +558,7 @@ public function changeAnchor(int $lid, int $blockId, string $anchor): UpdateResu * * @param int $lid Page identifier * @param int $blockId Block identifier - * @param string $selector Node selector - * @param string $tagName New tag name + * @param array $data Array of selectors and new tag names. Example: ['.landing-block-node-text@0' => 'h2'] * * @throws BaseException * @throws TransportException @@ -569,7 +568,7 @@ public function changeAnchor(int $lid, int $blockId, string $anchor): UpdateResu 'https://apidocs.bitrix24.com/api-reference/landing/block/methods/landing-block-change-node-name.html', 'Method for changing the tag name.' )] - public function changeNodeName(int $lid, int $blockId, string $selector, string $tagName): UpdateResult + public function changeNodeName(int $lid, int $blockId, array $data): UpdateResult { return new UpdateResult( $this->core->call( @@ -577,8 +576,7 @@ public function changeNodeName(int $lid, int $blockId, string $selector, string [ 'lid' => $lid, 'block' => $blockId, - 'selector' => $selector, - 'tagName' => $tagName, + 'data' => $data, ] ) ); diff --git a/tests/Integration/Services/Landing/Block/Service/BlockTest.php b/tests/Integration/Services/Landing/Block/Service/BlockTest.php index 9b9f6bc3..52ee4557 100644 --- a/tests/Integration/Services/Landing/Block/Service/BlockTest.php +++ b/tests/Integration/Services/Landing/Block/Service/BlockTest.php @@ -141,6 +141,147 @@ protected function createTestPageWithBlocks(): int return $pageId; } + /** + * Helper method to add a text block to page if no suitable blocks exist + */ + protected function ensurePageHasTextBlock(int $pageId): array + { + // First try to find existing block with nodes + $blockWithNodes = $this->findBlockWithNodes($pageId); + if ($blockWithNodes !== null) { + return $blockWithNodes; + } + + // If no suitable block found, use any first block and fallback to standard selectors + $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); + $blocks = $blocksResult->getBlocks(); + + if ($blocks !== []) { + return [ + 'blockId' => $blocks[0]->id, + 'nodeSelectors' => ['.landing-block-node-text'], + 'manifest' => null + ]; + } + + // This should never happen with template pages, but just in case + throw new \RuntimeException('No blocks found on page and unable to add new blocks'); + } + + /** + * Helper method to add a card block to page if no suitable blocks exist + */ + protected function ensurePageHasCardBlock(int $pageId): array + { + // First try to find existing block with cards + $blockWithCards = $this->findBlockWithCards($pageId); + if ($blockWithCards !== null) { + return $blockWithCards; + } + + // If no suitable block found, use any first block and fallback to standard selectors + $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); + $blocks = $blocksResult->getBlocks(); + + if ($blocks !== []) { + return [ + 'blockId' => $blocks[0]->id, + 'cardSelector' => '.landing-block-card', + 'manifest' => null + ]; + } + + // This should never happen with template pages, but just in case + throw new \RuntimeException('No blocks found on page and unable to add new blocks'); + } + + /** + * Helper method to find a block with cards from its manifest + */ + protected function findBlockWithCards(int $pageId): ?array + { + // Get blocks list for the page + $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); + $blocks = $blocksResult->getBlocks(); + + foreach ($blocks as $block) { + try { + // Get manifest for this block + $manifestResult = $this->blockService->getManifest($pageId, $block->id, ['edit_mode' => 1]); + $manifest = $manifestResult->getManifest(); + + // Check if block has cards in manifest + if (!empty($manifest->cards) && is_array($manifest->cards)) { + // Return first card selector found + $cardSelector = key($manifest->cards); + if ($cardSelector !== 0 && ($cardSelector !== '' && $cardSelector !== '0')) { + return [ + 'blockId' => $block->id, + 'cardSelector' => $cardSelector, + 'manifest' => $manifest + ]; + } + } + } catch (\Exception) { + // Skip blocks that can't provide manifest or don't have cards + continue; + } + } + + return null; + } + + /** + * Helper method to find a block with specific node selectors + */ + protected function findBlockWithNodes(int $pageId, array $requiredNodeTypes = []): ?array + { + // Get blocks list for the page + $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); + $blocks = $blocksResult->getBlocks(); + + foreach ($blocks as $block) { + try { + // Get manifest for this block + $manifestResult = $this->blockService->getManifest($pageId, $block->id, ['edit_mode' => 1]); + $manifest = $manifestResult->getManifest(); + + // Check if block has nodes in manifest + if (!empty($manifest->nodes) && is_array($manifest->nodes)) { + $nodeSelectors = array_keys($manifest->nodes); + + // If specific node types required, check for them + if ($requiredNodeTypes !== []) { + $hasRequiredNodes = false; + foreach ($nodeSelectors as $nodeSelector) { + foreach ($requiredNodeTypes as $requiredNodeType) { + if (str_contains($nodeSelector, (string) $requiredNodeType)) { + $hasRequiredNodes = true; + break 2; + } + } + } + + if (!$hasRequiredNodes) { + continue; + } + } + + return [ + 'blockId' => $block->id, + 'nodeSelectors' => $nodeSelectors, + 'manifest' => $manifest + ]; + } + } catch (\Exception) { + // Skip blocks that can't provide manifest + continue; + } + } + + return null; + } + /** * @throws BaseException * @throws TransportException @@ -322,17 +463,18 @@ public function testUpdateNodes(): void { $pageId = $this->createTestPageWithBlocks(); - // Get blocks list first to get a block ID - $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); - $blocks = $blocksResult->getBlocks(); - - self::assertNotEmpty($blocks, 'Page must have blocks for this test'); + // Ensure page has a block with text nodes (find existing or create new) + $blockWithNodes = $this->ensurePageHasTextBlock($pageId); + + $blockId = $blockWithNodes['blockId']; + $nodeSelectors = $blockWithNodes['nodeSelectors']; - $blockId = $blocks[0]->id; + // Use first available node selector + $firstNodeSelector = $nodeSelectors[0]; - // Test updating block nodes + // Test updating block nodes with real selector $updateData = [ - '.landing-block-node-text' => 'Updated text content ' . time() + $firstNodeSelector => 'Updated text content ' . time() ]; $updateResult = $this->blockService->updateNodes($pageId, $blockId, $updateData); @@ -349,17 +491,18 @@ public function testUpdateStyles(): void { $pageId = $this->createTestPageWithBlocks(); - // Get blocks list first to get a block ID - $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); - $blocks = $blocksResult->getBlocks(); + // Ensure page has a block with text nodes (find existing or create new) + $blockWithNodes = $this->ensurePageHasTextBlock($pageId); + + $blockId = $blockWithNodes['blockId']; + $nodeSelectors = $blockWithNodes['nodeSelectors']; - self::assertNotEmpty($blocks, 'Page must have blocks for this test'); + // Use first available node selector + $firstNodeSelector = $nodeSelectors[0]; - $blockId = $blocks[0]->id; - - // Test updating block styles + // Test updating block styles with real selector $styleData = [ - '.landing-block-node-text' => [ + $firstNodeSelector => [ 'classList' => ['landing-block-node-text', 'g-color-primary'], 'affect' => ['color'] ] @@ -428,4 +571,222 @@ public function testChangeAnchor(): void self::assertTrue($isSuccess); } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testUpdateAttrs(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Ensure page has a block with text nodes (find existing or create new) + $blockWithNodes = $this->ensurePageHasTextBlock($pageId); + + $blockId = $blockWithNodes['blockId']; + $nodeSelectors = $blockWithNodes['nodeSelectors']; + + // Use first available node selector + $firstNodeSelector = $nodeSelectors[0]; + + // Test updating block attributes with real selector + $attrsData = [ + $firstNodeSelector => [ + 'href' => 'https://example.com', + 'target' => '_blank' + ] + ]; + + $updateResult = $this->blockService->updateAttrs($pageId, $blockId, $attrsData); + $isSuccess = $updateResult->isSuccess(); + + self::assertTrue($isSuccess); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testUpdateContent(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Get blocks list first to get a block ID + $blocksResult = $this->blockService->list($pageId, ['edit_mode' => 1]); + $blocks = $blocksResult->getBlocks(); + + self::assertNotEmpty($blocks, 'Page must have blocks for this test'); + + $blockId = $blocks[0]->id; + + // Test updating block content with arbitrary content + $newContent = '
Updated content ' . time() . '
'; + + $updateResult = $this->blockService->updateContent($pageId, $blockId, $newContent); + $isSuccess = $updateResult->isSuccess(); + + self::assertTrue($isSuccess); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testUpdateCards(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Try to find a block with cards, fallback to text block + $blockWithCards = $this->findBlockWithCards($pageId); + + if ($blockWithCards !== null) { + $blockId = $blockWithCards['blockId']; + $cardSelector = $blockWithCards['cardSelector']; + } else { + // Fallback: use text block and try card operations + $blockWithNodes = $this->ensurePageHasTextBlock($pageId); + $blockId = $blockWithNodes['blockId']; + $cardSelector = '.landing-block-card'; + } + + // Get a node selector + $blockWithNodes = $this->ensurePageHasTextBlock($pageId); + $nodeSelector = $blockWithNodes['nodeSelectors'][0]; + + // Test bulk updating block cards with selectors + $cardsData = [ + $cardSelector . '@0' => [ + $nodeSelector => 'Updated card text ' . time() + ] + ]; + + // This may fail if block doesn't support cards, but that's ok for testing + $updateResult = $this->blockService->updateCards($pageId, $blockId, $cardsData); + $isSuccess = $updateResult->isSuccess(); + self::assertTrue($isSuccess); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testCloneCard(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Try to find a block with cards, fallback to any block + $blockWithCards = $this->findBlockWithCards($pageId); + + if ($blockWithCards !== null) { + $blockId = $blockWithCards['blockId']; + $cardSelector = $blockWithCards['cardSelector']; + } else { + // Fallback: use any block and try card operations + $blockWithNodes = $this->ensurePageHasTextBlock($pageId); + $blockId = $blockWithNodes['blockId']; + $cardSelector = '.landing-block-card'; + } + + // Test cloning a block card - this may fail if block doesn't support cards + $updateResult = $this->blockService->cloneCard($pageId, $blockId, $cardSelector); + $isSuccess = $updateResult->isSuccess(); + self::assertTrue($isSuccess); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testAddCard(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Try to find a block with cards, fallback to any block + $blockWithCards = $this->findBlockWithCards($pageId); + + if ($blockWithCards !== null) { + $blockId = $blockWithCards['blockId']; + $cardSelector = $blockWithCards['cardSelector']; + } else { + // Fallback: use any block and try card operations + $blockWithNodes = $this->ensurePageHasTextBlock($pageId); + $blockId = $blockWithNodes['blockId']; + $cardSelector = '.landing-block-card'; + } + + // Test adding a card with modified content + $content = '
New card content ' . time() . '
'; + + // This may fail if block doesn't support cards, but that's ok for testing + $updateResult = $this->blockService->addCard($pageId, $blockId, $cardSelector, $content); + $isSuccess = $updateResult->isSuccess(); + self::assertTrue($isSuccess); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testRemoveCard(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Try to find a block with cards, fallback to any block + $blockWithCards = $this->findBlockWithCards($pageId); + + if ($blockWithCards !== null) { + $blockId = $blockWithCards['blockId']; + $cardSelector = $blockWithCards['cardSelector']; + + // First clone a card to have something to remove + $this->blockService->cloneCard($pageId, $blockId, $cardSelector); + + // Test removing a block card - target the cloned card (should be index 1) + $removeSelector = $cardSelector . '@1'; + $updateResult = $this->blockService->removeCard($pageId, $blockId, $removeSelector); + $isSuccess = $updateResult->isSuccess(); + self::assertTrue($isSuccess); + + return; + } + + // Fallback: use any block and try card operations + $blockWithNodes = $this->ensurePageHasTextBlock($pageId); + $blockId = $blockWithNodes['blockId']; + $cardSelector = '.landing-block-card'; + + // Test removing a card - this may fail if block doesn't support cards + $removeSelector = $cardSelector . '@0'; + $updateResult = $this->blockService->removeCard($pageId, $blockId, $removeSelector); + $isSuccess = $updateResult->isSuccess(); + self::assertTrue($isSuccess); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testChangeNodeName(): void + { + $pageId = $this->createTestPageWithBlocks(); + + // Ensure page has a block with text nodes (find existing or create new) + $blockWithNodes = $this->ensurePageHasTextBlock($pageId); + + $blockId = $blockWithNodes['blockId']; + $nodeSelectors = $blockWithNodes['nodeSelectors']; + + // Use first available node selector + $firstNodeSelector = $nodeSelectors[0]; + + // Test changing tag name using data array format with real selector + $data = [ + $firstNodeSelector => 'h2' + ]; + + $updateResult = $this->blockService->changeNodeName($pageId, $blockId, $data); + $isSuccess = $updateResult->isSuccess(); + + self::assertTrue($isSuccess); + } }