├── php-fmt.sh
├── .gitignore
├── phpstan.neon
├── test
├── bootstrap.php
├── assets
│ └── CDFAttributeChild.php
├── AssetTest.php
├── SettingsTestHmacV1.php
├── SettingsTestHmacV2.php
├── ContentHubTestHmacV1.php
├── ContentHubTestHmacV2.php
├── EventSubscriber
│ ├── DefaultCDFTest.php
│ └── ClientCDFTest.php
├── Event
│ └── GetCDFTypeEventTest.php
├── SettingsTest.php
├── CDF
│ ├── ClientCDFObjectTest.php
│ └── CDFObjectTest.php
├── WebhookTest.php
├── SettingsTestBase.php
├── SearchCriteria
│ └── SearchCriteriaBuilderTest.php
├── CDFAttributeTest.php
├── ContentHubTestBase.php
└── CDFDocumentTest.php
├── src
├── StatusCodes.php
├── ContentHubLibraryEvents.php
├── EventSubscriber
│ ├── DefaultCDF.php
│ └── ClientCDF.php
├── Asset.php
├── Guzzle
│ └── Middleware
│ │ ├── RequestResponseHandler.php
│ │ └── RequestResponseLogger.php
├── Event
│ └── GetCDFTypeEvent.php
├── CDF
│ ├── ClientCDFObject.php
│ ├── CDFObjectInterface.php
│ └── CDFObject.php
├── SearchCriteria
│ ├── SearchCriteriaBuilder.php
│ └── SearchCriteria.php
├── CDFAttribute.php
├── Webhook.php
├── CDFDocument.php
├── Settings.php
├── ObjectFactory.php
├── ContentHubClientCommonTrait.php
├── ContentHubClientTrait.php
└── ContentHubClient.php
├── infection.json.dist
├── .github
└── workflows
│ └── content-hub-php-actions.yml
├── phpmd.xml
├── phpunit.xml
├── composer.json
├── Makefile
└── README.md
/php-fmt.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | ./vendor/bin/php-cs-fixer fix ./src --level=psr2
4 |
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bootstrap.php
2 | build
3 | vendor
4 | composer.lock
5 | infection
6 | .DS_Store
7 | nbproject
8 | .idea
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 1
3 | paths:
4 | - ./src
5 | ignoreErrors:
6 | - '#Unsafe usage of new static\(\).#'
7 | excludePaths:
8 | - test/
9 |
--------------------------------------------------------------------------------
/test/bootstrap.php:
--------------------------------------------------------------------------------
1 | setUrl($url);
23 | $asset->setReplaceToken($replaceToken);
24 | $this->assertEquals($url, $asset->getUrl());
25 | $this->assertEquals($replaceToken, $asset->getReplaceToken());
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/infection.json.dist:
--------------------------------------------------------------------------------
1 | {
2 | "source": {
3 | "directories": [
4 | "src"
5 | ]
6 | },
7 | "timeout": 10,
8 | "logs": {
9 | "text": "infection/logs/infection.log",
10 | "summary": "infection/logs/summary.log",
11 | "debug": "infection/logs/debug.log",
12 | "perMutator": "infection/logs/per-mutator.md"
13 | },
14 | "tmpDir": "infection/tmp",
15 | "phpUnit": {
16 | "configDir": ".",
17 | "customPath": "vendor/phpunit/phpunit/phpunit"
18 | },
19 | "mutators": {
20 | "@default": true,
21 | "@function_signature": false,
22 | "TrueValue": {
23 | "ignore": [
24 | "NameSpace\\*\\Class::method"
25 | ]
26 | }
27 | },
28 | "initialTestsPhpOptions": "-d zend_extension=xdebug.so",
29 | "testFrameworkOptions": "-vvv"
30 | }
--------------------------------------------------------------------------------
/test/SettingsTestHmacV1.php:
--------------------------------------------------------------------------------
1 | $stack]);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/test/SettingsTestHmacV2.php:
--------------------------------------------------------------------------------
1 | $stack]);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/test/ContentHubTestHmacV1.php:
--------------------------------------------------------------------------------
1 | $stack]);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/ContentHubLibraryEvents.php:
--------------------------------------------------------------------------------
1 | $stack]);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/.github/workflows/content-hub-php-actions.yml:
--------------------------------------------------------------------------------
1 | name: Content Hub PHP
2 | on: [push, pull_request]
3 | jobs:
4 | build:
5 | runs-on: ${{ matrix.os }}
6 | strategy:
7 | matrix:
8 | os: [ ubuntu-latest ]
9 | php-version: [ '7.4', '8.1', '8.2' ]
10 | steps:
11 | # This step checks out a copy of your repository.
12 | - name: Checkout
13 | uses: actions/checkout@v2
14 |
15 | - name: Setup PHP
16 | uses: shivammathur/setup-php@v2
17 | with:
18 | php-version: ${{ matrix.php-version }}
19 | coverage: xdebug
20 |
21 | - name: Install composer dependencies
22 | run: composer install
23 |
24 | - name: Run phpcs
25 | run: |
26 | ./vendor/bin/phpcs --config-set installed_paths vendor/drupal/coder/coder_sniffer
27 | ./vendor/bin/phpcs -n --standard=Drupal,DrupalPractice src/ test/
28 |
29 | - name: Run PHPUnit
30 | run: ./vendor/bin/phpunit test/
31 |
32 | - name: Run phpstan
33 | run: ./vendor/bin/phpstan analyse -c ./phpstan.neon
34 |
--------------------------------------------------------------------------------
/src/EventSubscriber/DefaultCDF.php:
--------------------------------------------------------------------------------
1 | setObject(CDFObject::fromArray($event->getData()));
35 | $event->stopPropagation();
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/phpmd.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | PHP Project Starter Rulset: Adopted From Jenkins for Symfony 2
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 | test
15 |
16 |
17 |
18 |
19 |
20 | src
21 |
22 | src/ObjectFactory.php
23 | src/ContentHubLibraryEvents.php
24 | src/Guzzle
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/Asset.php:
--------------------------------------------------------------------------------
1 | getValue('url', '');
40 | }
41 |
42 | /**
43 | * Getter for 'replace-token'.
44 | *
45 | * @return string
46 | * 'replace-token' value.
47 | */
48 | public function getReplaceToken(): string {
49 | return $this->getValue('replace-token', '');
50 | }
51 |
52 | /**
53 | * Properties getter.
54 | *
55 | * @param string $key
56 | * Property name.
57 | * @param string $default
58 | * Default value.
59 | *
60 | * @return mixed
61 | * Property value.
62 | */
63 | protected function getValue($key, $default) {
64 | return $this[$key] ?? $default;
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/EventSubscriber/ClientCDF.php:
--------------------------------------------------------------------------------
1 | getType() === 'client') {
36 | $data = $event->getData();
37 | /* @deprecated Backwards Compatibility, Remove by 2.0 */
38 | if (!isset($data['metadata']['settings'])) {
39 | $data['metadata'] = [
40 | 'settings' => $data['metadata'],
41 | ];
42 | }
43 | /* End deprecated code */
44 | $object = ClientCDFObject::fromArray($data);
45 | $event->setObject($object);
46 | $event->stopPropagation();
47 | }
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/Guzzle/Middleware/RequestResponseHandler.php:
--------------------------------------------------------------------------------
1 | logger = $logger;
29 | }
30 |
31 | /**
32 | * Logs any response/request.
33 | *
34 | * @param callable $handler
35 | * Request handler.
36 | *
37 | * @return \Closure
38 | * Request handler.
39 | */
40 | public function __invoke(callable $handler): \Closure {
41 | return function (RequestInterface $request, array $options) use ($handler) {
42 | $promise = function (ResponseInterface $response) use ($request) {
43 | try {
44 | (new RequestResponseLogger($request, $response,
45 | $this->logger))->log();
46 | }
47 | catch (\Exception $exception) {
48 | $message = sprintf('Failed to make log entry. Reason: %s',
49 | $exception->getMessage());
50 | $this->logger->critical($message);
51 | }
52 |
53 | return $response;
54 | };
55 |
56 | return $handler($request, $options)->then($promise);
57 | };
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "acquia/content-hub-php",
3 | "type": "library",
4 | "description": "A PHP Client library to consume the Acquia Content Hub API.",
5 | "homepage": "https://github.com/acquia/content-hub-php",
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "See Contributors",
10 | "homepage": "https://github.com/acquia/content-hub-php/graphs/contributors"
11 | }
12 | ],
13 | "support": {
14 | "issues": "https://github.com/acquia/content-hub-php/issues"
15 | },
16 | "require": {
17 | "acquia/http-hmac-php": ">=3.4",
18 | "ext-json": "*",
19 | "php": ">=7.3",
20 | "psr/log": ">=1.0",
21 | "guzzlehttp/guzzle": ">=6.5",
22 | "symfony/event-dispatcher": ">=4.4",
23 | "symfony/http-foundation": ">=4.4",
24 | "symfony/serializer": ">=4.4"
25 | },
26 | "require-dev": {
27 | "drupal/coder": "dev-8.x-3.x",
28 | "mockery/mockery": "^1.2",
29 | "pdepend/pdepend": "~1.0",
30 | "phploc/phploc": "~2.0",
31 | "phpmd/phpmd": "~1.0",
32 | "phpunit/phpunit": "^9",
33 | "scrutinizer/ocular": "~1.0",
34 | "sebastian/phpcpd": "~2.0",
35 | "squizlabs/php_codesniffer": "^3.5",
36 | "phpstan/phpstan": "^1.8",
37 | "phpspec/prophecy-phpunit": "^2"
38 | },
39 | "suggest": {
40 | "ramsey/uuid": "A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID)"
41 | },
42 | "autoload": {
43 | "psr-4": {
44 | "Acquia\\ContentHubClient\\": "src/"
45 | }
46 | },
47 | "autoload-dev": {
48 | "psr-4": {
49 | "Acquia\\ContentHubClient\\": "test/"
50 | }
51 | },
52 | "extra": {
53 | "branch-alias": {
54 | "dev-2.x": "2.x-dev"
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Event/GetCDFTypeEvent.php:
--------------------------------------------------------------------------------
1 | data = $data;
44 |
45 | if (!isset($data['type'])) {
46 | throw new \InvalidArgumentException('Parameters should have a \'type\' key');
47 | }
48 | $this->type = $data['type'];
49 | }
50 |
51 | /**
52 | * Returns CDF object.
53 | *
54 | * @return \Acquia\ContentHubClient\CDF\CDFObjectInterface
55 | * CDF object.
56 | */
57 | public function getObject() {
58 | return $this->cdfObject;
59 | }
60 |
61 | /**
62 | * CDF object setter.
63 | *
64 | * @param \Acquia\ContentHubClient\CDF\CDFObjectInterface $object
65 | * CDF object.
66 | */
67 | public function setObject(CDFObjectInterface $object) {
68 | $this->cdfObject = $object;
69 | }
70 |
71 | /**
72 | * Returns event data.
73 | *
74 | * @return array
75 | * CDF representation from plexus.
76 | */
77 | public function getData() {
78 | return $this->data;
79 | }
80 |
81 | /**
82 | * Returns CDF Type.
83 | *
84 | * @return string
85 | * CDF Type.
86 | */
87 | public function getType() {
88 | return $this->type;
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/test/EventSubscriber/DefaultCDFTest.php:
--------------------------------------------------------------------------------
1 | defaultCdf = new DefaultCDF();
41 | $this->handler = current(current($this->defaultCdf::getSubscribedEvents()[ContentHubLibraryEvents::GET_CDF_CLASS]));
42 | }
43 |
44 | /**
45 | * {@inheritdoc}
46 | */
47 | public function tearDown(): void {
48 | parent::tearDown();
49 |
50 | unset($this->clientCdf, $this->handler);
51 | }
52 |
53 | /**
54 | * {@inheritdoc}
55 | */
56 | public function testGetSubscribedEventsAddsHandlerToEvent() {
57 | $this->assertNotNull($this->handler);
58 | }
59 |
60 | /**
61 | * {@inheritdoc}
62 | */
63 | public function testHandler() {
64 | $cdfObjectInterfaceMock = \Mockery::mock(CDFObjectInterface::class);
65 | $cdfObjectMock = \Mockery::mock('overload:' . CDFObject::class);
66 |
67 | $cdfObjectMock->shouldReceive('fromArray')
68 | ->once()
69 | ->andReturn($cdfObjectInterfaceMock);
70 |
71 | $getCDFTypeEventMock = $this->getMockBuilder(GetCDFTypeEvent::class)
72 | ->disableOriginalConstructor()
73 | ->onlyMethods(['setObject', 'stopPropagation', 'getData'])
74 | ->getMock();
75 |
76 | $getCDFTypeEventMock->expects($this->once())
77 | ->method('getData');
78 |
79 | $getCDFTypeEventMock->expects($this->once())
80 | ->method('setObject');
81 |
82 | $getCDFTypeEventMock->expects($this->once())
83 | ->method('stopPropagation');
84 |
85 | $this->defaultCdf->{$this->handler}($getCDFTypeEventMock);
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | ########################################################
2 | # Constants
3 | ########################################################
4 | # Console Colors
5 | GREEN := $(shell tput -Txterm setaf 2)
6 | YELLOW := $(shell tput -Txterm setaf 3)
7 | WHITE := $(shell tput -Txterm setaf 7)
8 | RESET := $(shell tput -Txterm sgr0)
9 | TARGET_MAX_CHAR_NUM=20
10 |
11 | # PHPUnit and Infection
12 | INFECTION_DATA_DIR := infection
13 | DEPENDENCY_DIR := ./vendor
14 | VENDOR_BIN_PATH := $(DEPENDENCY_DIR)/bin
15 | PHPUNIT_EXEC := $(VENDOR_BIN_PATH)/phpunit
16 | INFECTION_EXEC := $(VENDOR_BIN_PATH)/infection
17 | COMPOSER_INSTALL := composer install
18 | ########################################################
19 | # Automatic Help Generator
20 | ########################################################
21 | help:
22 | @echo ''
23 | @echo 'Usage:'
24 | @echo ' ${YELLOW}make${RESET} ${GREEN}${RESET}'
25 | @echo ''
26 | @echo 'Targets:'
27 | @awk '/^[a-zA-Z\-\_0-9]+:/ { \
28 | helpMessage = match(lastLine, /^## (.*)/); \
29 | if (helpMessage) { \
30 | helpCommand = substr($$1, 0, index($$1, ":")-1); \
31 | helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
32 | printf " ${YELLOW}%-$(TARGET_MAX_CHAR_NUM)s${RESET} ${GREEN}%s${RESET}\n", helpCommand, helpMessage; \
33 | } \
34 | } \
35 | { lastLine = $$0 }' $(MAKEFILE_LIST)
36 | ########################################################
37 | # Commands
38 | ########################################################
39 | .PHONY: install file_test dir_tests all_tests coverage infection
40 |
41 | ## install all the dependencies
42 | install:
43 | @$(COMPOSER_INSTALL)
44 |
45 | ## run a specific test file ==> format: file=path/to/file
46 | method_test:
47 | @$(PHPUNIT_EXEC) --filter $(method) --no-coverage $(file)
48 |
49 | ## run a specific test file ==> format: file=path/to/file
50 | file_test:
51 | @$(PHPUNIT_EXEC) --no-coverage $(file)
52 |
53 | ## run all tests inside a directory ==> format: dir=path/to/directory
54 | dir_tests:
55 | @$(PHPUNIT_EXEC) --no-coverage $(dir)
56 |
57 | ## run all tests
58 | all_tests:
59 | @$(PHPUNIT_EXEC) --no-coverage
60 |
61 | ## generate test coverage (required for infection)
62 | coverage:
63 | @$(PHPUNIT_EXEC)
64 |
65 | ## run infection to see how quality the tests are
66 | infection:
67 | @[ -d $(INFECTION_DATA_DIR) ] || $(PHPUNIT_EXEC)
68 | @composer require --dev infection/infection
69 | @$(INFECTION_EXEC) --coverage=$(INFECTION_DATA_DIR)
70 | @composer remove --dev infection/infection
71 |
72 |
--------------------------------------------------------------------------------
/src/CDF/ClientCDFObject.php:
--------------------------------------------------------------------------------
1 | addAttribute('clientname', CDFAttribute::TYPE_STRING, $metadata['settings']['name']);
39 | return $cdf;
40 | }
41 |
42 | /**
43 | * Grabs the clientname on the cdf.
44 | *
45 | * @return \Acquia\ContentHubClient\CDFAttribute
46 | * The 'clientname' attribute.
47 | */
48 | public function getClientName() {
49 | return $this->getAttribute('clientname');
50 | }
51 |
52 | /**
53 | * Grabs the settings object instead of the attributes which are an array.
54 | *
55 | * @return \Acquia\ContentHubClient\Settings
56 | * Settings object.
57 | */
58 | public function getSettings() {
59 | // Add all the client settings as attributes to the client object.
60 | if (empty($this->settings)) {
61 | $metadata = $this->getMetadata();
62 | $this->settings = new Settings(
63 | $metadata['settings']['name'],
64 | $metadata['settings']['uuid'],
65 | $metadata['settings']['apiKey'],
66 | $metadata['settings']['secretKey'],
67 | $metadata['settings']['url'],
68 | $metadata['settings']['sharedSecret'],
69 | $metadata['settings']['webhook']
70 | );
71 | }
72 | return $this->settings;
73 | }
74 |
75 | /**
76 | * Grabs the webhook for the client.
77 | *
78 | * @return array
79 | * Webhook array.
80 | */
81 | public function getWebhook() {
82 | $metadata = $this->getMetadata();
83 | if (isset($metadata['settings']['webhook'])) {
84 | return $metadata['settings']['webhook'];
85 | }
86 |
87 | return [];
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/test/Event/GetCDFTypeEventTest.php:
--------------------------------------------------------------------------------
1 | 'dummy_type',
24 | ];
25 |
26 | /**
27 | * GetCDFTypeEvent instance.
28 | *
29 | * @var \Acquia\ContentHubClient\Event\GetCDFTypeEvent
30 | */
31 | private $getCdfTypeEvent;
32 |
33 | /**
34 | * Mocked CDF object.
35 | *
36 | * @var \PHPUnit\Framework\MockObject\MockObject
37 | */
38 | private $mockedCdfObject;
39 |
40 | /**
41 | * {@inheritDoc}
42 | */
43 | public function setUp(): void {
44 | parent::setUp();
45 |
46 | $this->mockedCdfObject = $this->getMockBuilder(CDFObject::class)
47 | ->disableOriginalConstructor()
48 | ->getMock();
49 | $this->getCdfTypeEvent = new GetCDFTypeEvent(self::DATA);
50 | }
51 |
52 | /**
53 | * {@inheritDoc}
54 | */
55 | public function tearDown(): void {
56 | parent::tearDown();
57 |
58 | unset($this->getCdfTypeEvent);
59 | }
60 |
61 | /**
62 | * Tests event creation.
63 | */
64 | public function testObjectCreationWithNoTypeSpecifiedWillThrowAnException(): void {
65 | $this->expectException(\InvalidArgumentException::class);
66 | new GetCDFTypeEvent([]);
67 | }
68 |
69 | /**
70 | * Tests event getter and setter.
71 | */
72 | public function testGetAndSetObject(): void {
73 | $this->assertNull($this->getCdfTypeEvent->getObject());
74 |
75 | $this->getCdfTypeEvent->setObject($this->mockedCdfObject);
76 | $cdfTypeEvent = $this->getCdfTypeEvent->getObject();
77 |
78 | $this->assertEquals($this->mockedCdfObject, $cdfTypeEvent);
79 | $this->assertInstanceOf(CDFObjectInterface::class, $cdfTypeEvent);
80 | }
81 |
82 | /**
83 | * @covers \Acquia\ContentHubClient\Event\GetCDFTypeEvent::getData
84 | */
85 | public function testGetData(): void {
86 | $this->assertEquals(self::DATA, $this->getCdfTypeEvent->getData());
87 | }
88 |
89 | /**
90 | * @covers \Acquia\ContentHubClient\Event\GetCDFTypeEvent::getType
91 | */
92 | public function testGetType(): void {
93 | $this->assertEquals(self::DATA['type'], $this->getCdfTypeEvent->getType());
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/SearchCriteria/SearchCriteriaBuilder.php:
--------------------------------------------------------------------------------
1 | ['search_term'],
49 | 'type' => ['type'],
50 | 'bundle' => ['bundle'],
51 | 'tags' => ['tags'],
52 | 'label' => ['label'],
53 | 'start_date' => ['start_date'],
54 | 'end_date' => ['end_date'],
55 | 'from' => ['from', 'start'],
56 | 'size' => ['size', 'limit'],
57 | 'sorting' => ['sort'],
58 | 'version' => ['version'],
59 | 'languages' => ['languages'],
60 | ];
61 | }
62 |
63 | /**
64 | * Extracts property value.
65 | *
66 | * @param string $propertyName
67 | * Property name.
68 | * @param array $data
69 | * Initial data.
70 | * @param string $default
71 | * Default value.
72 | *
73 | * @return array|mixed|string
74 | * Value.
75 | */
76 | protected static function extractPropertyFromArray(string $propertyName, array $data, $default = '') {
77 | $map = self::propertiesMap();
78 | $values = array_values(array_intersect($map[$propertyName],
79 | array_keys($data)));
80 |
81 | if (empty($values[0])) {
82 | return $default;
83 | }
84 |
85 | $key = $values[0];
86 |
87 | return is_array($default) && !is_array($data[$key]) ? [$data[$key]] : $data[$key];
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/test/SettingsTest.php:
--------------------------------------------------------------------------------
1 | setting_data = [
38 | 'name' => 'some-name',
39 | 'uuid' => 'some-uuid',
40 | 'apiKey' => 'some-api-key',
41 | 'secretKey' => 'some-secret-key',
42 | 'url' => 'some-url',
43 | 'sharedSecret' => 'some-shared-secret',
44 | 'webhook' => [
45 | 'webhook1' => 'w1-uuid',
46 | 'webhook2' => 'w2-uuid',
47 | ],
48 | ];
49 |
50 | $this->settings = new Settings(...array_values($this->setting_data));
51 | }
52 |
53 | /**
54 | * {@inheritDoc}
55 | */
56 | public function tearDown(): void {
57 | parent::tearDown();
58 |
59 | unset($this->settings, $this->setting_data);
60 | }
61 |
62 | /**
63 | * @covers \Acquia\ContentHubClient\Settings::toArray
64 | */
65 | public function testToArrayReturnsExactlyTheArraySettingWasCreatedOff(): void {
66 | $this->assertEquals($this->settings->toArray(), $this->setting_data);
67 | }
68 |
69 | /**
70 | * @covers \Acquia\ContentHubClient\Settings::getUuid
71 | */
72 | public function testToGetUuidReturnsFalseIfInitializedWithEmptyValue(): void {
73 | $this->setting_data['uuid'] = '';
74 | $this->settings = new Settings(...array_values($this->setting_data));
75 | $this->assertFalse($this->settings->getUuid());
76 | }
77 |
78 | /**
79 | * @covers \Acquia\ContentHubClient\Settings::getWebhook
80 | */
81 | public function testToGetWebhookReturnsFalseIfInitializedWithEmptyValue(): void {
82 | $this->setting_data['webhook'] = [];
83 | $this->settings = new Settings(...array_values($this->setting_data));
84 | $this->assertFalse($this->settings->getWebhook());
85 | }
86 |
87 | /**
88 | * @covers \Acquia\ContentHubClient\Settings::getWebhook
89 | */
90 | public function testToGetWebhookReturnsFalseIfCalledWithNonExistentKey(): void {
91 | $this->assertFalse($this->settings->getWebhook('some-non-existent-key'));
92 | }
93 |
94 | /**
95 | * @covers \Acquia\ContentHubClient\Settings::getWebhook
96 | */
97 | public function testToGetWebhookReturnsRespectiveValueCalledWithExistentKey(): void {
98 | $webhook = $this->settings->getWebhook('webhook1');
99 |
100 | $this->assertNotFalse($webhook);
101 | $this->assertEquals('w1-uuid', $webhook);
102 | }
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/test/CDF/ClientCDFObjectTest.php:
--------------------------------------------------------------------------------
1 | 'some-origin',
24 | 'created' => 'some-time',
25 | 'modified' => 'some-other-time',
26 | 'settings' => [
27 | 'uuid' => 'some-uuid',
28 | 'name' => 'some-name',
29 | 'apiKey' => 'some-api-key',
30 | 'secretKey' => 'some-secret-key',
31 | 'url' => 'some-url',
32 | 'sharedSecret' => NULL,
33 | 'webhook' => [
34 | 'webhook1' => 'w1-uuid',
35 | 'webhook2' => 'w2-uuid',
36 | ],
37 | ],
38 | ];
39 |
40 | /**
41 | * ClientCDFObject instance.
42 | *
43 | * @var \Acquia\ContentHubClient\CDF\ClientCDFObject
44 | */
45 | private $clientCdfObject;
46 |
47 | /**
48 | * {@inheritDoc}
49 | */
50 | public function setUp(): void {
51 | parent::setUp();
52 |
53 | $this->clientCdfObject = ClientCDFObject::create('client_cdf_id_1', self::METADATA);
54 | }
55 |
56 | /**
57 | * {@inheritDoc}
58 | */
59 | public function tearDown(): void {
60 | parent::tearDown();
61 |
62 | unset($this->clientCdfObject);
63 | }
64 |
65 | /**
66 | * @covers \Acquia\ContentHubClient\CDF\ClientCDFObject::getClientName
67 | */
68 | public function testGetClientName(): void {
69 | $clientName = $this->clientCdfObject->getClientName();
70 |
71 | $this->assertInstanceOf(CDFAttribute::class, $clientName);
72 | $this->assertEquals(CDFAttribute::TYPE_STRING, $clientName->getType());
73 | $this->assertEquals(self::METADATA['settings']['name'], $clientName->getValue()[CDFObject::LANGUAGE_UNDETERMINED]);
74 | }
75 |
76 | /**
77 | * @covers \Acquia\ContentHubClient\CDF\ClientCDFObject::getSettings
78 | */
79 | public function testGetSettings(): void {
80 | $settings = self::METADATA['settings'];
81 | $settings['secretKey'] = '********';
82 | $this->assertEquals($settings, $this->clientCdfObject->getSettings()->toArray());
83 | }
84 |
85 | /**
86 | * @covers \Acquia\ContentHubClient\CDF\ClientCDFObject::getWebhook
87 | */
88 | public function testGetWebhookReturnsNonEmptyArrayWhenThereAreSome(): void {
89 | $this->assertEquals(self::METADATA['settings']['webhook'], $this->clientCdfObject->getWebhook());
90 | }
91 |
92 | /**
93 | * @covers \Acquia\ContentHubClient\CDF\ClientCDFObject::getWebhook
94 | */
95 | public function testGetWebhookReturnsEmptyArrayWhenThereIsNone(): void {
96 | $metadata = self::METADATA;
97 | unset($metadata['settings']['webhook']);
98 | $this->clientCdfObject = ClientCDFObject::create('client_cdf_id_1', $metadata);
99 |
100 | $this->assertCount(0, $this->clientCdfObject->getWebhook());
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/test/WebhookTest.php:
--------------------------------------------------------------------------------
1 | definition = [
39 | 'uuid' => 'some-uuid',
40 | 'client_uuid' => 'some-client_uuid',
41 | 'client_name' => 'some-client-name',
42 | 'url' => 'some-url',
43 | 'version' => 1,
44 | 'disable_retries' => FALSE,
45 | 'filters' => [
46 | 'filter1_uuid',
47 | 'filter2_uuid',
48 | ],
49 | 'status' => 'some-status',
50 | 'is_migrated' => FALSE,
51 | 'suppressed_until' => 0,
52 | ];
53 |
54 | $this->webhook = new Webhook($this->definition);
55 | }
56 |
57 | /**
58 | * {@inheritDoc}
59 | */
60 | protected function tearDown(): void {
61 | parent::tearDown();
62 |
63 | unset($this->webhook, $this->definition);
64 | }
65 |
66 | /**
67 | * Tests webhook creation.
68 | */
69 | public function testGettersReturnWhatPropertiesWereSetTo(): void {
70 | $this->assertEquals(
71 | [
72 | $this->webhook->getUuid(),
73 | $this->webhook->getClientUuid(),
74 | $this->webhook->getClientName(),
75 | $this->webhook->getUrl(),
76 | $this->webhook->getVersion(),
77 | $this->webhook->getDisableRetries(),
78 | $this->webhook->getFilters(),
79 | $this->webhook->getStatus(),
80 | $this->webhook->getIsMigrated(),
81 | $this->webhook->getSuppressedUntil(),
82 | ],
83 | array_values($this->definition)
84 | );
85 |
86 | $this->assertEquals($this->webhook->getDefinition(), $this->definition);
87 | }
88 |
89 | /**
90 | * Tests webhook status.
91 | */
92 | public function testGetIsEnabledReturnsTrueIfStatusIsEnabled(): void {
93 | $this->definition['status'] = 'ENABLED';
94 | $this->webhook = new Webhook($this->definition);
95 | $this->assertTrue($this->webhook->isEnabled());
96 | }
97 |
98 | /**
99 | * Tests webhook status.
100 | */
101 | public function testGetIsEnabledReturnsTrueIfStatusIsEmptyString(): void {
102 | $this->definition['status'] = '';
103 | $this->webhook = new Webhook($this->definition);
104 | $this->assertTrue($this->webhook->isEnabled());
105 | }
106 |
107 | /**
108 | * Tests webhook status.
109 | */
110 | public function testGetIsEnabledReturnsFalseIfStatusIsNeitherENABLEDnorEmptyString(): void { // phpcs:ignore
111 | $this->definition['status'] = 'some-status';
112 | $this->webhook = new Webhook($this->definition);
113 | $this->assertFalse($this->webhook->isEnabled());
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/src/CDF/CDFObjectInterface.php:
--------------------------------------------------------------------------------
1 | ';
32 |
33 | const TYPE_ARRAY_STRING = 'array';
34 |
35 | const TYPE_ARRAY_KEYWORD = 'array';
36 |
37 | const TYPE_ARRAY_BOOLEAN = 'array';
38 |
39 | const TYPE_ARRAY_NUMBER = 'array';
40 |
41 | const TYPE_ARRAY_REFERENCE = 'array';
42 |
43 | /**
44 | * The identifier of the attribute.
45 | *
46 | * @var string
47 | */
48 | protected $id;
49 |
50 | /**
51 | * The attribute's data type.
52 | *
53 | * @var string
54 | */
55 | protected $type;
56 |
57 | /**
58 | * The value of the attribute.
59 | *
60 | * @var mixed
61 | */
62 | protected $value;
63 |
64 | /**
65 | * CDFAttribute constructor.
66 | *
67 | * @param string $id
68 | * The identifier of the attribute.
69 | * @param string $type
70 | * The attribute's data type.
71 | * @param mixed $value
72 | * The value of the attribute.
73 | * @param string $language
74 | * The language of the initial value.
75 | *
76 | * @throws \Exception
77 | * Unsupported data type exception.
78 | */
79 | public function __construct($id, $type, $value = NULL, $language = CDFObject::LANGUAGE_UNDETERMINED) {
80 | $r = new \ReflectionClass(__CLASS__);
81 | if (!in_array($type, $r->getConstants())) {
82 | // @todo validate value against data type?
83 | throw new \Exception(sprintf("Unsupported CDF Attribute data type \"%s\".", $type));
84 | }
85 | $this->id = $id;
86 | $this->type = $type;
87 |
88 | if ($value !== NULL) {
89 | $this->value[$language] = $value;
90 | }
91 | }
92 |
93 | /**
94 | * ID getter.
95 | *
96 | * @return string
97 | * Attribute ID.
98 | */
99 | public function getId() {
100 | return $this->id;
101 | }
102 |
103 | /**
104 | * Type getter.
105 | *
106 | * @return string
107 | * Attribute type.
108 | */
109 | public function getType() {
110 | return $this->type;
111 | }
112 |
113 | /**
114 | * Value getter.
115 | *
116 | * @return mixed
117 | * Attribute value.
118 | */
119 | public function getValue() {
120 | return $this->value;
121 | }
122 |
123 | /**
124 | * Value setter.
125 | *
126 | * @param mixed $value
127 | * Attribute value.
128 | * @param string $language
129 | * Attribute language.
130 | */
131 | public function setValue($value, $language = CDFObject::LANGUAGE_UNDETERMINED) {
132 | $this->value[$language] = $value;
133 | }
134 |
135 | /**
136 | * Transforms attribute to array.
137 | *
138 | * @return array
139 | * Array representation.
140 | */
141 | public function toArray() {
142 | return [
143 | 'type' => $this->getType(),
144 | 'value' => $this->getValue(),
145 | ];
146 | }
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/src/Webhook.php:
--------------------------------------------------------------------------------
1 | definition = $definition;
29 | }
30 |
31 | /**
32 | * Returns webhook UUID.
33 | *
34 | * @return string
35 | * Webhook UUID.
36 | */
37 | public function getUuid() {
38 | return $this->definition['uuid'];
39 | }
40 |
41 | /**
42 | * Returns client UUID of the webhook.
43 | *
44 | * @return string
45 | * Client's UUID.
46 | */
47 | public function getClientUuid() {
48 | return $this->definition['client_uuid'];
49 | }
50 |
51 | /**
52 | * Returns client name of the webhook.
53 | *
54 | * @return string
55 | * Client's name.
56 | */
57 | public function getClientName() {
58 | return $this->definition['client_name'];
59 | }
60 |
61 | /**
62 | * Returns URL of the webhook.
63 | *
64 | * @return string
65 | * Webhook URL.
66 | */
67 | public function getUrl() {
68 | return $this->definition['url'];
69 | }
70 |
71 | /**
72 | * Returns version of the webhook.
73 | *
74 | * @return string
75 | * Webhook version string.
76 | */
77 | public function getVersion() {
78 | return $this->definition['version'];
79 | }
80 |
81 | /**
82 | * Returns state of the 'disable_retries' option.
83 | *
84 | * @return string
85 | * State of the 'disable_retries' option.
86 | */
87 | public function getDisableRetries() {
88 | return $this->definition['disable_retries'];
89 | }
90 |
91 | /**
92 | * Returns filters list of the webhook.
93 | *
94 | * @return array
95 | * Filters list.
96 | */
97 | public function getFilters() {
98 | return $this->definition['filters'];
99 | }
100 |
101 | /**
102 | * Returns status of the webhook.
103 | *
104 | * @return string
105 | * Webhook status.
106 | */
107 | public function getStatus() {
108 | return $this->definition['status'];
109 | }
110 |
111 | /**
112 | * Returns 'is_migrated' property.
113 | *
114 | * @return bool
115 | * 'is_migrated' property.
116 | */
117 | public function getIsMigrated(): bool {
118 | return $this->definition['is_migrated'];
119 | }
120 |
121 | /**
122 | * Returns 'suppressed_until' property.
123 | *
124 | * @return int
125 | * 'suppressed_until' property.
126 | */
127 | public function getSuppressedUntil(): int {
128 | return $this->definition['suppressed_until'];
129 | }
130 |
131 | /**
132 | * Returns definition of the webhook.
133 | *
134 | * @return array
135 | * Webhook definition.
136 | */
137 | public function getDefinition() {
138 | return $this->definition;
139 | }
140 |
141 | /**
142 | * Returns the state of the webhook.
143 | *
144 | * @return bool
145 | * Whether the webhook is in enabled or in the disabled state.
146 | */
147 | public function isEnabled() {
148 | $enabled = [
149 | 'enabled',
150 | '',
151 | ];
152 | return in_array(strtolower($this->getStatus()), $enabled, TRUE);
153 | }
154 |
155 | }
156 |
--------------------------------------------------------------------------------
/src/CDFDocument.php:
--------------------------------------------------------------------------------
1 | setCdfEntities(...$entities);
29 | }
30 |
31 | /**
32 | * Returns entities list.
33 | *
34 | * @return \Acquia\ContentHubClient\CDF\CDFObject[]
35 | * Entities list.
36 | */
37 | public function getEntities() {
38 | return $this->entities;
39 | }
40 |
41 | /**
42 | * Returns entity by UUID.
43 | *
44 | * @param string $uuid
45 | * Entity UUID.
46 | *
47 | * @return \Acquia\ContentHubClient\CDF\CDFObject|null
48 | * CDFObject if exists, otherwise NULL
49 | */
50 | public function getCdfEntity($uuid) {
51 | return $this->entities[$uuid] ?? NULL;
52 | }
53 |
54 | /**
55 | * Entities setter.
56 | *
57 | * @param \Acquia\ContentHubClient\CDF\CDFObject[] $entities
58 | * Entities list.
59 | */
60 | public function setCdfEntities(CDFObject ...$entities) { // phpcs:ignore
61 | $entitiesList = [];
62 | foreach ($entities as $entity) {
63 | $entitiesList[$entity->getUuid()] = $entity;
64 | }
65 | $this->entities = $entitiesList;
66 | }
67 |
68 | /**
69 | * Appends CDF object to document.
70 | *
71 | * @param \Acquia\ContentHubClient\CDF\CDFObject $object
72 | * CDF object.
73 | */
74 | public function addCdfEntity(CDFObject $object) {
75 | $this->entities[$object->getUuid()] = $object;
76 | }
77 |
78 | /**
79 | * Removes entity from document.
80 | *
81 | * @param string $uuid
82 | * Entity UUID.
83 | */
84 | public function removeCdfEntity($uuid) {
85 | unset($this->entities[$uuid]);
86 | }
87 |
88 | /**
89 | * Checks if document contains entities.
90 | *
91 | * @return bool
92 | * TRUE if entities exists, otherwise FALSE.
93 | */
94 | public function hasEntities() {
95 | return (bool) $this->entities;
96 | }
97 |
98 | /**
99 | * Checks that entity exists in document.
100 | *
101 | * @param string $uuid
102 | * Entity UUID.
103 | *
104 | * @return bool
105 | * TRUE if entity exists, otherwise FALSE.
106 | */
107 | public function hasEntity($uuid) {
108 | return !empty($this->entities[$uuid]);
109 | }
110 |
111 | /**
112 | * Merges CDF document into current.
113 | *
114 | * @param \Acquia\ContentHubClient\CDFDocument $document
115 | * CDF document.
116 | */
117 | public function mergeDocuments(CDFDocument $document) {
118 | foreach ($document->getEntities() as $entity) {
119 | $this->addCdfEntity($entity);
120 | }
121 | }
122 |
123 | /**
124 | * Converts CDF document to string (JSON).
125 | *
126 | * @return false|string
127 | * String representation.
128 | */
129 | public function toString() {
130 | $entities = [];
131 | foreach ($this->getEntities() as $entity) {
132 | $entities[] = $entity->toArray();
133 | }
134 | $output = ['entities' => $entities];
135 |
136 | return json_encode($output, JSON_PRETTY_PRINT);
137 | }
138 |
139 | }
140 |
--------------------------------------------------------------------------------
/test/EventSubscriber/ClientCDFTest.php:
--------------------------------------------------------------------------------
1 | client_cdf = new ClientCDF();
43 | $this->handler = current(current($this->client_cdf::getSubscribedEvents()[ContentHubLibraryEvents::GET_CDF_CLASS]));
44 | }
45 |
46 | /**
47 | * {@inheritdoc}
48 | */
49 | public function tearDown(): void {
50 | parent::tearDown();
51 |
52 | unset($this->client_cdf, $this->handler);
53 | }
54 |
55 | /**
56 | * {@inheritdoc}
57 | */
58 | public function testGetSubscribedEventsAddsHandlerToEvent() {
59 | $this->assertNotNull($this->handler);
60 | }
61 |
62 | /**
63 | * {@inheritdoc}
64 | */
65 | public function testEventGetsHandledWhenTypeIsClient() {
66 | $event = $this->getGetCDFTypeEvent();
67 | $event->expects($this->once())
68 | ->method('getType')
69 | ->willReturn('client');
70 |
71 | $event->expects($this->once())
72 | ->method('getData')
73 | ->willReturn(['metadata' => 'Client Metadata']);
74 |
75 | $event->expects($this->once())
76 | ->method('setObject');
77 |
78 | $event->expects($this->once())
79 | ->method('stopPropagation');
80 |
81 | $this->client_cdf->{$this->handler}($event);
82 | }
83 |
84 | /**
85 | * {@inheritdoc}
86 | */
87 | public function testHandlerDoesNothingWhenTypeIsNonClient() {
88 | $event = $this->getGetCDFTypeEvent();
89 | $event->expects($this->once())
90 | ->method('getType')
91 | ->willReturn('non-client');
92 |
93 | $event->expects($this->never())
94 | ->method('getData');
95 |
96 | $event->expects($this->never())
97 | ->method('setObject');
98 |
99 | $event->expects($this->never())
100 | ->method('stopPropagation');
101 |
102 | $this->client_cdf->{$this->handler}($event);
103 | }
104 |
105 | /**
106 | * Mock builder for GetCDFTypeEvent class.
107 | *
108 | * @return \Acquia\ContentHubClient\Event\GetCDFTypeEvent
109 | * Mocked object.
110 | */
111 | private function getGetCDFTypeEvent(): GetCDFTypeEvent { // phpcs:ignore
112 | $mock_cdf_object = \Mockery::mock(CDFObject::class);
113 | $mock_client_cdf_object = \Mockery::mock('overload:' . ClientCDFObject::class);
114 |
115 | $mock_client_cdf_object->shouldReceive('fromArray')
116 | ->once()
117 | ->andReturn($mock_cdf_object);
118 |
119 | return $this->getMockBuilder(GetCDFTypeEvent::class)
120 | ->disableOriginalConstructor()
121 | ->onlyMethods([
122 | 'getType',
123 | 'setObject',
124 | 'stopPropagation',
125 | 'getData',
126 | 'getObject',
127 | ])
128 | ->getMock();
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/src/Guzzle/Middleware/RequestResponseLogger.php:
--------------------------------------------------------------------------------
1 | request = $request;
57 | $this->response = $response;
58 | $this->logger = $logger;
59 | $this->decodedResponseBody = json_decode($response->getBody(), TRUE);
60 | }
61 |
62 | /**
63 | * Logs response/request data.
64 | */
65 | public function log(): void {
66 | if (!$this->isTrackable()) {
67 | return;
68 | }
69 |
70 | $message = $this->buildLogMessage();
71 |
72 | $this->logMessage($message, $this->response->getStatusCode());
73 | }
74 |
75 | /**
76 | * Checks if a response can be tracked.
77 | *
78 | * @return bool
79 | * TRUE in the case when the response should be tracked.
80 | */
81 | protected function isTrackable(): bool {
82 | // Skip tracking for requests without ID.
83 | if (empty($this->decodedResponseBody['request_id'])) {
84 | return FALSE;
85 | }
86 |
87 | // Skip tracking for requests with a shared secret.
88 | if (isset($this->decodedResponseBody['shared_secret'])) {
89 | return FALSE;
90 | }
91 |
92 | // Skip tracking for requests with sensitive data.
93 | if (isset($this->decodedResponseBody['data']['data']['metadata']['settings'])) {
94 | return FALSE;
95 | }
96 |
97 | return TRUE;
98 | }
99 |
100 | /**
101 | * Builds log message.
102 | *
103 | * @return string
104 | * Log message.
105 | */
106 | protected function buildLogMessage(): string {
107 | return sprintf(
108 | 'Request ID: %s. Method: %s. Path: %s. Status code: %d.',
109 | $this->decodedResponseBody['request_id'],
110 | $this->request->getMethod(),
111 | $this->request->getUri()->getPath(),
112 | $this->response->getStatusCode()
113 | );
114 | }
115 |
116 | /**
117 | * Logs message depending on response status code.
118 | *
119 | * @param string $message
120 | * Log message.
121 | * @param int $responseStatusCode
122 | * Response status code.
123 | */
124 | protected function logMessage(string $message, int $responseStatusCode): void {
125 | if ($responseStatusCode >= Response::HTTP_INTERNAL_SERVER_ERROR) {
126 | $this->logger->error($message);
127 |
128 | return;
129 | }
130 |
131 | if ($responseStatusCode >= Response::HTTP_BAD_REQUEST) {
132 | $this->logger->warning($message);
133 |
134 | return;
135 | }
136 |
137 | $this->logger->info($message);
138 | }
139 |
140 | }
141 |
--------------------------------------------------------------------------------
/test/SettingsTestBase.php:
--------------------------------------------------------------------------------
1 | "someuser",
34 | "created" => "2014-12-21T20:12:11+00:00Z",
35 | "modified" => "2014-12-21T20:12:11+00:00Z",
36 | "webhooks" => [
37 | [
38 | "url" => "http://example1.com/webhooks",
39 | "uuid" => "00000000-0000-0000-0000-000000000000",
40 | ],
41 | [
42 | "url" => "http://example2.com/webhooks",
43 | "uuid" => "11111111-0000-0000-0000-000000000000",
44 | ],
45 | ],
46 | "clients" => [
47 | [
48 | "name" => "My Client Site 1",
49 | "uuid" => "22222222-0000-0000-0000-000000000000",
50 | ],
51 | ],
52 | "success" => 1,
53 | ];
54 | }
55 |
56 | /**
57 | * Tests settings.
58 | */
59 | public function testReadSettings() {
60 | // Setup.
61 | $data = $this->setData();
62 | $responses = [
63 | new Response(200, [], json_encode($data)),
64 | ];
65 | $client = $this->getClient($responses);
66 |
67 | // Read Settings.
68 | $settings = $client->getSettings();
69 | $this->assertEquals($data['uuid'], $settings->getUuid());
70 | $this->assertEquals($data['created'], $settings->getCreated());
71 | $this->assertEquals($data['modified'], $settings->getModified());
72 | $this->assertEquals($data['webhooks'], $settings->getWebhooks());
73 | $this->assertEquals($data['clients'], $settings->getClients());
74 | $this->assertEquals($data['success'], $settings->success());
75 |
76 | $this->assertEquals($data['webhooks'][0],
77 | $settings->getWebhook('http://example1.com/webhooks'));
78 | $this->assertFalse($settings->getWebhook('http://example.com/webhook'));
79 | $this->assertEquals($data['clients'][0],
80 | $settings->getClient('My Client Site 1'));
81 | $this->assertFalse($settings->getClient('My Client Site 2'));
82 | }
83 |
84 | /**
85 | * @covers \Acquia\ContentHubClient\ContentHubClient::register
86 | */
87 | public function testRegisterClients() {
88 | // Setup.
89 | $data = $this->setData()['clients'][0];
90 | $responses = [
91 | new Response(200, [], json_encode($data)),
92 | ];
93 | $client = $this->getClient($responses);
94 |
95 | // Add a Client.
96 | $registered_client = $client->register('My Client Site 1');
97 | $this->assertEquals($data, $registered_client);
98 | }
99 |
100 | /**
101 | * @covers \Acquia\ContentHubClient\ContentHubClient::addWebhook
102 | */
103 | public function testAddWebhook() {
104 | // Setup.
105 | $data = $this->setData()['webhooks'][0];
106 | $responses = [
107 | new Response(200, [], json_encode($data)),
108 | ];
109 | $client = $this->getClient($responses);
110 |
111 | // Set a Webhook.
112 | $webhook = $client->addWebhook('http://example1.com/webhooks');
113 | $this->assertEquals($data, $webhook);
114 | }
115 |
116 | /**
117 | * @covers \Acquia\ContentHubClient\ContentHubClient::deleteWebhook
118 | */
119 | public function testDeleteWebhook() {
120 | // Setup.
121 | $data = [
122 | 'success' => 1,
123 | ];
124 | $responses = [
125 | new Response(200, [], json_encode($data)),
126 | ];
127 | $client = $this->getClient($responses);
128 |
129 | // Deletes a Webhook.
130 | $webhook = $client->deleteWebhook('http://example1.com/webhooks');
131 | $this->assertEquals($data, json_decode($webhook->getBody(), TRUE));
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/test/SearchCriteria/SearchCriteriaBuilderTest.php:
--------------------------------------------------------------------------------
1 | default_search_criteria_data = [
41 | 'search_term' => SearchCriteria::DEFAULT_SEARCH_TERM,
42 | 'type' => [],
43 | 'bundle' => [],
44 | 'tags' => [],
45 | 'label' => '',
46 | 'start_date' => NULL,
47 | 'end_date' => NULL,
48 | 'from' => SearchCriteria::DEFAULT_OFFSET,
49 | 'size' => SearchCriteria::DEFAULT_LIMIT,
50 | 'sorting' => '',
51 | 'version' => SearchCriteria::DEFAULT_VERSION,
52 | 'languages' => [CDFObject::LANGUAGE_UNDETERMINED],
53 | ];
54 |
55 | $this->search_criteria_data = [
56 | 'search_term' => 'some-search-term',
57 | 'type' => ['type1', 'type2'],
58 | 'bundle' => ['bundle1', 'bundle2', 'bundle3'],
59 | 'tags' => ['tag1', 'tag2'],
60 | 'label' => 'some-label',
61 | 'start_date' => new \DateTimeImmutable(),
62 | 'end_date' => new \DateTimeImmutable(),
63 | 'from' => 10,
64 | 'size' => 20,
65 | 'sorting' => '',
66 | 'version' => 'some-version',
67 | 'languages' => ['lang1'],
68 | ];
69 | }
70 |
71 | /**
72 | * {@inheritDoc}
73 | */
74 | protected function tearDown(): void {
75 | parent::tearDown();
76 | }
77 |
78 | /**
79 | * Tests SearchCriteria creation with all required params.
80 | */
81 | public function testObjectCreationWithAllRequiredParams(): void {
82 | $search_criteria = SearchCriteriaBuilder::createFromArray($this->search_criteria_data);
83 |
84 | $this->assertEquals($search_criteria->jsonSerialize(), $this->search_criteria_data);
85 | $this->assertEquals($search_criteria->getSearchTerm(), $this->search_criteria_data['search_term']);
86 | $this->assertEquals($search_criteria->getEntityType(), $this->search_criteria_data['type']);
87 | $this->assertEquals($search_criteria->getBundle(), $this->search_criteria_data['bundle']);
88 | $this->assertEquals($search_criteria->getTags(), $this->search_criteria_data['tags']);
89 | $this->assertEquals($search_criteria->getLabel(), $this->search_criteria_data['label']);
90 | $this->assertEquals($search_criteria->getStartDate(), $this->search_criteria_data['start_date']);
91 | $this->assertEquals($search_criteria->getEndDate(), $this->search_criteria_data['end_date']);
92 | $this->assertEquals($search_criteria->getFrom(), $this->search_criteria_data['from']);
93 | $this->assertEquals($search_criteria->getSize(), $this->search_criteria_data['size']);
94 | $this->assertEquals($search_criteria->getSorting(), $this->search_criteria_data['sorting']);
95 | $this->assertEquals($search_criteria->getVersion(), $this->search_criteria_data['version']);
96 | }
97 |
98 | /**
99 | * Tests SearchCriteria creation with all default params.
100 | */
101 | public function testObjectCreationWithAllDefaultParams(): void {
102 | $search_criteria = SearchCriteriaBuilder::createFromArray($this->default_search_criteria_data);
103 |
104 | $this->assertEquals($search_criteria->jsonSerialize(), $this->default_search_criteria_data);
105 | }
106 |
107 | /**
108 | * Tests SearchCriteria creation from empty array.
109 | */
110 | public function testObjectCreationWithUnsetParamsUsesDefault(): void {
111 | $search_criteria = SearchCriteriaBuilder::createFromArray([]);
112 |
113 | $this->assertEquals($search_criteria->jsonSerialize(), $this->default_search_criteria_data);
114 | }
115 |
116 | /**
117 | * Tests language switching.
118 | */
119 | public function testSetLanguagesOnSearchCriteriaChangesLanguages(): void {
120 | $new_languages = ['new-lang1', 'new-lang2'];
121 |
122 | $search_criteria = SearchCriteriaBuilder::createFromArray($this->search_criteria_data);
123 | $this->assertNotEquals($search_criteria->getLanguages(), $new_languages);
124 |
125 | $search_criteria->setLanguages($new_languages);
126 |
127 | $this->assertEquals($search_criteria->getLanguages(), $new_languages);
128 | }
129 |
130 | }
131 |
--------------------------------------------------------------------------------
/src/Settings.php:
--------------------------------------------------------------------------------
1 | name = $name;
92 | $this->uuid = $uuid;
93 | $this->apiKey = $api_key;
94 | $this->secretKey = $secret_key;
95 | $this->url = $url;
96 | $this->sharedSecret = $shared_secret;
97 | $this->webhook = $webhook;
98 | }
99 |
100 | /**
101 | * Transforms settings object to array.
102 | *
103 | * @return array
104 | * Array representation.
105 | */
106 | public function toArray() {
107 | return [
108 | 'name' => $this->getName(),
109 | 'uuid' => $this->getUuid(),
110 | 'apiKey' => $this->getApiKey(),
111 | 'secretKey' => $this->getSecretKey(),
112 | 'url' => $this->getUrl(),
113 | 'sharedSecret' => $this->getSharedSecret(),
114 | 'webhook' => $this->webhook,
115 | ];
116 | }
117 |
118 | /**
119 | * Get the settings name.
120 | *
121 | * @return string
122 | * Name attribute.
123 | */
124 | public function getName() {
125 | return $this->name;
126 | }
127 |
128 | /**
129 | * Returns the Uuid.
130 | *
131 | * @return string|bool
132 | * UUID attribute.
133 | */
134 | public function getUuid() {
135 | return !empty($this->uuid) ? $this->uuid : FALSE;
136 | }
137 |
138 | /**
139 | * Returns the webhook UUID associated with this site.
140 | *
141 | * @param string $op
142 | * Optional setting to grab the specific key for a webhook. Options are:
143 | * * uuid: The UUID for the webhook.
144 | * * url: The fully qualified URL that plexus accesses the site.
145 | * * settings_url: The nice URL that users interact with.
146 | *
147 | * @return string
148 | * The Webhook if set from connection settings.
149 | */
150 | public function getWebhook($op = 'settings_url') {
151 | if (empty($this->webhook) || !isset($this->webhook[$op])) {
152 | return FALSE;
153 | }
154 |
155 | return $this->webhook[$op];
156 | }
157 |
158 | /**
159 | * Returns URL of the endpoint.
160 | *
161 | * @return string
162 | * URL of the endpoint.
163 | */
164 | public function getUrl() {
165 | return $this->url;
166 | }
167 |
168 | /**
169 | * Returns middleware.
170 | *
171 | * @codeCoverageIgnore
172 | *
173 | * @return \Acquia\Hmac\Guzzle\HmacAuthMiddleware
174 | * Auth middleware.
175 | */
176 | public function getMiddleware() {
177 | $key = new Key($this->getApiKey(), $this->getSecretKey());
178 |
179 | return new HmacAuthMiddleware($key);
180 | }
181 |
182 | /**
183 | * Returns API key of these settings.
184 | *
185 | * @return string
186 | * API key of these settings.
187 | */
188 | public function getApiKey() {
189 | return $this->apiKey;
190 | }
191 |
192 | /**
193 | * Returns the API Secret Key used for Webhook verification.
194 | *
195 | * @return string|bool
196 | * The api secret key if it is set, FALSE otherwise.
197 | */
198 | public function getSecretKey() {
199 | return $this->secretKey;
200 | }
201 |
202 | /**
203 | * Returns shared secret.
204 | *
205 | * @return null|string
206 | * Shared secret.
207 | */
208 | public function getSharedSecret() {
209 | return $this->sharedSecret;
210 | }
211 |
212 | }
213 |
--------------------------------------------------------------------------------
/src/ObjectFactory.php:
--------------------------------------------------------------------------------
1 | attributeData = $this->getAttributeData();
37 | $this->attributeId = $this->attributeData['attributes']['id'];
38 | }
39 |
40 | /**
41 | * {@inheritDoc}
42 | */
43 | public function tearDown(): void {
44 | unset($this->attributeId);
45 | unset($this->attributeData);
46 | }
47 |
48 | /**
49 | * @covers \Acquia\ContentHubClient\CDFAttribute::getType
50 | *
51 | * @throws \Exception
52 | */
53 | public function testCreateStringAttribute() {
54 | $title = $this->attributeData['attributes']['title'];
55 |
56 | $attribute = new CDFAttribute($this->attributeId, CDFAttribute::TYPE_STRING);
57 | $this->assertEquals('string', $attribute->getType());
58 |
59 | foreach ($title['value'] as $language => $value) {
60 | $attribute->setValue($value, $language);
61 | }
62 |
63 | $this->assertEquals($title['value'], $attribute->getValue());
64 | }
65 |
66 | /**
67 | * @covers \Acquia\ContentHubClient\CDFAttribute::getType
68 | *
69 | * @throws \Exception
70 | */
71 | public function testCreateNumericAttribute() {
72 | $numericAttribute = $this->attributeData['attributes']['num'];
73 |
74 | $attribute = new CDFAttribute($this->attributeId, CDFAttribute::TYPE_NUMBER);
75 | $this->assertEquals('number', $attribute->getType());
76 |
77 | foreach ($numericAttribute['value'] as $language => $value) {
78 | $attribute->setValue($value, $language);
79 | }
80 |
81 | $this->assertEquals($numericAttribute['value'], $attribute->getValue());
82 | }
83 |
84 | /**
85 | * @covers \Acquia\ContentHubClient\CDFAttribute
86 | * @throws \Exception
87 | */
88 | public function testAttributeToArrayConvert() {
89 | $value = $this->attributeData['attributes']['num']['value']['en'];
90 |
91 | $attribute = new CDFAttribute($this->attributeId, CDFAttribute::TYPE_NUMBER, $value);
92 |
93 | $expected = [
94 | 'type' => CDFAttribute::TYPE_NUMBER,
95 | 'value' => [CDFObject::LANGUAGE_UNDETERMINED => $value],
96 | ];
97 |
98 | $this->assertEquals($this->attributeId, $attribute->getId());
99 | $this->assertEquals($expected, $attribute->toArray());
100 | }
101 |
102 | /**
103 | * @covers \Acquia\ContentHubClient\CDFAttribute
104 | *
105 | * @throws \Exception
106 | */
107 | public function testCreateNumericArrayAttribute() {
108 | $numericArrayAttribute = $this->attributeData['attributes']['num_array'];
109 |
110 | $attribute = new CDFAttribute($this->attributeId, CDFAttribute::TYPE_ARRAY_NUMBER);
111 | $this->assertEquals('array', $attribute->getType());
112 |
113 | foreach ($numericArrayAttribute['value'] as $language => $value) {
114 | $attribute->setValue($value, $language);
115 | }
116 |
117 | $this->assertEquals($numericArrayAttribute['value'], $attribute->getValue());
118 | }
119 |
120 | /**
121 | * @covers \Acquia\ContentHubClient\CDFAttribute
122 | */
123 | public function testUnsupportedDataTypeAttribute() {
124 | try {
125 | $dataType = 'unsupported_data_type';
126 | $attribute = new CDFAttribute($this->attributeId, $dataType);
127 | $this->fail(sprintf("It was expected an exception from \"%s\".", $dataType));
128 | }
129 | catch (\Exception $e) {
130 | $this->assertEquals(sprintf("Unsupported CDF Attribute data type \"%s\".", $dataType), $e->getMessage());
131 | }
132 | }
133 |
134 | /**
135 | * Provides test data.
136 | *
137 | * @return array
138 | * Test data.
139 | */
140 | private function getAttributeData() {
141 | return [
142 | "attributes" => [
143 | "id" => 1,
144 | "num_array" => [
145 | "type" => "array",
146 | "value" => [
147 | "en" => [
148 | 6.66,
149 | 3.23,
150 | ],
151 | "hu" => [
152 | 4.66,
153 | 4.23,
154 | ],
155 | "und" => [
156 | 1.22,
157 | 1.11,
158 | ],
159 | ],
160 | ],
161 | "num" => [
162 | "type" => "number",
163 | "value" => [
164 | 'en' => 13.45,
165 | 'es' => 1.43,
166 | CDFObject::LANGUAGE_UNDETERMINED => 1.23,
167 | ],
168 | ],
169 | "title" => [
170 | "type" => "string",
171 | "value" => [
172 | "en" => "nothing",
173 | "es" => "nada",
174 | CDFObject::LANGUAGE_UNDETERMINED => "niente",
175 | ],
176 | ],
177 | ],
178 | ];
179 | }
180 |
181 | }
182 |
--------------------------------------------------------------------------------
/src/ContentHubClientCommonTrait.php:
--------------------------------------------------------------------------------
1 | = 7.
10 | if (defined('\GuzzleHttp\ClientInterface::MAJOR_VERSION')) {
11 | /**
12 | * Common client trait for guzzle 7 and above.
13 | */
14 | trait ContentHubClientCommonTrait {
15 |
16 | /**
17 | * The last call's response object.
18 | *
19 | * @var \Psr\Http\Message\ResponseInterface
20 | */
21 | private $response;
22 |
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function request(string $method, $uri, array $options = []): ResponseInterface {
27 | try {
28 | $response = $this->httpClient->request($method, $uri, $options);
29 | }
30 | catch (\Exception $e) {
31 | $response = $this->getExceptionResponse($method, $uri, $e);
32 | }
33 | $this->response = $response;
34 | return $response;
35 | }
36 |
37 | /**
38 | * {@inheritdoc}
39 | */
40 | public function requestAsync(string $method, $uri, array $options = []): PromiseInterface {
41 | try {
42 | return $this->httpClient->requestAsync($method, $uri, $options);
43 | }
44 | catch (\Exception $e) {
45 | return $this->getExceptionResponse($method, $uri, $e);
46 | }
47 | }
48 |
49 | /**
50 | * {@inheritdoc}
51 | */
52 | public function send(RequestInterface $request, array $options = []): ResponseInterface {
53 | try {
54 | return $this->httpClient->send($request, $options);
55 | }
56 | catch (\Exception $e) {
57 | return $this->getExceptionResponse($request->getMethod(), $request->getUri()->getPath(), $e);
58 | }
59 | }
60 |
61 | /**
62 | * {@inheritdoc}
63 | */
64 | public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface {
65 | try {
66 | return $this->httpClient->sendAsync($request, $options);
67 | }
68 | catch (\Exception $e) {
69 | return $this->getExceptionResponse($request->getMethod(), $request->getUri()->getPath(), $e);
70 | }
71 | }
72 |
73 | /**
74 | * Get a client configuration option.
75 | *
76 | * @param string|null $option
77 | * The config option to retrieve.
78 | *
79 | * @return mixed
80 | * The client configurations.
81 | */
82 | public function getConfig(?string $option = NULL) {
83 | return $option === NULL
84 | ? $this->config
85 | : ($this->config[$option] ?? NULL);
86 | }
87 |
88 | /**
89 | * Returns the response object from the last call.
90 | *
91 | * In case further examination needed e.g. status code or error message.
92 | *
93 | * @return \Psr\Http\Message\ResponseInterface
94 | * The response object.
95 | */
96 | public function getResponse(): ResponseInterface {
97 | return $this->response;
98 | }
99 |
100 | }
101 | }
102 | else {
103 | /**
104 | * Common client trait for guzzle 6.
105 | */
106 | trait ContentHubClientCommonTrait {
107 |
108 | /**
109 | * The last call's response object.
110 | *
111 | * @var \Psr\Http\Message\ResponseInterface
112 | */
113 | private $response;
114 |
115 | /**
116 | * {@inheritdoc}
117 | */
118 | public function request($method, $uri, array $options = []) {
119 | try {
120 | $response = $this->httpClient->request($method, $uri, $options);
121 | }
122 | catch (\Exception $e) {
123 | $response = $this->getExceptionResponse($method, $uri, $e);
124 | }
125 | $this->response = $response;
126 | return $response;
127 | }
128 |
129 | /**
130 | * Returns the response object from the last call.
131 | *
132 | * In case further examination needed e.g. status code or error message.
133 | *
134 | * @return \Psr\Http\Message\ResponseInterface
135 | * The response object.
136 | */
137 | public function getResponse(): ResponseInterface {
138 | return $this->response;
139 | }
140 |
141 | /**
142 | * {@inheritdoc}
143 | */
144 | public function requestAsync($method, $uri, array $options = []) {
145 | try {
146 | return $this->httpClient->requestAsync($method, $uri, $options);
147 | }
148 | catch (\Exception $e) {
149 | return $this->getExceptionResponse($method, $uri, $e);
150 | }
151 | }
152 |
153 | /**
154 | * {@inheritdoc}
155 | */
156 | public function send(RequestInterface $request, array $options = []) {
157 | try {
158 | return $this->httpClient->send($request, $options);
159 | }
160 | catch (\Exception $e) {
161 | return $this->getExceptionResponse($request->getMethod(), $request->getUri()->getPath(), $e);
162 | }
163 | }
164 |
165 | /**
166 | * {@inheritdoc}
167 | */
168 | public function sendAsync(RequestInterface $request, array $options = []) {
169 | try {
170 | return $this->httpClient->sendAsync($request, $options);
171 | }
172 | catch (\Exception $e) {
173 | return $this->getExceptionResponse($request->getMethod(), $request->getUri()->getPath(), $e);
174 | }
175 | }
176 |
177 | /**
178 | * Get a client configuration option.
179 | *
180 | * @param string|null $option
181 | * The config option to retrieve.
182 | *
183 | * @return mixed
184 | * The client configurations.
185 | */
186 | public function getConfig($option = NULL) {
187 | return $option === NULL
188 | ? $this->config
189 | : ($this->config[$option] ?? NULL);
190 | }
191 |
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/src/SearchCriteria/SearchCriteria.php:
--------------------------------------------------------------------------------
1 | searchTerm = $searchTerm;
149 | $this->entityType = $entityType;
150 | $this->bundle = $bundle;
151 | $this->tags = $tags;
152 | $this->label = $label;
153 | $this->startDate = $startDate;
154 | $this->endDate = $endDate;
155 | $this->from = $from;
156 | $this->size = $size;
157 | $this->sorting = $sorting;
158 | $this->version = $version;
159 | $this->languages = $languages;
160 | }
161 |
162 | /**
163 | * {@inheritDoc}
164 | *
165 | * @return array
166 | * The serialized array.
167 | */
168 | public function jsonSerialize(): array {
169 | return [
170 | 'search_term' => $this->getSearchTerm(),
171 | 'type' => $this->getEntityType(),
172 | 'bundle' => $this->getBundle(),
173 | 'tags' => $this->getTags(),
174 | 'label' => $this->getLabel(),
175 | 'start_date' => $this->getStartDate(),
176 | 'end_date' => $this->getEndDate(),
177 | 'from' => $this->getFrom(),
178 | 'size' => $this->getSize(),
179 | 'sorting' => $this->getSorting(),
180 | 'version' => $this->getVersion(),
181 | 'languages' => $this->getLanguages(),
182 | ];
183 | }
184 |
185 | /**
186 | * Search term getter.
187 | *
188 | * @return string
189 | * Search term.
190 | */
191 | public function getSearchTerm(): string {
192 | return $this->searchTerm;
193 | }
194 |
195 | /**
196 | * Entity types getter.
197 | *
198 | * @return array
199 | * Entity types list.
200 | */
201 | public function getEntityType(): array {
202 | return $this->entityType;
203 | }
204 |
205 | /**
206 | * Bundle getter.
207 | *
208 | * @return array
209 | * Bundles list.
210 | */
211 | public function getBundle(): array {
212 | return $this->bundle;
213 | }
214 |
215 | /**
216 | * Tags getter.
217 | *
218 | * @return array
219 | * Tags list.
220 | */
221 | public function getTags(): array {
222 | return $this->tags;
223 | }
224 |
225 | /**
226 | * Label getter.
227 | *
228 | * @return string
229 | * Label.
230 | */
231 | public function getLabel(): string {
232 | return $this->label;
233 | }
234 |
235 | /**
236 | * Start date getter.
237 | *
238 | * @return \DateTimeInterface|null
239 | * Search start date.
240 | */
241 | public function getStartDate(): ?\DateTimeInterface {
242 | return $this->startDate;
243 | }
244 |
245 | /**
246 | * End date getter.
247 | *
248 | * @return \DateTimeInterface|null
249 | * Search end date.
250 | */
251 | public function getEndDate(): ?\DateTimeInterface {
252 | return $this->endDate;
253 | }
254 |
255 | /**
256 | * Returns number of items that should be skipped before selection.
257 | *
258 | * @return int
259 | * A number of items that should be skipped before selection.
260 | */
261 | public function getFrom(): int {
262 | return $this->from;
263 | }
264 |
265 | /**
266 | * Returns how many items should be selected.
267 | *
268 | * @return int
269 | * Number of items that should be selected.
270 | */
271 | public function getSize(): int {
272 | return $this->size;
273 | }
274 |
275 | /**
276 | * Sorting getter.
277 | *
278 | * @return string
279 | * Sorting value.
280 | */
281 | public function getSorting(): string {
282 | return $this->sorting;
283 | }
284 |
285 | /**
286 | * Version getter.
287 | *
288 | * @return string
289 | * Version string.
290 | */
291 | public function getVersion(): string {
292 | return $this->version;
293 | }
294 |
295 | /**
296 | * Languages getter.
297 | *
298 | * @return array
299 | * Languages list.
300 | */
301 | public function getLanguages(): array {
302 | return $this->languages;
303 | }
304 |
305 | /**
306 | * Languages setter.
307 | *
308 | * @param array $languages
309 | * Languages list.
310 | */
311 | public function setLanguages(array $languages): void {
312 | $this->languages = $languages;
313 | }
314 |
315 | }
316 |
--------------------------------------------------------------------------------
/src/CDF/CDFObject.php:
--------------------------------------------------------------------------------
1 | type = $type;
97 | $this->uuid = $uuid;
98 | $this->created = $created;
99 | $this->modified = $modified;
100 | $this->origin = $origin;
101 | $this->setMetadata($metadata);
102 | }
103 |
104 | /**
105 | * Static Factory method to allow CDFObject to interpret their own data.
106 | *
107 | * @param array $data
108 | * Initial data.
109 | *
110 | * @return \Acquia\ContentHubClient\CDF\CDFObject
111 | * CDFObject.
112 | *
113 | * @throws \ReflectionException
114 | */
115 | public static function fromArray(array $data) {
116 | $object = new static($data['type'], $data['uuid'], $data['created'], $data['modified'], $data['origin'], $data['metadata']);
117 | foreach ($data['attributes'] as $attribute_name => $values) {
118 | if (!$attribute = $object->getAttribute($attribute_name)) {
119 | $class = $object->getMetadata()['attributes'][$attribute_name]['class'] ?? 'non-existing-class';
120 |
121 | if (class_exists($class)) {
122 | $object->addAttribute($attribute_name, $values['type'], NULL, self::LANGUAGE_UNDETERMINED, $class);
123 | }
124 | else {
125 | $object->addAttribute($attribute_name, $values['type'], NULL);
126 | }
127 |
128 | $attribute = $object->getAttribute($attribute_name);
129 | }
130 | $value_property = (new \ReflectionClass($attribute))->getProperty('value');
131 | $value_property->setAccessible(TRUE);
132 | $value_property->setValue($attribute, $values['value']);
133 | }
134 | return $object;
135 | }
136 |
137 | /**
138 | * Static Factory method to format data from JSON into the CDFObject.
139 | *
140 | * @param string $json
141 | * Data in JSON format.
142 | *
143 | * @return \Acquia\ContentHubClient\CDF\CDFObject
144 | * CDFObject.
145 | *
146 | * @throws \ReflectionException
147 | */
148 | public static function fromJson(string $json) {
149 | return self::fromArray(json_decode($json, TRUE));
150 | }
151 |
152 | /**
153 | * {@inheritdoc}
154 | */
155 | public function getType() {
156 | return $this->type;
157 | }
158 |
159 | /**
160 | * {@inheritdoc}
161 | */
162 | public function getUuid() {
163 | return $this->uuid;
164 | }
165 |
166 | /**
167 | * {@inheritdoc}
168 | */
169 | public function getCreated() {
170 | return $this->created;
171 | }
172 |
173 | /**
174 | * {@inheritdoc}
175 | */
176 | public function getModified() {
177 | return $this->modified;
178 | }
179 |
180 | /**
181 | * {@inheritdoc}
182 | */
183 | public function getOrigin() {
184 | return $this->origin;
185 | }
186 |
187 | /**
188 | * {@inheritdoc}
189 | */
190 | public function getMetadata() {
191 | return $this->metadata;
192 | }
193 |
194 | /**
195 | * {@inheritdoc}
196 | */
197 | public function setMetadata(array $metadata) {
198 | $this->metadata = $metadata;
199 | }
200 |
201 | /**
202 | * {@inheritdoc}
203 | */
204 | public function getModuleDependencies() {
205 | return !empty($this->metadata['dependencies']['module']) ? $this->metadata['dependencies']['module'] : [];
206 | }
207 |
208 | /**
209 | * {@inheritdoc}
210 | */
211 | public function getDependencies() {
212 | return !empty($this->metadata['dependencies']['entity']) ? $this->metadata['dependencies']['entity'] : [];
213 | }
214 |
215 | /**
216 | * {@inheritdoc}
217 | */
218 | public function hasProcessedDependencies() {
219 | return $this->processed;
220 | }
221 |
222 | /**
223 | * {@inheritdoc}
224 | */
225 | public function markProcessedDependencies() {
226 | $this->processed = TRUE;
227 | }
228 |
229 | /**
230 | * {@inheritdoc}
231 | */
232 | public function getAttributes() {
233 | return $this->attributes;
234 | }
235 |
236 | /**
237 | * {@inheritdoc}
238 | *
239 | * @return null|\Acquia\ContentHubClient\CDFAttribute
240 | * Attribute object.
241 | */
242 | public function getAttribute($id): ?CDFAttribute {
243 | if (!empty($this->attributes[$id])) {
244 | return $this->attributes[$id];
245 | }
246 | return NULL;
247 | }
248 |
249 | /**
250 | * {@inheritdoc}
251 | */
252 | public function addAttribute(
253 | $id,
254 | $type,
255 | $value = NULL,
256 | $language = self::LANGUAGE_UNDETERMINED,
257 | $className = CDFAttribute::class
258 | ) {
259 | if ($className !== CDFAttribute::class && !is_subclass_of($className, CDFAttribute::class)) {
260 | throw new \Exception(sprintf("The %s class must be a subclass of \Acquia\ContentHubClient\CDFAttribute", $className));
261 | }
262 | $attribute = new $className($id, $type, $value, $language);
263 | $this->attributes[$attribute->getId()] = $attribute;
264 | // Keep track of the class used for this attribute.
265 | if ($className !== CDFAttribute::class) {
266 | $this->metadata['attributes'][$attribute->getId()]['class'] = $className;
267 | }
268 | else {
269 | unset($this->metadata['attributes'][$attribute->getId()]);
270 | }
271 | }
272 |
273 | /**
274 | * {@inheritdoc}
275 | */
276 | public function toArray() {
277 | $output = [
278 | 'uuid' => $this->getUuid(),
279 | 'type' => $this->getType(),
280 | 'created' => $this->getCreated(),
281 | 'modified' => $this->getModified(),
282 | 'origin' => $this->getOrigin(),
283 | ];
284 | if ($attributes = $this->getAttributes()) {
285 | foreach ($attributes as $attribute) {
286 | $output['attributes'][$attribute->getId()] = $attribute->toArray();
287 | }
288 | }
289 | if ($metadata = $this->getMetadata()) {
290 | $output['metadata'] = $metadata;
291 | }
292 |
293 | return $output;
294 | }
295 |
296 | }
297 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Acquia Content Hub Client for PHP
2 |
3 | [](https://travis-ci.org/acquia/content-hub-php)
4 |
5 | A PHP Client library to consume the Acquia Content Hub API.
6 |
7 | ## Version Information
8 |
9 | * `0.6.x` branch: Uses guzzle version `~5.0`. Drupal 7 [content hub module](https://docs.acquia.com/content-hub) depends upon builds against this branch.
10 | * `master` branch: Uses guzzle version `~6.0`. Drupal 8 content hub work, that is in progress at the moment, depends upon builds against this branch.
11 |
12 | ## Installation
13 |
14 | Install the latest version with [Composer](https://getcomposer.org/):
15 |
16 | ```bash
17 | $ composer require acquia/content-hub-php
18 | ```
19 |
20 | ## Usage
21 |
22 | #### Register the application
23 |
24 | Applications must register themselves with Content Hub so that they are assigned
25 | a unique identifier. The identifier is required by most API endpoints and is
26 | used as the "origin" of entities that are created by the application and
27 | published to the hub.
28 |
29 | ```php
30 | 1.3, the api key is passed via the HMAC middleware.
44 | $middleware = new MiddlewareHmacV1($apiKey, $secretKey, 'V1');
45 | $client = new ContentHub('', $middleware, ['base_url' => $url]);
46 |
47 | // For versions < 1.3, use the following client callback.
48 | $client = new ContentHub($apiKey, $secretKey, '', ['base_url' => $url]);
49 |
50 | // Register the application (or client site) with Content Hub. The parameter
51 | // passed to this method is the human-readable name of the application.
52 | $clientSite = $client->register('myclientsite');
53 |
54 | // Stores the application's unique identifier that is assigned by Content Hub.
55 | $clientId = $clientSite['uuid'];
56 |
57 | ```
58 |
59 | #### Add a webhook receiver endpoint
60 |
61 | Content Hub sends push notifications and status messages for asynchronous
62 | operations via webhooks. Even if your application doesn't require near-real-time
63 | content updates, you should implement a webhook receiver endpoint so that you
64 | have visibility into what is happening during asynchronous operations.
65 |
66 | ```php
67 | addWebhook('http://example.com/content-hub/webhooks');
71 |
72 | // Deleting the webhook receiver endpoint so that the application will no longer
73 | // receive webhooks.
74 | $client->deleteWebhook($webhook['uuid']);
75 |
76 | ```
77 |
78 | #### Creating entities
79 |
80 | ```php
81 | $url]);
92 |
93 | // The unique identifier of the entity, usually a randomly generated UUID.
94 | // See https://github.com/ramsey/uuid to simplify UUID generation in PHP.
95 | $uuid = '00000000-0000-0000-0000-000000000000'
96 |
97 | // Build the entity, add required metadata
98 | $entity = new Entity();
99 | $entity->setUuid($uuid);
100 | $entity->setType('product');
101 | $entity->setOrigin($clientId);
102 | $entity->setCreated('2014-12-21T20:12:11+00:00Z');
103 | $entity->setModified('2014-12-21T20:12:11+00:00Z');
104 |
105 | // Add attributes
106 | $attribute = new Attribute(Attribute::TYPE_STRING);
107 | $attribute->setValue('nothing', 'en');
108 | $attribute->setValue('nada', 'es');
109 | $attribute->setValue('nothing');
110 | $entity->setAttribute('name', $attribute);
111 |
112 | $attribute = new Attribute(Attribute::TYPE_INTEGER);
113 | $attribute->setValue(4);
114 | $entity->setAttribute('age', $attribute);
115 |
116 | // Add references to binary assets, e.g. images.
117 | $attribute = new Attribute(Attribute::TYPE_STRING);
118 | $attribute->setValue('[asset-1]');
119 | $entity->setAttribute('image', $attribute);
120 |
121 | $asset = new Asset();
122 | $asset->setUrl('http://placehold.it/100');
123 | $asset->setReplaceToken('[asset-1]');
124 | $entity->addAsset($asset);
125 |
126 | // Create an entity container, add the entity to it.
127 | $entities = new Entities();
128 | $entities->addEntity($entity);
129 |
130 | // Render the entities in Common Data Format (CDF). This should be the payload
131 | // returned by requests to $resourceUrl (defined below).
132 | $cdf = $entities->json();
133 |
134 | // Queue the entity to be added to Content Hub. An important concept in Content
135 | // Hub is that write operations are asynchronous, meaning that the actions are
136 | // not performed right away. In this example, a URL is passed to Content Hub
137 | // which is expected to render the entities that you want to add to the hub in
138 | // CDF. Content Hub receives the request and immediately returns a 202 which
139 | // signifies that the request was received. In the background, Content Hub then
140 | // makes a request to the URL, reads the CDF, and adds the entities. Success and
141 | // error messages are sent via webhooks, so it is important to implement a
142 | // webhook receiver endpoint so that you know what is going on.
143 | $resourceUrl = 'http://example.com/path/to/cdf';
144 | $client->createEntities($resourceUrl);
145 |
146 | ```
147 |
148 | #### Reading entities
149 |
150 | ```php
151 | readEntity($uuid);
155 |
156 | // Get the "name" attribute in English, then Spanish.
157 | $name = $entity->getAttribute('name')->getValue('en');
158 | $nombre = $entity->getAttribute('name')->getValue('es');
159 |
160 | // Get the URL of the image attribute by dereferencing the token.
161 | $token = $entity->getAttribute('image')->getValue();
162 | $url = $entity->getAsset($token)->getUrl();
163 |
164 | ```
165 |
166 | #### Updating entities
167 |
168 | ```php
169 | setValue(5);
174 | $entity->setAttribute('age', $attribute);
175 |
176 | // Updating entities is also an asynchronous operation, so it may take a couple
177 | // of seconds for the changes to be reflected in the hub.
178 | $client->updateEntity($resourceUrl, $uuid);
179 |
180 | ```
181 |
182 | #### Deleting entities
183 |
184 | ```php
185 | deleteEntity($uuid);
190 |
191 | ```
192 |
193 | #### Running Tests
194 |
195 | To better facilitate running tests, this library is now equipped with a Makefile with the following targets:
196 | (running `make help` also shows this information)
197 | - install: To install the dependencies
198 | - example: make install
199 | - method_test file=path/to/test/file: To run a specific test
200 | - example: make method_test method=testFromJSONStringCreation file=test/CDFObjectTest.php
201 | - file_test file=path/to/test/file: To run a specific test
202 | - example: make file_test file=test/CDFObjectTest.php
203 | - dir_tests dir=path/to/test-directory: To run all the tests inside a directory
204 | - example: make dir_tests test
205 | - all_tests: To run all Unit Tests
206 | - example: make all_tests
207 | - coverage: To create test coverage for the Unit Tests
208 | - example: make coverage
209 | - infection: To run infection on the existing tests
210 | - example: make infection
211 |
212 |
--------------------------------------------------------------------------------
/test/CDF/CDFObjectTest.php:
--------------------------------------------------------------------------------
1 | 'some-type',
24 | 'uuid' => 'some-uuid',
25 | 'created' => 'some-creation-date',
26 | 'modified' => 'some-modification-date',
27 | 'origin' => 'some-origin',
28 | 'attributes' => [
29 | 'name1' => [
30 | 'type' => 'integer',
31 | 'value' => 123,
32 | ],
33 | 'name2' => [
34 | 'type' => 'string',
35 | 'value' => 'some-attribute-value',
36 | ],
37 | ],
38 | 'metadata' => [
39 | 'webhook-1' => 'w1-uuid',
40 | 'webhook-2' => 'w2-uuid',
41 | 'attributes' => [
42 | 'name2' => [
43 | 'class' => CDFAttributeChild::class,
44 | ],
45 | ],
46 | ],
47 | ];
48 |
49 | /**
50 | * CDFObject instance.
51 | *
52 | * @var \Acquia\ContentHubClient\CDF\CDFObject
53 | */
54 | private $cdfObject;
55 |
56 | /**
57 | * {@inheritDoc}
58 | */
59 | public function setUp(): void {
60 | parent::setUp();
61 |
62 | $this->cdfObject = new CDFObject(
63 | self::SAMPLE_CDF_OBJECT_PARAMS['type'],
64 | self::SAMPLE_CDF_OBJECT_PARAMS['uuid'],
65 | self::SAMPLE_CDF_OBJECT_PARAMS['created'],
66 | self::SAMPLE_CDF_OBJECT_PARAMS['modified'],
67 | self::SAMPLE_CDF_OBJECT_PARAMS['origin'],
68 | self::SAMPLE_CDF_OBJECT_PARAMS['metadata']
69 | );
70 | }
71 |
72 | /**
73 | * {@inheritDoc}
74 | */
75 | public function tearDown(): void {
76 | parent::tearDown();
77 | unset($this->cdfObject);
78 | }
79 |
80 | /**
81 | * @covers \Acquia\ContentHubClient\CDF\CDFObject::toArray
82 | */
83 | public function testToArray(): void {
84 | $this->cdfObject->addAttribute('id', CDFAttribute::TYPE_ARRAY_INTEGER, 1,
85 | CDFObject::LANGUAGE_UNDETERMINED, CDFAttribute::class);
86 | $base_array = self::SAMPLE_CDF_OBJECT_PARAMS;
87 | $base_array['attributes'] = $this->attributesToArray($this->cdfObject->getAttributes());
88 |
89 | $this->assertEquals($this->cdfObject->toArray(), $base_array);
90 | }
91 |
92 | /**
93 | * @covers \Acquia\ContentHubClient\CDF\CDFObject::getAttributes
94 | */
95 | public function testFromArrayCreation(): void {
96 | $cdf_object = CDFObject::fromArray(self::SAMPLE_CDF_OBJECT_PARAMS);
97 |
98 | $attributes = $cdf_object->getAttributes();
99 |
100 | $this->assertInstanceOf(CDFAttribute::class, $attributes['name1']);
101 | $this->assertInstanceOf(CDFAttributeChild::class, $attributes['name2']);
102 | }
103 |
104 | /**
105 | * @covers \Acquia\ContentHubClient\CDF\CDFObject::fromJson
106 | */
107 | public function testFromJSONStringCreation(): void { // phpcs:ignore
108 | $cdf_object = CDFObject::fromJson(json_encode(self::SAMPLE_CDF_OBJECT_PARAMS));
109 |
110 | $this->assertEquals(
111 | self::SAMPLE_CDF_OBJECT_PARAMS['attributes'],
112 | $this->attributesToArray($cdf_object->getAttributes())
113 | );
114 | }
115 |
116 | /**
117 | * @covers \Acquia\ContentHubClient\CDF\CDFObject::getAttribute
118 | */
119 | public function testGetAttributeReturnsNullIfNoAttributeIsPresent(): void {
120 | $this->assertNull($this->cdfObject->getAttribute('some-id'));
121 | }
122 |
123 | /**
124 | * @covers \Acquia\ContentHubClient\CDF\CDFObject::getModuleDependencies
125 | */
126 | public function testGetModuleDependenciesReturnsEmptyArrayWhenEmpty(): void {
127 | $this->assertEquals($this->cdfObject->getModuleDependencies(), []);
128 | }
129 |
130 | /**
131 | * @covers \Acquia\ContentHubClient\CDF\CDFObject::getModuleDependencies
132 | */
133 | public function testGetModuleDependenciesReturnsNoEmptyArrayWhenNonEmpty(): void {
134 | $some_value = 'some-value';
135 | $this->cdfObject->setMetadata([
136 | 'dependencies' => [
137 | 'module' => $some_value,
138 | ],
139 | ]);
140 |
141 | $this->assertEquals($this->cdfObject->getModuleDependencies(), $some_value);
142 | }
143 |
144 | /**
145 | * @covers \Acquia\ContentHubClient\CDF\CDFObject::getDependencies
146 | */
147 | public function testGetDependenciesReturnsEmptyArrayWhenEmpty(): void {
148 | $this->assertEquals($this->cdfObject->getDependencies(), []);
149 | }
150 |
151 | /**
152 | * @covers \Acquia\ContentHubClient\CDF\CDFObject::getDependencies
153 | */
154 | public function testGetDependenciesReturnsNoEmptyArrayWhenNonEmpty(): void {
155 | $some_value = 'some-value';
156 | $this->cdfObject->setMetadata([
157 | 'dependencies' => [
158 | 'entity' => $some_value,
159 | ],
160 | ]);
161 |
162 | $this->assertEquals($this->cdfObject->getDependencies(), $some_value);
163 | }
164 |
165 | /**
166 | * @covers \Acquia\ContentHubClient\CDF\CDFObject::hasProcessedDependencies
167 | */
168 | public function testProcessedDependencies(): void {
169 | $this->assertFalse($this->cdfObject->hasProcessedDependencies());
170 | $this->cdfObject->markProcessedDependencies();
171 | $this->assertTrue($this->cdfObject->hasProcessedDependencies());
172 | }
173 |
174 | /**
175 | * @covers \Acquia\ContentHubClient\CDF\CDFObject::addAttribute
176 | */
177 | public function testAddIncorrectAttributeThrowsException(): void {
178 | $this->expectException(\Exception::class);
179 | $this->cdfObject->addAttribute('dummy_attribute_id', CDFAttribute::TYPE_ARRAY_BOOLEAN, [], CDFObject::LANGUAGE_UNDETERMINED, 'DummyClass');
180 | }
181 |
182 | /**
183 | * @covers \Acquia\ContentHubClient\CDF\CDFObject::addAttribute
184 | *
185 | * @dataProvider attributeDataProvider
186 | *
187 | * @param mixed $value
188 | * Test data.
189 | *
190 | * @throws \Exception
191 | */
192 | public function testAddAttributeAltersMetadataWithCDFAttributeSubclasses($value): void { // phpcs:ignore
193 | $attribute_id = 'attribute_id_1';
194 | $cdf_attribute_child_class = CDFAttributeChild::class;
195 |
196 | $this->cdfObject->addAttribute($attribute_id, CDFAttribute::TYPE_ARRAY_INTEGER, $value, CDFObject::LANGUAGE_UNDETERMINED, $cdf_attribute_child_class);
197 |
198 | $this->assertEquals(get_class($this->cdfObject->getAttribute($attribute_id)), $cdf_attribute_child_class);
199 | $this->assertTrue(isset($this->cdfObject->getMetadata()['attributes'][$attribute_id]));
200 | $this->assertEquals($this->cdfObject->getMetadata()['attributes'][$attribute_id]['class'], $cdf_attribute_child_class);
201 | }
202 |
203 | /**
204 | * @covers \Acquia\ContentHubClient\CDF\CDFObject::addAttribute
205 | *
206 | * @dataProvider attributeDataProvider
207 | *
208 | * @param mixed $value
209 | * Test data.
210 | *
211 | * @throws \Exception
212 | */
213 | public function testAddAttributeUnsetsAttributeFromMetadataWithCDFAttributeClass($value): void { // phpcs:ignore
214 | $attribute_id = 'attribute_id_1';
215 | $this->cdfObject->addAttribute($attribute_id, CDFAttribute::TYPE_ARRAY_INTEGER, $value, CDFObject::LANGUAGE_UNDETERMINED, CDFAttribute::class);
216 |
217 | $this->assertFalse(isset($this->cdfObject->getMetadata()['attributes'][$attribute_id]));
218 | }
219 |
220 | /**
221 | * Data provider.
222 | *
223 | * @return array
224 | * Test data.
225 | */
226 | public function attributeDataProvider(): array {
227 | return [
228 | [
229 | 'value' => [
230 | 'en' => [
231 | 6.66,
232 | 3.23,
233 | ],
234 | 'hu' => [
235 | 4.66,
236 | 4.23,
237 | ],
238 | CDFObject::LANGUAGE_UNDETERMINED => [
239 | 1.22,
240 | 1.11,
241 | ],
242 | ],
243 | ],
244 | ];
245 | }
246 |
247 | /**
248 | * Converts attributes to array.
249 | *
250 | * @param array $attributes
251 | * Attributes array.
252 | *
253 | * @return array
254 | * Converted data.
255 | */
256 | private function attributesToArray(array $attributes) {
257 | return array_map(static function (CDFAttribute $attribute) {
258 | return $attribute->toArray();
259 | }, $attributes);
260 | }
261 |
262 | }
263 |
--------------------------------------------------------------------------------
/src/ContentHubClientTrait.php:
--------------------------------------------------------------------------------
1 | logger)) {
44 | return;
45 | }
46 |
47 | if (!$config['handler'] instanceof HandlerStack) {
48 | return;
49 | }
50 |
51 | $config['handler']->push(new RequestResponseHandler($this->logger));
52 | }
53 |
54 | /**
55 | * Removes all leading and trailing slashes.
56 | *
57 | * Strip all leading and trailing slashes from all components of the given
58 | * array.
59 | *
60 | * @param string[] $components
61 | * Array of strings.
62 | *
63 | * @return string[]
64 | * Processed array.
65 | */
66 | protected static function removeAllLeadingAndTrailingSlashes(array $components): array {
67 | return array_map(function ($component) {
68 | return trim($component, '/');
69 | }, $components);
70 | }
71 |
72 | /**
73 | * Glue all elements of an array together.
74 | *
75 | * @param array $parts
76 | * Parts array.
77 | * @param string $glue
78 | * Glue symbol.
79 | *
80 | * @return string
81 | * Processed string.
82 | */
83 | protected static function gluePartsTogether(array $parts, string $glue): string {
84 | return implode($glue, self::removeAllLeadingAndTrailingSlashes($parts));
85 | }
86 |
87 | /**
88 | * Make a base url out of components and add a trailing slash to it.
89 | *
90 | * @param string[] $base_url_components
91 | * Base URL components.
92 | *
93 | * @return string
94 | * Processed string.
95 | */
96 | protected static function makeBaseURL(...$base_url_components): string { // phpcs:ignore
97 | return self::makePath(...$base_url_components) . '/';
98 | }
99 |
100 | /**
101 | * Make path out of its individual components.
102 | *
103 | * @param string[] $path_components
104 | * Path components.
105 | *
106 | * @return string
107 | * Processed string.
108 | */
109 | protected static function makePath(...$path_components): string { // phpcs:ignore
110 | return self::gluePartsTogether($path_components, '/');
111 | }
112 |
113 | /**
114 | * Returns error response.
115 | *
116 | * @param int $code
117 | * Status code.
118 | * @param string $reason
119 | * Reason.
120 | * @param string|null $request_id
121 | * The request id from the ContentHub service if available.
122 | *
123 | * @return \Psr\Http\Message\ResponseInterface
124 | * Response.
125 | */
126 | protected function getErrorResponse(int $code, string $reason, ?string $request_id = NULL): ResponseInterface {
127 | if ($code < 100 || $code >= 600) {
128 | $code = 500;
129 | }
130 | $body = [
131 | 'request_id' => $request_id,
132 | 'error' => [
133 | 'code' => $code,
134 | 'message' => $reason,
135 | ],
136 | ];
137 | return new Response($code, [], json_encode($body), '1.1', $reason);
138 | }
139 |
140 | /**
141 | * Obtains the appropriate exception Response, logging error messages according to API call.
142 | *
143 | * @param string $method
144 | * The Request to Plexus, as defined in the content-hub-php library.
145 | * @param string $api_call
146 | * The api endpoint.
147 | * @param \Exception $exception
148 | * The Exception object.
149 | *
150 | * @return \Psr\Http\Message\ResponseInterface
151 | * The response after raising an exception.
152 | *
153 | * @codeCoverageIgnore
154 | */
155 | protected function getExceptionResponse(string $method, string $api_call, \Exception $exception): ResponseInterface {
156 | // If we reach here it is because there was an exception raised in the API call.
157 | $response = $exception->getResponse();
158 | if (!$response) {
159 | $response = $this->getErrorResponse($exception->getCode(), $exception->getMessage());
160 | }
161 | $response_body = json_decode($response->getBody(), TRUE);
162 | $error_code = $response_body['error']['code'] ?? '';
163 | $error_message = $response_body['error']['message'] ?? '';
164 |
165 | // Customize Error messages according to API Call.
166 | switch ($api_call) {
167 | case'settings/webhooks':
168 | $log_level = LogLevel::WARNING;
169 | break;
170 |
171 | case (preg_match('/filters\?name=*/', $api_call) ? TRUE : FALSE):
172 | case (preg_match('/settings\/clients\/*/', $api_call) ? TRUE : FALSE):
173 | case (preg_match('/settings\/webhooks\/.*\/filters/', $api_call) ? TRUE : FALSE):
174 | $log_level = LogLevel::NOTICE;
175 | break;
176 |
177 | default:
178 | // The default log level is ERROR.
179 | $log_level = LogLevel::ERROR;
180 | break;
181 | }
182 |
183 | $reason = sprintf("Request ID: %s, Method: %s, Path: \"%s\", Status Code: %s, Reason: %s, Error Code: %s, Error Message: \"%s\". Error data: \"%s\"",
184 | $response_body['request_id'] ?? '',
185 | strtoupper($method),
186 | $api_call,
187 | $response->getStatusCode(),
188 | $response->getReasonPhrase(),
189 | $error_code,
190 | $error_message,
191 | print_r($response_body['error']['data'] ?? $response_body['error'] ?? '', TRUE)
192 | );
193 | $this->logger->log($log_level, $reason);
194 |
195 | // Return the response.
196 | return $response;
197 | }
198 |
199 | /**
200 | * Get the settings that were used to instantiate this client.
201 | *
202 | * @return \Acquia\ContentHubClient\Settings
203 | * Settings object.
204 | *
205 | * @codeCoverageIgnore
206 | */
207 | public function getSettings() {
208 | return $this->settings;
209 | }
210 |
211 | /**
212 | * Gets a Json Response from a request.
213 | *
214 | * @param \Psr\Http\Message\ResponseInterface $response
215 | * Response.
216 | *
217 | * @return mixed
218 | * Response array.
219 | *
220 | * @throws \Exception
221 | */
222 | public static function getResponseJson(ResponseInterface $response) {
223 | try {
224 | $body = (string) $response->getBody();
225 | }
226 | catch (\Exception $exception) {
227 | $message = sprintf("An exception occurred in the JSON response. Message: %s",
228 | $exception->getMessage());
229 | throw new \Exception($message);
230 | }
231 |
232 | return json_decode($body, TRUE);
233 | }
234 |
235 | /**
236 | * Pings the service to ensure that it is available.
237 | *
238 | * @return \Psr\Http\Message\ResponseInterface
239 | * Response.
240 | *
241 | * @throws \GuzzleHttp\Exception\RequestException
242 | * @throws \Exception
243 | *
244 | * @since 0.2.0
245 | */
246 | public function ping() {
247 | $makeBaseURL = self::makeBaseURL($this->getConfig()['base_url']);
248 | $client = ObjectFactory::getGuzzleClient([
249 | 'base_uri' => $makeBaseURL,
250 | ]);
251 |
252 | return $client->get('ping');
253 | }
254 |
255 | /**
256 | * Create and send an HTTP GET request.
257 | *
258 | * @param string $uri
259 | * URI object or string.
260 | * @param array $options
261 | * Request options to apply.
262 | */
263 | public function get(string $uri, array $options = []): ResponseInterface {
264 | return $this->request('GET', $uri, $options);
265 | }
266 |
267 | /**
268 | * Create and send an HTTP PUT request.
269 | *
270 | * @param string $uri
271 | * URI object or string.
272 | * @param array $options
273 | * Request options to apply.
274 | */
275 | public function put(string $uri, array $options = []): ResponseInterface {
276 | return $this->request('PUT', $uri, $options);
277 | }
278 |
279 | /**
280 | * Create and send an HTTP POST request.
281 | *
282 | * @param string $uri
283 | * URI object or string.
284 | * @param array $options
285 | * Request options to apply.
286 | */
287 | public function post(string $uri, array $options = []): ResponseInterface {
288 | return $this->request('POST', $uri, $options);
289 | }
290 |
291 | /**
292 | * Create and send an HTTP DELETE request.
293 | *
294 | * @param string $uri
295 | * URI object or string.
296 | * @param array $options
297 | * Request options to apply.
298 | */
299 | public function delete(string $uri, array $options = []): ResponseInterface {
300 | return $this->request('DELETE', $uri, $options);
301 | }
302 |
303 | /**
304 | * Sets configurations.
305 | *
306 | * @param array $config
307 | * Array of configurations.
308 | */
309 | public function setConfigs(array $config): void {
310 | $this->config = $config;
311 | }
312 |
313 | }
314 |
--------------------------------------------------------------------------------
/test/ContentHubTestBase.php:
--------------------------------------------------------------------------------
1 | [
34 | 'uuid' => '00000000-0000-0000-0000-000000000000',
35 | 'origin' => '11111111-0000-0000-0000-000000000000',
36 | 'data' => [
37 | 'uuid' => '00000000-0000-0000-0000-000000000000',
38 | "type" => "product",
39 | "created" => "2014-12-21T20:12:11+00:00Z",
40 | "modified" => "2014-12-21T20:12:11+00:00Z",
41 | "attributes" => [
42 | "title" => [
43 | "type" => "string",
44 | "value" => [
45 | "en" => "A",
46 | "hu" => "B",
47 | "und" => "C",
48 | ],
49 | ],
50 | ],
51 | "assets" => [
52 | [
53 | "url" => "http://acquia.com/sites/default/files/foo.png",
54 | "replace-token" => "[acquia-logo]",
55 | ],
56 | [
57 | "url" => "http://acquia.com/sites/default/files/bar.png",
58 | "replace-token" => "[acquia-thumb]",
59 | ],
60 | ],
61 | ],
62 | ],
63 | ];
64 | }
65 |
66 | /**
67 | * Returns test data.
68 | *
69 | * @return array
70 | * Test data.
71 | */
72 | protected function setDefinition() {
73 | return [
74 | 'children' => [
75 | 0 => '/settings',
76 | 1 => '/register',
77 | 2 => '/entities',
78 | 3 => '/ping',
79 | 4 => '/elastic',
80 | ],
81 | ];
82 | }
83 |
84 | /**
85 | * Returns list of entities.
86 | *
87 | * @return array
88 | * Test data.
89 | */
90 | protected function setListOfEntities() {
91 | return [
92 | 'success' => TRUE,
93 | 'total' => 2,
94 | 'data' => [
95 | 0 => [
96 | 'uuid' => '00000000-0000-0000-0000-000000000000',
97 | 'origin' => '11111111-1111-1111-1111-111111111111',
98 | 'modified' => '2015-06-29T12:15:36-04:00',
99 | 'type' => 'node',
100 | 'attributes' => [
101 | 'body' => [
102 | 'und' => '{"summary":"","value":"Custom table","format":"filtered_html"}',
103 | ],
104 | 'description' => NULL,
105 | 'field_tags' => [
106 | 'und' => [
107 | 0 => '88fa41e8-b959-41f1-aaa9-e9017936d8ca',
108 | 1 => '7f0931f6-2d04-4488-9eec-fbd81e604ce5',
109 | ],
110 | ],
111 | 'status' => [
112 | 'und' => 1,
113 | ],
114 | 'title' => [
115 | 'und' => 'A new custom table',
116 | ],
117 | ],
118 | ],
119 | 1 => [
120 | 'uuid' => '00000000-1111-0000-0000-000000000000',
121 | 'origin' => '11111111-1111-1111-1111-111111111111',
122 | 'modified' => '2015-07-01T14:18:29-04:00',
123 | 'type' => 'node',
124 | 'attributes' => [
125 | 'body' => [
126 | 'und' => '{"summary":"","value":"The following is a Custom bench for Boston.","format":"filtered_html"}',
127 | ],
128 | 'description' => NULL,
129 | 'field_tags' => [
130 | 'und' => [
131 | 0 => '94e38271-df71-4da6-ae3c-dce143244b65',
132 | ],
133 | ],
134 | 'status' => [
135 | 'und' => 1,
136 | ],
137 | 'title' => [
138 | 'und' => 'New Custom Bench 2',
139 | ],
140 | ],
141 | ],
142 | ],
143 | ];
144 | }
145 |
146 | /**
147 | * Returns test data.
148 | *
149 | * @return array
150 | * Test data.
151 | */
152 | public function setResponseTrue() {
153 | return [
154 | 'success' => TRUE,
155 | 'request_id' => '00000000-0000-0000-0000-000000000000',
156 | ];
157 | }
158 |
159 | /**
160 | * Returns log entry.
161 | *
162 | * @return array
163 | * Test data.
164 | */
165 | public function setHistoryLogs() {
166 | return [
167 | '_shards' => [
168 | 'failed' => 0,
169 | 'successful' => 5,
170 | 'total' => 5,
171 | ],
172 | 'hits' => [
173 | 'hits' => [
174 | 0 => [
175 | '_id' => '7257fb6e-2fba-4919-6311-656385295b2f',
176 | '_index' => '00000000-0000-4000-8000-000000000000_history_index',
177 | '_score' => 1,
178 | '_source' => [
179 | 'client' => '12340000-0000-4000-6012-000000000000',
180 | 'entity' => 'eadc61e3-b847-4310-946a-511cca7bb14b',
181 | 'id' => '7257fb6e-2fba-4919-6311-656385295b2f',
182 | 'request_id' => '71b983d5-169d-48d9-6f62-c474cbdd5454',
183 | 'status' => 'succeeded',
184 | 'subscription' => '00000000-0000-4000-8000-000000000000',
185 | 'timestamp' => '2017-03-09T13:49:23Z',
186 | 'type' => 'create',
187 | ],
188 | '_type' => 'history',
189 | ],
190 | ],
191 | 'total' => 1,
192 | ],
193 | 'timed_out' => FALSE,
194 | 'took' => 63,
195 | ];
196 | }
197 |
198 | /**
199 | * Returns mapping.
200 | *
201 | * @return array
202 | * Test data.
203 | */
204 | public function setMapping() {
205 | return [
206 | 'entity' => [
207 | 'dynamic' => 'strict',
208 | 'properties' => [
209 | 'data' => [
210 | 'dynamic' => 'strict',
211 | 'properties' => [
212 | 'assets' => [
213 | 'dynamic' => 'strict',
214 | 'properties' => [
215 | 'replace-token' => [
216 | 'type' => 'string',
217 | ],
218 | 'url' => [
219 | 'type' => 'string',
220 | ],
221 | ],
222 | ],
223 | 'attributes' => [
224 | 'dynamic' => 'true',
225 | 'properties' => [
226 | 'title' => [
227 | 'dynamic' => 'strict',
228 | 'properties' => [
229 | 'metadata' => [
230 | 'type' => 'string',
231 | ],
232 | 'type' => [
233 | 'type' => 'string',
234 | ],
235 | 'value' => [
236 | 'dynamic' => 'true',
237 | 'properties' => [
238 | 'und' => [
239 | 'type' => 'string',
240 | ],
241 | ],
242 | ],
243 | ],
244 | ],
245 | ],
246 | 'type' => 'object',
247 | ],
248 | 'created' => [
249 | 'type' => 'date',
250 | ],
251 | 'metadata' => [
252 | 'dynamic' => 'true',
253 | 'index' => 'no',
254 | 'type' => 'object',
255 | ],
256 | 'modified' => [
257 | 'type' => 'date',
258 | ],
259 | 'origin' => [
260 | 'type' => 'string',
261 | ],
262 | 'type' => [
263 | 'type' => 'string',
264 | ],
265 | 'uuid' => [
266 | 'type' => 'string',
267 | ],
268 | ],
269 | ],
270 | 'id' => [
271 | 'type' => 'string',
272 | ],
273 | 'origin' => [
274 | 'index' => 'not_analyzed',
275 | 'type' => 'string',
276 | ],
277 | 'revision' => [
278 | 'type' => 'long',
279 | ],
280 | 'subscription' => [
281 | 'type' => 'string',
282 | ],
283 | 'uuid' => [
284 | 'index' => 'not_analyzed',
285 | 'type' => 'string',
286 | ],
287 | ],
288 | ],
289 | ];
290 | }
291 |
292 | /**
293 | * @covers \Acquia\ContentHubClient\ContentHubClient::ping
294 | */
295 | public function testPing() {
296 | // Setup.
297 | $data = [
298 | 'success' => 1,
299 | ];
300 | $responses = [
301 | new Response('200', [], json_encode($data)),
302 | ];
303 | $client = $this->getClient($responses);
304 |
305 | // Ping the service.
306 | $response = $client->ping();
307 | $body = (string) $response->getBody();
308 | $this->assertEquals($data, json_decode($body, TRUE));
309 | }
310 |
311 | /**
312 | * @covers \Acquia\ContentHubClient\ContentHubClient::definition
313 | */
314 | public function testDefinition() {
315 | // Setup.
316 | $data = $this->setDefinition();
317 | $responses = [
318 | new Response('200', [], json_encode($data)),
319 | ];
320 | $client = $this->getClient($responses);
321 |
322 | // Get definition.
323 | $response = $client->definition();
324 | $this->assertEquals($data, $response);
325 | }
326 |
327 | /**
328 | * @covers \Acquia\ContentHubClient\ContentHubClient::getClientByName
329 | */
330 | public function testClientByName() {
331 | // Setup.
332 | $data = [
333 | 'name' => 'mysite',
334 | 'uuid' => '00000000-0000-0000-0000-000000000000',
335 | ];
336 | $responses = [
337 | new Response('200', [], json_encode($data)),
338 | ];
339 | $client = $this->getClient($responses);
340 |
341 | // Get client by name.
342 | $response = $client->getClientByName('mysite');
343 | $this->assertEquals($data, $response);
344 | }
345 |
346 | /**
347 | * @covers \Acquia\ContentHubClient\ContentHubClient::createEntities
348 | */
349 | public function testCreateEntity() {
350 | // Setup.
351 | $data = [
352 | 'success' => TRUE,
353 | ];
354 | $resource = 'http://acquia.com/content_hub_connector/node/00000000-0000-0000-0000-000000000000';
355 | $responses = [
356 | new Response(200, [], json_encode($data)),
357 | new Response(200, [], json_encode($data)),
358 | ];
359 | $client = $this->getClient($responses);
360 |
361 | // Create an Entity.
362 | $response = $client->createEntity($resource);
363 | $body = json_decode((string) $response->getBody(), TRUE);
364 | $this->assertEquals($data, $body);
365 | $this->assertEquals($responses[0], $response);
366 |
367 | // Create one or more entities.
368 | $response = $client->createEntities($resource);
369 | $body = json_decode((string) $response->getBody(), TRUE);
370 | $this->assertEquals($data, $body);
371 | $this->assertEquals($responses[1], $response);
372 | }
373 |
374 | /**
375 | * @covers \Acquia\ContentHubClient\ContentHubClient::getEntity
376 | */
377 | public function testReadEntity() {
378 | // Setup.
379 | $data = $this->setData();
380 | $responses = [
381 | new Response(200, [], json_encode($data)),
382 | ];
383 | $client = $this->getClient($responses);
384 |
385 | // Read an Entity.
386 | $entity = $client->readEntity('00000000-0000-0000-0000-000000000000');
387 | $this->assertEquals(6, count($entity));
388 | $this->assertEquals($data['data']['data'], (array) $entity);
389 | }
390 |
391 | /**
392 | * @covers \Acquia\ContentHubClient\ContentHubClient::get
393 | */
394 | public function testUpdateEntity() {
395 | // Setup.
396 | $data = [
397 | 'success' => TRUE,
398 | ];
399 | $resource = 'http://acquia.com/content_hub_connector/node/00000000-0000-0000-0000-000000000000';
400 | $responses = [
401 | new Response(200, [], json_encode($data)),
402 | new Response(200, [], json_encode($data)),
403 | ];
404 | $client = $this->getClient($responses);
405 |
406 | // Update an Entity.
407 | $response = $client->updateEntity($resource,
408 | '00000000-0000-0000-0000-000000000000');
409 | $this->assertEquals(json_encode($data), $response->getBody());
410 | $this->assertEquals($responses[0], $response);
411 |
412 | // Test Update Entities (one or more)
413 | $response = $client->updateEntities($resource);
414 | $this->assertEquals(json_encode($data), $response->getBody());
415 | $this->assertEquals($responses[1], $response);
416 | }
417 |
418 | /**
419 | * @covers \Acquia\ContentHubClient\ContentHubClient::deleteEntity
420 | */
421 | public function testDeleteEntity() {
422 | // Setup.
423 | $responses = [
424 | new Response(200),
425 | ];
426 | $client = $this->getClient($responses);
427 |
428 | // Delete an Entity.
429 | $response = $client->deleteEntity('00000000-0000-0000-0000-000000000000');
430 | $this->assertEquals(200, $response->getStatusCode());
431 | }
432 |
433 | /**
434 | * @covers \Acquia\ContentHubClient\ContentHubClient::listEntities
435 | */
436 | public function testListEntities() {
437 | // Setup.
438 | $data = $this->setListOfEntities();
439 | $responses = [
440 | new Response(200, [], json_encode($data)),
441 | ];
442 | $client = $this->getClient($responses);
443 |
444 | // Listing entities.
445 | $options = [
446 | 'limit' => 20,
447 | 'type' => 'node',
448 | 'origin' => '11111111-1111-1111-1111-111111111111',
449 | 'fields' => 'status,title,body,field_tags,description',
450 | 'filters' => [
451 | 'status' => 1,
452 | 'title' => 'New*',
453 | 'body' => '/Custom/',
454 | ],
455 | ];
456 | $response = $client->listEntities($options);
457 | $this->assertEquals($data, $response);
458 | }
459 |
460 | /**
461 | * @covers \Acquia\ContentHubClient\ContentHubClient::purge
462 | */
463 | public function testPurge() {
464 | // Setup.
465 | $data = $this->setResponseTrue();
466 | $responses = [
467 | new Response(200, [], json_encode($data)),
468 | ];
469 | $client = $this->getClient($responses);
470 |
471 | // Purge entities.
472 | $response = $client->purge();
473 | $this->assertTrue($response['success']);
474 | }
475 |
476 | /**
477 | * @covers \Acquia\ContentHubClient\ContentHubClient::restore
478 | */
479 | public function testRestore() {
480 | // Setup.
481 | $data = $this->setResponseTrue();
482 | $responses = [
483 | new Response(200, [], json_encode($data)),
484 | ];
485 | $client = $this->getClient($responses);
486 |
487 | // Restore entities.
488 | $response = $client->restore();
489 | $this->assertTrue($response['success']);
490 | }
491 |
492 | /**
493 | * @covers \Acquia\ContentHubClient\ContentHubClient::reindex
494 | */
495 | public function testReindex() {
496 | // Setup.
497 | $data = $this->setResponseTrue();
498 | $responses = [
499 | new Response(200, [], json_encode($data)),
500 | ];
501 | $client = $this->getClient($responses);
502 |
503 | // Reindex.
504 | $response = $client->reindex();
505 | $this->assertTrue($response['success']);
506 | }
507 |
508 | /**
509 | * @covers \Acquia\ContentHubClient\ContentHubClient::logs
510 | */
511 | public function testHistory() {
512 | // Setup.
513 | $data = $this->setHistoryLogs();
514 | $responses = [
515 | new Response(200, [], json_encode($data)),
516 | ];
517 | $client = $this->getClient($responses);
518 |
519 | // Get History.
520 | $response = $client->logs('');
521 | $this->assertEquals($data['hits']['total'], $response['hits']['total']);
522 | $this->assertEquals($data['hits']['hits'], $response['hits']['hits']);
523 | }
524 |
525 | /**
526 | * @covers \Acquia\ContentHubClient\ContentHubClient::mapping
527 | */
528 | public function testMapping() {
529 | // Setup.
530 | $data = $this->setMapping();
531 | $responses = [
532 | new Response(200, [], json_encode($data)),
533 | ];
534 | $client = $this->getClient($responses);
535 |
536 | // Purge entities.
537 | $response = $client->mapping();
538 | $this->assertEquals($data['entity'], $response['entity']);
539 | }
540 |
541 | }
542 |
--------------------------------------------------------------------------------
/test/CDFDocumentTest.php:
--------------------------------------------------------------------------------
1 | cdfDocument = new CDFDocument();
31 | }
32 |
33 | /**
34 | * {@inheritDoc}
35 | */
36 | public function tearDown(): void {
37 | parent::tearDown();
38 | unset($this->cdfDocument);
39 | }
40 |
41 | /**
42 | * @covers \Acquia\ContentHubClient\CDFDocument::hasEntities
43 | *
44 | * @dataProvider providerEntityOperations
45 | *
46 | * @param \Acquia\ContentHubClient\CDF\CDFObject $objectToAdd
47 | * CDF object.
48 | * @param \Acquia\ContentHubClient\CDF\CDFObject $notAddedObject
49 | * CDF object.
50 | */
51 | public function testHasEntities(CDFObject $objectToAdd, CDFObject $notAddedObject) {
52 | // Check hasEntities method before and after we add an Object.
53 | $this->assertEquals($this->cdfDocument->hasEntities(), FALSE);
54 | $this->cdfDocument->addCdfEntity($objectToAdd);
55 | $this->assertEquals($this->cdfDocument->hasEntities(), TRUE);
56 | }
57 |
58 | /**
59 | * @covers \Acquia\ContentHubClient\CDFDocument::getCdfEntity
60 | *
61 | * @dataProvider providerEntityOperations
62 | *
63 | * @param \Acquia\ContentHubClient\CDF\CDFObject $objectToAdd
64 | * CDF object.
65 | * @param \Acquia\ContentHubClient\CDF\CDFObject $notAddedObject
66 | * CDF object.
67 | */
68 | public function testGetEntity(CDFObject $objectToAdd, CDFObject $notAddedObject) {
69 | // Check getting added and not added Object.
70 | $this->cdfDocument->addCdfEntity($objectToAdd);
71 | $this->assertEquals($this->cdfDocument->getCdfEntity($objectToAdd->getUuid()), $objectToAdd);
72 | $this->assertEquals($this->cdfDocument->getCdfEntity($notAddedObject->getUuid()), NULL);
73 | }
74 |
75 | /**
76 | * @covers \Acquia\ContentHubClient\CDFDocument::getEntities
77 | *
78 | * @dataProvider providerEntityOperations
79 | *
80 | * @param \Acquia\ContentHubClient\CDF\CDFObject $objectOne
81 | * CDF object.
82 | * @param \Acquia\ContentHubClient\CDF\CDFObject $objectTwo
83 | * CDF object.
84 | */
85 | public function testGetEntities(CDFObject $objectOne, CDFObject $objectTwo) {
86 | // Check getting added and not added Object.
87 | $this->cdfDocument->setCdfEntities($objectOne, $objectTwo);
88 |
89 | foreach ($this->cdfDocument->getEntities() as $entity) {
90 | $this->assertInstanceOf(CDFObject::class, $entity);
91 | }
92 | }
93 |
94 | /**
95 | * @covers \Acquia\ContentHubClient\CDFDocument::addCdfEntity
96 | *
97 | * @dataProvider providerEntityOperations
98 | *
99 | * @param \Acquia\ContentHubClient\CDF\CDFObject $objectToAdd
100 | * CDF object.
101 | * @param \Acquia\ContentHubClient\CDF\CDFObject $notAddedObject
102 | * CDF object.
103 | */
104 | public function testAddEntity(CDFObject $objectToAdd, CDFObject $notAddedObject) {
105 | // Check if hasEntity will return correct values for added and not added Objects.
106 | $this->cdfDocument->addCdfEntity($objectToAdd);
107 | $this->assertEquals($this->cdfDocument->hasEntity($objectToAdd->getUuid()), TRUE);
108 | $this->assertEquals($this->cdfDocument->hasEntity($notAddedObject->getUuid()), FALSE);
109 | }
110 |
111 | /**
112 | * @covers \Acquia\ContentHubClient\CDFDocument::removeCdfEntity
113 | *
114 | * @dataProvider providerEntityOperations
115 | *
116 | * @param \Acquia\ContentHubClient\CDF\CDFObject $objectToAdd
117 | * CDF object.
118 | */
119 | public function testRemoveEntity(CDFObject $objectToAdd) {
120 | // Test removing Entity.
121 | $this->cdfDocument->addCdfEntity($objectToAdd);
122 | $this->assertEquals($this->cdfDocument->hasEntity($objectToAdd->getUuid()), TRUE);
123 | $this->cdfDocument->removeCdfEntity($objectToAdd->getUuid());
124 | $this->assertEquals($this->cdfDocument->hasEntity($objectToAdd->getUuid()), FALSE);
125 | }
126 |
127 | /**
128 | * @covers \Acquia\ContentHubClient\CDFDocument::mergeDocuments
129 | *
130 | * @dataProvider providerMergeDocuments
131 | *
132 | * @param array $setOne
133 | * Data set.
134 | * @param array $setTwo
135 | * Data set.
136 | */
137 | public function testMergeDocuments(array $setOne, array $setTwo) {
138 | $this->cdfDocument->setCdfEntities(...$setOne);
139 | $documentToMerge = new CDFDocument(...$setTwo);
140 |
141 | foreach ($setTwo as $entity) {
142 | $this->assertFalse($this->cdfDocument->hasEntity($entity->getUuid()));
143 | }
144 | $this->cdfDocument->mergeDocuments($documentToMerge);
145 | foreach ($setTwo as $entity) {
146 | $this->assertTrue($this->cdfDocument->hasEntity($entity->getUuid()));
147 | }
148 | }
149 |
150 | /**
151 | * @covers \Acquia\ContentHubClient\CDFDocument::mergeDocuments
152 | *
153 | * @dataProvider providerMergeDocuments
154 | *
155 | * @param array $setOne
156 | * Data set.
157 | * @param array $setTwo
158 | * Data set.
159 | */
160 | public function testMergeDocumentsByKeys(array $setOne, array $setTwo) {
161 | $this->cdfDocument->setCdfEntities(...$setOne);
162 | $documentToMerge = new CDFDocument(...$setTwo);
163 |
164 | $keysOne = array_keys($this->cdfDocument->getEntities());
165 | $keysTwo = array_keys($documentToMerge->getEntities());
166 |
167 | $this->assertEquals(array_diff($keysOne, $keysTwo), $keysOne);
168 |
169 | $this->cdfDocument->mergeDocuments($documentToMerge);
170 | $mergedKeys = array_keys($this->cdfDocument->getEntities());
171 | $this->assertEquals($mergedKeys, array_merge($keysOne, $keysTwo));
172 | }
173 |
174 | /**
175 | * @covers \Acquia\ContentHubClient\CDFDocument::mergeDocuments
176 | *
177 | * @dataProvider providerMergeDocumentsNoOverlap
178 | *
179 | * @param array $setOne
180 | * Data set.
181 | * @param array $setTwo
182 | * Data set.
183 | * @param \Acquia\ContentHubClient\CDF\CDFObject $elementFromSetTwo
184 | * CDF object.
185 | */
186 | public function testMergeDocumentsNoOverlap(array $setOne, array $setTwo, CDFObject $elementFromSetTwo) {
187 | $this->cdfDocument->setCdfEntities(...$setOne);
188 | $documentToMerge = new CDFDocument(...$setTwo);
189 |
190 | $this->assertFalse($this->cdfDocument->hasEntity($elementFromSetTwo->getUuid()));
191 | $this->cdfDocument->mergeDocuments($documentToMerge);
192 | $this->assertTrue($this->cdfDocument->hasEntity($elementFromSetTwo->getUuid()));
193 | }
194 |
195 | /**
196 | * @covers \Acquia\ContentHubClient\CDFDocument::mergeDocuments
197 | *
198 | * @dataProvider providerMergeDocumentsOverlap
199 | *
200 | * @param array $setOne
201 | * Data set.
202 | * @param array $setTwo
203 | * Data set.
204 | * @param \Acquia\ContentHubClient\CDF\CDFObject $overlappingElement
205 | * CDF object.
206 | */
207 | public function testMergeDocumentsOverlap(array $setOne, array $setTwo, CDFObject $overlappingElement) {
208 | $this->cdfDocument->setCdfEntities(...$setOne);
209 | $documentToMerge = new CDFDocument(...$setTwo);
210 |
211 | $this->assertTrue($this->cdfDocument->hasEntity($overlappingElement->getUuid()));
212 | $this->cdfDocument->mergeDocuments($documentToMerge);
213 | $this->assertTrue($this->cdfDocument->hasEntity($overlappingElement->getUuid()));
214 | }
215 |
216 | /**
217 | * @covers \Acquia\ContentHubClient\CDFDocument::toString
218 | *
219 | * @dataProvider providerToString
220 | *
221 | * @param array $objectsList
222 | * Objects list.
223 | * @param string $emptyObjectsJson
224 | * JSON string.
225 | * @param string $filledObjectsJson
226 | * JSON string.
227 | */
228 | public function testToString(array $objectsList, $emptyObjectsJson, $filledObjectsJson) {
229 | $this->assertJsonStringEqualsJsonString($this->cdfDocument->toString(), $emptyObjectsJson);
230 | $this->cdfDocument->setCdfEntities(...$objectsList);
231 | $this->assertJsonStringEqualsJsonString($this->cdfDocument->toString(), $filledObjectsJson);
232 | }
233 |
234 | /**
235 | * Data provider for ::testHasEntities.
236 | *
237 | * @return array
238 | * Test data.
239 | */
240 | public function providerEntityOperations() {
241 | $cdfObjectMockFirst = $this->getMockBuilder(CDFObject::class)
242 | ->disableOriginalConstructor()
243 | ->onlyMethods(['getUuid'])
244 | ->getMock();
245 | $cdfObjectMockSecond = $this->getMockBuilder(CDFObject::class)
246 | ->disableOriginalConstructor()
247 | ->onlyMethods(['getUuid'])
248 | ->getMock();
249 |
250 | $cdfObjectMockFirst->expects($this->any())
251 | ->method('getUuid')
252 | ->will($this->returnValue('11111111-0000-0000-0000-000000000000'));
253 |
254 | $cdfObjectMockSecond->expects($this->any())
255 | ->method('getUuid')
256 | ->will($this->returnValue('22222222-0000-0000-0000-000000000000'));
257 |
258 | return [
259 | [
260 | $cdfObjectMockFirst,
261 | $cdfObjectMockSecond,
262 | ],
263 | ];
264 | }
265 |
266 | /**
267 | * Data provider for ::testMergeDocuments.
268 | *
269 | * @return array
270 | * Test data.
271 | */
272 | public function providerMergeDocuments() {
273 | $cdfObjectMockFirst = $this->getMockBuilder(CDFObject::class)
274 | ->disableOriginalConstructor()
275 | ->onlyMethods(['getUuid'])
276 | ->getMock();
277 | $cdfObjectMockSecond = $this->getMockBuilder(CDFObject::class)
278 | ->disableOriginalConstructor()
279 | ->onlyMethods(['getUuid'])
280 | ->getMock();
281 |
282 | $cdfObjectMockFirst->expects($this->any())
283 | ->method('getUuid')
284 | ->willReturn('33333333-0000-0000-0000-000000000000');
285 |
286 | $cdfObjectMockSecond->expects($this->any())
287 | ->method('getUuid')
288 | ->willReturn('44444444-0000-0000-0000-000000000000');
289 |
290 | return [
291 | array_merge($this->providerEntityOperations(), [
292 | [
293 | $cdfObjectMockFirst,
294 | $cdfObjectMockSecond,
295 | ],
296 | ]),
297 | ];
298 | }
299 |
300 | /**
301 | * Data provider for ::testMergeDocumentsNoOverlap.
302 | *
303 | * @return array
304 | * Test data.
305 | */
306 | public function providerMergeDocumentsNoOverlap() {
307 | // First set of objects.
308 | $setOneFirst = $this->getMockBuilder(CDFObject::class)
309 | ->disableOriginalConstructor()
310 | ->onlyMethods(['getUuid'])
311 | ->getMock();
312 | $setOneSecond = $this->getMockBuilder(CDFObject::class)
313 | ->disableOriginalConstructor()
314 | ->onlyMethods(['getUuid'])
315 | ->getMock();
316 |
317 | $setOneFirst->expects($this->any())
318 | ->method('getUuid')
319 | ->willReturn('11111111-0000-0000-0000-000000000000');
320 |
321 | $setOneSecond->expects($this->any())
322 | ->method('getUuid')
323 | ->willReturn('22222222-0000-0000-0000-000000000000');
324 |
325 | // Second set of objects.
326 | $setTwoFirst = $this->getMockBuilder(CDFObject::class)
327 | ->disableOriginalConstructor()
328 | ->onlyMethods(['getUuid'])
329 | ->getMock();
330 | $setTwoSecond = $this->getMockBuilder(CDFObject::class)
331 | ->disableOriginalConstructor()
332 | ->onlyMethods(['getUuid'])
333 | ->getMock();
334 |
335 | $setTwoFirst->expects($this->any())
336 | ->method('getUuid')
337 | ->willReturn('33333333-0000-0000-0000-000000000000');
338 |
339 | $setTwoSecond->expects($this->any())
340 | ->method('getUuid')
341 | ->willReturn('44444444-0000-0000-0000-000000000000');
342 |
343 | return [
344 | [
345 | [
346 | $setOneFirst,
347 | $setOneSecond,
348 | ],
349 | [
350 | $setTwoFirst,
351 | $setTwoSecond,
352 | ],
353 | $setTwoFirst,
354 | ],
355 | [
356 | [
357 | $setOneFirst,
358 | $setOneSecond,
359 | ],
360 | [
361 | $setTwoFirst,
362 | $setTwoSecond,
363 | ],
364 | $setTwoSecond,
365 | ],
366 | ];
367 | }
368 |
369 | /**
370 | * Data provider for ::testMergeDocumentsOverlap.
371 | *
372 | * @return array
373 | * Test data.
374 | */
375 | public function providerMergeDocumentsOverlap() {
376 | // First set of objects.
377 | $setOneFirst = $this->getMockBuilder(CDFObject::class)
378 | ->disableOriginalConstructor()
379 | ->onlyMethods(['getUuid'])
380 | ->getMock();
381 | $setOneSecond = $this->getMockBuilder(CDFObject::class)
382 | ->disableOriginalConstructor()
383 | ->onlyMethods(['getUuid'])
384 | ->getMock();
385 |
386 | $setOneFirst->expects($this->any())
387 | ->method('getUuid')
388 | ->willReturn('11111111-0000-0000-0000-000000000000');
389 |
390 | $setOneSecond->expects($this->any())
391 | ->method('getUuid')
392 | ->willReturn('22222222-0000-0000-0000-000000000000');
393 |
394 | // Second set of objects.
395 | $setTwoFirst = $this->getMockBuilder(CDFObject::class)
396 | ->disableOriginalConstructor()
397 | ->onlyMethods(['getUuid'])
398 | ->getMock();
399 | $setTwoSecond = $this->getMockBuilder(CDFObject::class)
400 | ->disableOriginalConstructor()
401 | ->onlyMethods(['getUuid'])
402 | ->getMock();
403 |
404 | $setTwoFirst->expects($this->any())
405 | ->method('getUuid')
406 | ->willReturn('11111111-0000-0000-0000-000000000000');
407 |
408 | $setTwoSecond->expects($this->any())
409 | ->method('getUuid')
410 | ->willReturn('22222222-0000-0000-0000-000000000000');
411 |
412 | return [
413 | [
414 | [
415 | $setOneFirst,
416 | $setOneSecond,
417 | ],
418 | [
419 | $setTwoFirst,
420 | $setTwoSecond,
421 | ],
422 | $setTwoFirst,
423 | ],
424 | [
425 | [
426 | $setOneFirst,
427 | $setOneSecond,
428 | ],
429 | [
430 | $setTwoFirst,
431 | $setTwoSecond,
432 | ],
433 | $setTwoSecond,
434 | ],
435 | ];
436 | }
437 |
438 | /**
439 | * Data provider for ::testToString.
440 | *
441 | * @return array
442 | * Test data.
443 | */
444 | public function providerToString() {
445 | $cdfObjectMockFirst = $this->getMockBuilder(CDFObject::class)
446 | ->disableOriginalConstructor()
447 | ->onlyMethods(['getUuid', 'toArray'])
448 | ->getMock();
449 | $cdfObjectMockSecond = $this->getMockBuilder(CDFObject::class)
450 | ->disableOriginalConstructor()
451 | ->onlyMethods(['getUuid', 'toArray'])
452 | ->getMock();
453 |
454 | $cdfObjectMockFirst->expects($this->any())
455 | ->method('getUuid')
456 | ->will($this->returnValue('55555555-0000-0000-0000-000000000000'));
457 |
458 | $cdfArrayMock = [
459 | 'uuid' => '00000000-0000-0000-0000-000000000000',
460 | 'type' => 'product',
461 | 'created' => '2014-12-21T20:12:11+00:00Z',
462 | 'modified' => '2014-12-21T20:12:11+00:00Z',
463 | 'origin' => '00000000-0000-0000-0000-000000000000',
464 | ];
465 | $cdfObjectMockFirstToArray = $cdfArrayMock;
466 | $cdfObjectMockSecondToArray = $cdfArrayMock;
467 |
468 | $cdfObjectMockFirstToArray['uuid'] = '55555555-0000-0000-0000-000000000000';
469 | $cdfObjectMockFirstToArray['origin'] = '11111111-0000-0000-0000-000000000000';
470 |
471 | $cdfObjectMockFirstToArray['uuid'] = '66666666-0000-0000-0000-000000000000';
472 | $cdfObjectMockFirstToArray['origin'] = '22222222-0000-0000-0000-000000000000';
473 |
474 | $cdfObjectMockFirst->expects($this->any())
475 | ->method('toArray')
476 | ->willReturn($cdfObjectMockFirstToArray);
477 |
478 | $cdfObjectMockSecond->expects($this->any())
479 | ->method('getUuid')
480 | ->willReturn('66666666-0000-0000-0000-000000000000');
481 |
482 | $cdfObjectMockSecond->expects($this->any())
483 | ->method('toArray')
484 | ->willReturn($cdfObjectMockSecondToArray);
485 |
486 | return [
487 | [
488 | [
489 | $cdfObjectMockFirst,
490 | $cdfObjectMockSecond,
491 | ],
492 | json_encode(['entities' => []]),
493 | json_encode([
494 | 'entities' => [
495 | $cdfObjectMockFirstToArray,
496 | $cdfObjectMockSecondToArray,
497 | ],
498 | ]),
499 | ],
500 | ];
501 | }
502 |
503 | }
504 |
--------------------------------------------------------------------------------
/src/ContentHubClient.php:
--------------------------------------------------------------------------------
1 | FALSE,
39 | 'error' => [
40 | 'code' => HttpResponse::HTTP_GONE,
41 | 'message' => 'This feature is deprecated',
42 | ],
43 | ];
44 |
45 | /**
46 | * The settings.
47 | *
48 | * @var \Acquia\ContentHubClient\Settings
49 | */
50 | protected $settings;
51 |
52 | /**
53 | * The logger responsible for tracking request failures.
54 | *
55 | * @var \Psr\Log\LoggerInterface
56 | */
57 | protected $logger;
58 |
59 | /**
60 | * The Event Dispatcher.
61 | *
62 | * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
63 | */
64 | protected $dispatcher;
65 |
66 | /**
67 | * Cached remote settings.
68 | *
69 | * @var array
70 | */
71 | protected $remoteSettings = [];
72 |
73 | /**
74 | * Whether to return cached remote settings.
75 | *
76 | * @var bool
77 | * True if it should return cached.
78 | */
79 | protected $shouldReturnCachedRemoteSettings = FALSE;
80 |
81 | // phpcs:disable
82 | /**
83 | * {@inheritdoc}
84 | *
85 | * @codeCoverageIgnore
86 | */
87 | public function __construct(
88 | LoggerInterface $logger,
89 | Settings $settings,
90 | HmacAuthMiddleware $middleware,
91 | EventDispatcherInterface $dispatcher,
92 | array $config = [],
93 | $api_version = 'v2'
94 | ) {
95 | $this->logger = $logger;
96 | $this->settings = $settings;
97 | $this->dispatcher = $dispatcher;
98 |
99 | // "base_url" parameter changed to "base_uri" in Guzzle6, so the following line
100 | // is there to make sure it does not disrupt previous configuration.
101 | if (!isset($config['base_uri']) && isset($config['base_url'])) {
102 | $config['base_uri'] = self::makeBaseURL($config['base_url'],
103 | $api_version);
104 | }
105 | else {
106 | $config['base_uri'] = self::makeBaseURL($config['base_uri'],
107 | $api_version);
108 | }
109 |
110 | // Setting up the User Header string.
111 | $user_agent_string = self::LIBRARYNAME . '/' . self::LIB_VERSION . ' ' . default_user_agent();
112 | if (isset($config['client-user-agent'])) {
113 | $user_agent_string = $config['client-user-agent'] . ' ' . $user_agent_string;
114 | }
115 |
116 | // Setting up the headers.
117 | $config['headers']['Content-Type'] = 'application/json';
118 | $config['headers']['X-Acquia-Plexus-Client-Id'] = $settings->getUuid();
119 | $config['headers']['User-Agent'] = $user_agent_string;
120 |
121 | // Add the authentication handler.
122 | // @see https://github.com/acquia/http-hmac-spec
123 | if (!isset($config['handler'])) {
124 | $config['handler'] = ObjectFactory::getHandlerStack();
125 | }
126 | $config['handler']->push($middleware);
127 | $this->addRequestResponseHandler($config);
128 |
129 | $this->httpClient = ObjectFactory::getGuzzleClient($config);
130 | $this->setConfigs($config);
131 | }
132 | // phpcs:enable
133 |
134 | /**
135 | * Discoverability of the API.
136 | *
137 | * @param string $endpoint
138 | * Endpoint URI.
139 | *
140 | * @return array
141 | * Response.
142 | *
143 | * @throws \Exception
144 | *
145 | * @codeCoverageIgnore
146 | */
147 | public function definition($endpoint = '') {
148 | return self::getResponseJson($this->request('options', $endpoint));
149 | }
150 |
151 | /**
152 | * Registers a new client for the active subscription.
153 | *
154 | * This method also returns the UUID for the new client being registered.
155 | *
156 | * @param \Psr\Log\LoggerInterface $logger
157 | * Logger.
158 | * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
159 | * Event dispatcher.
160 | * @param string $name
161 | * The human-readable name for the client.
162 | * @param string $url
163 | * URL.
164 | * @param string $api_key
165 | * API key.
166 | * @param string $secret
167 | * API secret.
168 | * @param string $api_version
169 | * API version.
170 | *
171 | * @return \Acquia\ContentHubClient\ContentHubClient
172 | * ContentHubClient instance.
173 | *
174 | * @throws \Exception
175 | */
176 | public static function register(
177 | LoggerInterface $logger,
178 | EventDispatcherInterface $dispatcher,
179 | $name,
180 | $url,
181 | $api_key,
182 | $secret,
183 | $api_version = 'v2'
184 | ) {
185 | $config = [
186 | 'base_uri' => self::makeBaseURL($url, $api_version),
187 | 'headers' => [
188 | 'Content-Type' => 'application/json',
189 | 'User-Agent' => self::LIBRARYNAME . '/' . self::LIB_VERSION . ' ' . default_user_agent(),
190 | ],
191 | 'handler' => ObjectFactory::getHandlerStack(),
192 | ];
193 |
194 | // Add the authentication handler.
195 | // @see https://github.com/acquia/http-hmac-spec
196 | $key = ObjectFactory::getAuthenticationKey($api_key, $secret);
197 | $middleware = ObjectFactory::getHmacAuthMiddleware($key);
198 | $config['handler']->push($middleware);
199 | $client = ObjectFactory::getGuzzleClient($config);
200 | $options['body'] = json_encode(['name' => $name]);
201 | try {
202 | $response = $client->post('register', $options);
203 | $values = self::getResponseJson($response);
204 | $settings = ObjectFactory::instantiateSettings($values['name'],
205 | $values['uuid'], $api_key, $secret, $url);
206 | $config = [
207 | 'base_url' => $settings->getUrl(),
208 | ];
209 | $client = ObjectFactory::getCHClient($config, $logger, $settings,
210 | $settings->getMiddleware(), $dispatcher);
211 | // @todo remove this once shared secret is returned on the register
212 | // endpoint.
213 | // We need the shared secret to be fully functional, so an additional
214 | // request is required to get that.
215 | $remote = $client->getRemoteSettings();
216 | // Now that we have the shared secret, reinstantiate everything and
217 | // return a new instance of this class.
218 | $settings = ObjectFactory::instantiateSettings($settings->getName(),
219 | $settings->getUuid(), $settings->getApiKey(), $settings->getSecretKey(),
220 | $settings->getUrl(), $remote['shared_secret']);
221 | return ObjectFactory::getCHClient($config, $logger, $settings,
222 | $settings->getMiddleware(), $dispatcher);
223 | }
224 | catch (\Exception $exception) {
225 | if ($exception instanceof BadResponseException) {
226 | $message = sprintf('Error registering client with name="%s" (Error Code = %d: %s)',
227 | $name, $exception->getResponse()->getStatusCode(),
228 | $exception->getResponse()->getReasonPhrase());
229 | $logger->error($message);
230 | throw new RequestException($message, $exception->getRequest(),
231 | $exception->getResponse());
232 | }
233 | if ($exception instanceof RequestException) {
234 | $message = sprintf('Could not get authorization from Content Hub to register client %s. Are your credentials inserted correctly? (Error message = %s)',
235 | $name, $exception->getMessage());
236 | $logger->error($message);
237 | throw new RequestException($message, $exception->getRequest(),
238 | $exception->getResponse());
239 | }
240 | $message = sprintf("An unknown exception was caught. Message: %s",
241 | $exception->getMessage());
242 | $logger->error($message);
243 | throw new \Exception($message);
244 | }
245 | }
246 |
247 | /**
248 | * Checks Plexus to see if the client name is already in use.
249 | *
250 | * @param string $name
251 | * Name.
252 | * @param string $url
253 | * URL.
254 | * @param string $api_key
255 | * API key.
256 | * @param string $secret
257 | * API secret.
258 | * @param string $api_version
259 | * API version.
260 | *
261 | * @return bool
262 | * Whether the clientName from the request matches the name passed to it.
263 | */
264 | public static function clientNameExists(
265 | $name,
266 | $url,
267 | $api_key,
268 | $secret,
269 | $api_version = 'v2'
270 | ) {
271 | $config = [
272 | 'base_uri' => self::makeBaseURL($url, $api_version),
273 | 'headers' => [
274 | 'Content-Type' => 'application/json',
275 | 'User-Agent' => self::LIBRARYNAME . '/' . self::LIB_VERSION . ' ' . default_user_agent(),
276 | ],
277 | 'handler' => ObjectFactory::getHandlerStack(),
278 | ];
279 |
280 | // Add the authentication handler.
281 | // @see https://github.com/acquia/http-hmac-spec
282 | $key = ObjectFactory::getAuthenticationKey($api_key, $secret);
283 | $middleware = ObjectFactory::getHmacAuthMiddleware($key);
284 | $config['handler']->push($middleware);
285 | $client = ObjectFactory::getGuzzleClient($config);
286 | $options['body'] = json_encode(['name' => $name]);
287 | // Attempt to fetch the client name, if it works.
288 | try {
289 | $client->get("settings/clients/$name");
290 |
291 | return TRUE;
292 | }
293 | catch (ClientException $error) {
294 | return $error->getResponse()->getStatusCode() !== HttpResponse::HTTP_NOT_FOUND;
295 | }
296 | }
297 |
298 | /**
299 | * Sends request to asynchronously create entities.
300 | *
301 | * phpcs:ignore @param \Acquia\ContentHubClient\CDF\CDFObject ...$objects
302 | * Individual CDFObjects to send to ContentHub.
303 | *
304 | * @return \Psr\Http\Message\ResponseInterface
305 | * Response.
306 | */
307 | public function createEntities(CDFObject ...$objects) {
308 | $json = [
309 | 'resource' => "",
310 | ];
311 | foreach ($objects as $object) {
312 | $json['entities'][] = $object->toArray();
313 | }
314 | $options['body'] = json_encode($json);
315 | return $this->post('entities', $options);
316 | }
317 |
318 | /**
319 | * Returns an entity by UUID.
320 | *
321 | * @param string $uuid
322 | * UUID.
323 | *
324 | * @return \Acquia\ContentHubClient\CDF\CDFObjectInterface|array
325 | * A CDFObject representing the entity or an array if there was no data.
326 | *
327 | * @throws \GuzzleHttp\Exception\RequestException
328 | * @throws \Exception
329 | *
330 | * @todo can we return a CDFObject here?
331 | */
332 | public function getEntity($uuid) {
333 | $return = self::getResponseJson($this->get("entities/$uuid"));
334 | if (!empty($return['data']['data'])) {
335 | return $this->getCDFObject($return['data']['data']);
336 | }
337 |
338 | return $return;
339 | }
340 |
341 | /**
342 | * Searches for entities.
343 | *
344 | * @param array $uuids
345 | * An array of UUIDs.
346 | *
347 | * @return \Acquia\ContentHubClient\CDFDocument
348 | * CDFDocument instance.
349 | *
350 | * @throws \GuzzleHttp\Exception\RequestException
351 | * @throws \Exception
352 | */
353 | public function getEntities(array $uuids) {
354 | $chunks = array_chunk($uuids, 50);
355 | $objects = [];
356 | foreach ($chunks as $chunk) {
357 | $query = [
358 | 'size' => 50,
359 | 'query' => [
360 | 'constant_score' => [
361 | 'filter' => [
362 | 'terms' => [
363 | 'uuid' => $chunk,
364 | ],
365 | ],
366 | ],
367 | ],
368 | ];
369 | $options['body'] = json_encode($query);
370 | $results = self::getResponseJson($this->get('_search', $options));
371 | if (isset($results['hits']['total'])) {
372 | foreach ($results['hits']['hits'] as $key => $item) {
373 | $objects[] = $this->getCDFObject($item['_source']['data']);
374 | }
375 | }
376 | }
377 |
378 | return ObjectFactory::getCDFDocument(...$objects);
379 | }
380 |
381 | /**
382 | * Retrieves a CDF Object.
383 | *
384 | * @param mixed $data
385 | * Data.
386 | *
387 | * @return \Acquia\ContentHubClient\CDF\CDFObjectInterface
388 | * CDFObject
389 | */
390 | public function getCDFObject($data) { // phpcs:ignore
391 | $event = ObjectFactory::getCDFTypeEvent($data);
392 | $this->dispatcher->dispatch($event, ContentHubLibraryEvents::GET_CDF_CLASS);
393 |
394 | return $event->getObject();
395 | }
396 |
397 | /**
398 | * Updates many entities asynchronously.
399 | *
400 | * phpcs:ignore @param \Acquia\ContentHubClient\CDF\CDFObject ...$objects
401 | * The CDFObjects to update.
402 | *
403 | * @return \Psr\Http\Message\ResponseInterface
404 | * Response.
405 | */
406 | public function putEntities(CDFObject ...$objects) {
407 | $json = [
408 | 'resource' => '',
409 | ];
410 |
411 | foreach ($objects as $object) {
412 | $json['data']['entities'][] = $object->toArray();
413 | }
414 |
415 | $options['body'] = json_encode($json);
416 |
417 | return $this->put('entities', $options);
418 | }
419 |
420 | /**
421 | * Post entities.
422 | *
423 | * phpcs:ignore @param \Acquia\ContentHubClient\CDF\CDFObject ...$objects
424 | *
425 | * @return \Psr\Http\Message\ResponseInterface
426 | * Response.
427 | */
428 | public function postEntities(CDFObject ...$objects) {
429 | $json = [
430 | 'resource' => "",
431 | ];
432 | foreach ($objects as $object) {
433 | $json['data']['entities'][] = $object->toArray();
434 | }
435 | $options['body'] = json_encode($json);
436 | return $this->post('entities', $options);
437 | }
438 |
439 | /**
440 | * Deletes an entity by UUID.
441 | *
442 | * @param string $uuid
443 | * Entity UUID.
444 | *
445 | * @return \Psr\Http\Message\ResponseInterface
446 | * Response.
447 | *
448 | * @throws \GuzzleHttp\Exception\RequestException
449 | */
450 | public function deleteEntity($uuid) {
451 | return $this->delete("entities/$uuid");
452 | }
453 |
454 | /**
455 | * Deletes an entity from a webhook's interest list.
456 | *
457 | * @param string $uuid
458 | * Interest UUID.
459 | * @param string $webhook_uuid
460 | * Webhook UUID.
461 | *
462 | * @return \Psr\Http\Message\ResponseInterface
463 | * Response.
464 | */
465 | public function deleteInterest($uuid, $webhook_uuid) {
466 | return $this->delete("interest/$uuid/$webhook_uuid");
467 | }
468 |
469 | /**
470 | * Purges all entities from the Content Hub.
471 | *
472 | * This method should be used carefully as it deletes all the entities for
473 | * the current subscription from the Content Hub. This creates a backup that
474 | * can be restored at any time. Any subsequent purges overwrite the existing
475 | * backup. Be VERY careful when using this endpoint.
476 | *
477 | * @return mixed
478 | * Response.
479 | *
480 | * @throws \Exception
481 | */
482 | public function purge() {
483 | return self::getResponseJson($this->post('entities/purge'));
484 | }
485 |
486 | /**
487 | * Restores the state of entities before the previous purge.
488 | *
489 | * Only to be used if a purge has been called previously. This means new
490 | * entities added after the purge was enacted will be overwritten by the
491 | * previous state. Be VERY careful when using this endpoint.
492 | *
493 | * @return mixed
494 | * Response.
495 | *
496 | * @throws \Exception
497 | */
498 | public function restore() {
499 | return self::getResponseJson($this->post('entities/restore'));
500 | }
501 |
502 | /**
503 | * Reindex a subscription.
504 | *
505 | * Schedules a reindex process.
506 | *
507 | * @return mixed
508 | * Response.
509 | *
510 | * @throws \GuzzleHttp\Exception\RequestException
511 | * @throws \Exception
512 | */
513 | public function reindex() {
514 | return self::getResponseJson($this->post('reindex'));
515 | }
516 |
517 | /**
518 | * Obtains Customer-Facing-Logs for the subscription.
519 | *
520 | * This is forward search request to Elastic Search.
521 | *
522 | * @param string $query
523 | * An elastic search query.
524 | * @param array $query_options
525 | * An array with the number of items to show in the list and offset.
526 | *
527 | * @return mixed
528 | * Response.
529 | *
530 | * @throws \Exception
531 | * @throws \GuzzleHttp\Exception\RequestException
532 | */
533 | public function logs($query = '', array $query_options = []) {
534 | return new Response(
535 | self::FEATURE_DEPRECATED_RESPONSE['error']['code'],
536 | [],
537 | json_encode(self::FEATURE_DEPRECATED_RESPONSE),
538 | '1.1',
539 | self::FEATURE_DEPRECATED_RESPONSE['error']['message']
540 | );
541 | }
542 |
543 | /**
544 | * Retrieves active ElasticSearch mapping of entities.
545 | *
546 | * @return mixed
547 | * Response.
548 | *
549 | * @throws \Exception
550 | * @throws \GuzzleHttp\Exception\RequestException
551 | */
552 | public function mapping() {
553 | return self::getResponseJson($this->get('_mapping'));
554 | }
555 |
556 | /**
557 | * Lists Entities from the Content Hub.
558 | *
559 | * Example of how to structure the $options parameter:
560 | *
561 | * $options = [
562 | * 'limit' => 20,
563 | * 'type' => 'node',
564 | * 'origin' => '11111111-1111-1111-1111-111111111111',
565 | * 'fields' => 'status,title,body,field_tags,description',
566 | * 'filters' => [
567 | * 'status' => 1,
568 | * 'title' => 'New*',
569 | * 'body' => '/Boston/',
570 | * ],
571 | * ];
572 | *
573 | *
574 | * @param array $options
575 | * Query options.
576 | *
577 | * @return mixed
578 | * Response.
579 | *
580 | * @throws \GuzzleHttp\Exception\RequestException
581 | * @throws \Exception
582 | */
583 | public function listEntities(array $options = []) {
584 | $variables = $options + [
585 | 'limit' => 1000,
586 | 'start' => 0,
587 | 'filters' => [],
588 | ];
589 |
590 | foreach ($variables['filters'] as $key => $value) {
591 | $variables["filter:${key}"] = $value;
592 | }
593 | unset($variables['filters']);
594 |
595 | // Now make the request.
596 | return self::getResponseJson($this->get('entities?' . http_build_query($variables)));
597 | }
598 |
599 | /**
600 | * Searches for entities.
601 | *
602 | * @param mixed $query
603 | * Search query.
604 | *
605 | * @return mixed
606 | * Response.
607 | *
608 | * @throws \Exception
609 | * @throws \GuzzleHttp\Exception\RequestException
610 | */
611 | public function searchEntity($query) {
612 | $options['body'] = json_encode((array) $query);
613 | return self::getResponseJson($this->get('_search', $options));
614 | }
615 |
616 | /**
617 | * Returns the Client, given the site name.
618 | *
619 | * @param string $name
620 | * Client name.
621 | *
622 | * @return mixed
623 | * Response.
624 | *
625 | * @throws \Exception
626 | */
627 | public function getClientByName($name) {
628 | return self::getResponseJson($this->get("settings/client/name/$name"));
629 | }
630 |
631 | /**
632 | * Returns the Client, given its uuid.
633 | *
634 | * @param string $uuid
635 | * Client uuid.
636 | *
637 | * @return array
638 | * The client array (uuid, name).
639 | *
640 | * @throws \Exception
641 | */
642 | public function getClientByUuid(string $uuid): array {
643 | $settings = $this->getRemoteSettings();
644 | foreach ($settings['clients'] as $client) {
645 | if ($client['uuid'] === $uuid) {
646 | return $client;
647 | }
648 | }
649 | return [];
650 | }
651 |
652 | /**
653 | * Returns clients.
654 | *
655 | * @return mixed
656 | * Clients list.
657 | *
658 | * @throws \Exception
659 | */
660 | public function getClients() {
661 | $data = $this->getRemoteSettings();
662 |
663 | return $data['clients'] ?? [];
664 | }
665 |
666 | /**
667 | * Returns webhooks list.
668 | *
669 | * @return \Acquia\ContentHubClient\Webhook[]
670 | * Webhooks list.
671 | *
672 | * @throws \Exception
673 | */
674 | public function getWebHooks() {
675 | $data = $this->getRemoteSettings();
676 | $webhooks = $data['webhooks'] ?? [];
677 | array_walk($webhooks, function (&$webhook) {
678 | $webhook = ObjectFactory::getWebhook($webhook);
679 | });
680 | return $webhooks;
681 | }
682 |
683 | /**
684 | * Returns webhook by URL.
685 | *
686 | * @param string $url
687 | * URL.
688 | *
689 | * @return array
690 | * Webhook.
691 | *
692 | * @throws \Exception
693 | *
694 | * @codeCoverageIgnore
695 | */
696 | public function getWebHook($url) {
697 | return current(array_filter($this->getWebHooks(),
698 | function (Webhook $webhook) use ($url) {
699 | return $webhook->getUrl() === $url;
700 | })) ?? [];
701 | }
702 |
703 | /**
704 | * Returns status information for all webhooks.
705 | *
706 | * @return array
707 | * Webhooks status information.
708 | *
709 | * @throws \Exception
710 | */
711 | public function getWebhookStatus() {
712 | return self::getResponseJson($this->get('settings/webhooks/status'));
713 | }
714 |
715 | /**
716 | * Returns interests list.
717 | *
718 | * @param string $webhook_uuid
719 | * Webhook UUID.
720 | *
721 | * @return array
722 | * Interests list.
723 | *
724 | * @throws \Exception
725 | */
726 | public function getInterestsByWebhook($webhook_uuid) {
727 | $data = self::getResponseJson($this->get("interest/webhook/$webhook_uuid"));
728 |
729 | return $data['data']['interests'] ?? [];
730 | }
731 |
732 | /**
733 | * Obtains the Settings for the active subscription.
734 | *
735 | * @return array
736 | * Response.
737 | *
738 | * @throws \Exception
739 | *
740 | * @codeCoverageIgnore
741 | */
742 | public function getRemoteSettings(): array {
743 | if ($this->shouldReturnCachedRemoteSettings && !empty($this->remoteSettings)) {
744 | return $this->remoteSettings;
745 | }
746 | $this->remoteSettings = self::getResponseJson($this->get('settings'));
747 | return !is_array($this->remoteSettings) ? [] : $this->remoteSettings;
748 | }
749 |
750 | /**
751 | * Sets cachable remote settings.
752 | *
753 | * @param bool $should_cache
754 | * If set to true, returns cached remote settings.
755 | */
756 | public function cacheRemoteSettings(bool $should_cache): void {
757 | $this->shouldReturnCachedRemoteSettings = $should_cache;
758 | }
759 |
760 | /**
761 | * Adds a webhook to the active subscription.
762 | *
763 | * @param string $webhook_url
764 | * Webhook URL.
765 | *
766 | * @return mixed
767 | * Response.
768 | *
769 | * @throws \Exception
770 | */
771 | public function addWebhook($webhook_url) {
772 | $options['body'] = json_encode(['url' => $webhook_url, 'version' => 2.0]);
773 |
774 | return self::getResponseJson($this->post('settings/webhooks', $options));
775 | }
776 |
777 | /**
778 | * Deletes a webhook from the active subscription.
779 | *
780 | * @param string $uuid
781 | * The UUID of the webhook to delete.
782 | *
783 | * @return \Psr\Http\Message\ResponseInterface
784 | * Response.
785 | *
786 | * @throws \GuzzleHttp\Exception\RequestException
787 | */
788 | public function deleteWebhook($uuid) {
789 | return $this->delete("settings/webhooks/$uuid");
790 | }
791 |
792 | /**
793 | * Updates a webhook from the active subscription.
794 | *
795 | * @param string $uuid
796 | * The UUID of the webhook to update.
797 | * @param array $options
798 | * What to change in the webhook: url, version, disable_retries, etc.
799 | *
800 | * @return \Psr\Http\Message\ResponseInterface
801 | * Response.
802 | *
803 | * @throws \GuzzleHttp\Exception\RequestException
804 | */
805 | public function updateWebhook($uuid, array $options) {
806 | if (isset($options['version']) && !in_array($options['version'], [1, 2],
807 | TRUE)) {
808 | $options['version'] = 2;
809 | }
810 | $acceptable_keys = [
811 | 'version',
812 | 'url',
813 | 'disable_retries',
814 | 'status',
815 | ];
816 | $values = [];
817 | foreach ($acceptable_keys as $key) {
818 | if (isset($options[$key])) {
819 | $values[$key] = $options[$key];
820 | }
821 | }
822 | $data['body'] = json_encode($values);
823 | return $this->put("settings/webhooks/$uuid", $data);
824 | }
825 |
826 | /**
827 | * Suppress webhook.
828 | *
829 | * @param string $webhook_uuid
830 | * Webhook uuid.
831 | *
832 | * @return mixed
833 | * Response body of backend call.
834 | */
835 | public function suppressWebhook(string $webhook_uuid) {
836 | return self::getResponseJson($this->put("webhook/$webhook_uuid/suppress"));
837 | }
838 |
839 | /**
840 | * Remove suppression from webhook.
841 | *
842 | * @param string $webhook_uuid
843 | * Webhook uuid.
844 | *
845 | * @return mixed
846 | * Response body of backend call.
847 | */
848 | public function unSuppressWebhook(string $webhook_uuid) {
849 | return self::getResponseJson($this->put("settings/webhooks/$webhook_uuid/enable"));
850 | }
851 |
852 | /**
853 | * Add entities to Interest List.
854 | *
855 | * @param string $webhook_uuid
856 | * The UUID of the webhook.
857 | * @param array $uuids
858 | * Entity UUIDs to add to Interest List.
859 | *
860 | * @return \Psr\Http\Message\ResponseInterface
861 | * The response.
862 | *
863 | * @throws \GuzzleHttp\Exception\RequestException
864 | */
865 | public function addEntitiesToInterestList($webhook_uuid, array $uuids) {
866 | $options['body'] = json_encode(['interests' => $uuids]);
867 |
868 | return $this->post("interest/webhook/$webhook_uuid", $options);
869 | }
870 |
871 | /**
872 | * Deletes a client from the active subscription.
873 | *
874 | * @param string $client_uuid
875 | * The UUID of the client to delete, blank for current client.
876 | *
877 | * @return \Psr\Http\Message\ResponseInterface
878 | * Response.
879 | *
880 | * @throws \Exception
881 | */
882 | public function deleteClient($client_uuid = NULL) {
883 | $settings = $this->getSettings();
884 | $uuid = $client_uuid ?? $settings->getUuid();
885 | $response = $this->deleteEntity($uuid);
886 | if (!$response || $response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
887 | throw new \Exception(sprintf("Entity with UUID = %s cannot be deleted.", $uuid));
888 | }
889 | return $this->delete("settings/client/uuid/$uuid");
890 | }
891 |
892 | /**
893 | * Updates a client from the active subscription.
894 | *
895 | * @param string $uuid
896 | * The UUID of the client to update.
897 | * @param string $name
898 | * The new name for the client we're updating.
899 | *
900 | * @return \Psr\Http\Message\ResponseInterface
901 | * Response.
902 | *
903 | * @throws \GuzzleHttp\Exception\RequestException
904 | */
905 | public function updateClient($uuid, $name) {
906 | $options['body'] = json_encode(['name' => $name]);
907 | return $this->put("settings/client/uuid/$uuid", $options);
908 | }
909 |
910 | /**
911 | * Regenerates a Shared Secret for the Subscription.
912 | *
913 | * @return array
914 | * Response.
915 | *
916 | * @throws \GuzzleHttp\Exception\RequestException
917 | * @throws \Exception
918 | */
919 | public function regenerateSharedSecret() {
920 | return self::getResponseJson($this->post('settings/secret', ['body' => json_encode([])]));
921 | }
922 |
923 | /**
924 | * Gets filter by UUID.
925 | *
926 | * @param string $filter_id
927 | * The filter UUID.
928 | *
929 | * @return array
930 | * Response
931 | *
932 | * @throws \GuzzleHttp\Exception\RequestException
933 | * @throws \Exception
934 | */
935 | public function getFilter($filter_id) {
936 | return $this::getResponseJson($this->get("filters/$filter_id"));
937 | }
938 |
939 | /**
940 | * Gets filter by Name.
941 | *
942 | * @param string $filter_name
943 | * The filter name.
944 | *
945 | * @return array
946 | * The filter array.
947 | *
948 | * @throws \GuzzleHttp\Exception\RequestException
949 | * @throws \Exception
950 | */
951 | public function getFilterByName($filter_name) {
952 | $result = $this::getResponseJson($this->get("filters?name={$filter_name}"));
953 | if ($result['success'] == 1) {
954 | return $result['data'];
955 | }
956 |
957 | return NULL;
958 | }
959 |
960 | /**
961 | * List all filters in the subscription.
962 | *
963 | * @return array
964 | * An array of all filters in the subscription.
965 | *
966 | * @throws \GuzzleHttp\Exception\RequestException
967 | * @throws \Exception
968 | */
969 | public function listFilters() {
970 | return $this::getResponseJson($this->get('filters'));
971 | }
972 |
973 | /**
974 | * Puts a Filter into Content Hub.
975 | *
976 | * @param string|array $query
977 | * The query to add to the filter.
978 | * @param string $name
979 | * The name of the filter.
980 | * @param string $uuid
981 | * The filter UUID to update existing filter, NULL to create a new one.
982 | * @param array $metadata
983 | * The Metadata array, empty if not given.
984 | *
985 | * @return array
986 | * An array of data including the filter UUID, if succeeds.
987 | *
988 | * @throws \GuzzleHttp\Exception\RequestException
989 | * @throws \Exception
990 | */
991 | public function putFilter($query, $name, $uuid = NULL, array $metadata = []) {
992 | $data = [
993 | 'name' => $name,
994 | 'data' => [
995 | 'query' => $query,
996 | ],
997 | 'metadata' => (object) $metadata,
998 | ];
999 | if (!empty($uuid)) {
1000 | $data['uuid'] = $uuid;
1001 | }
1002 | $options = ['body' => json_encode($data)];
1003 |
1004 | return self::getResponseJson($this->put('filters', $options));
1005 | }
1006 |
1007 | /**
1008 | * Deletes a filter, given its UUID.
1009 | *
1010 | * @param string $filter_uuid
1011 | * The filter UUID.
1012 | *
1013 | * @return \Psr\Http\Message\ResponseInterface
1014 | * The response.
1015 | *
1016 | * @throws \GuzzleHttp\Exception\RequestException
1017 | */
1018 | public function deleteFilter($filter_uuid) {
1019 | return $this->delete("filters/{$filter_uuid}");
1020 | }
1021 |
1022 | /**
1023 | * List all filters attached to a particular webhook.
1024 | *
1025 | * @param string $webhook_id
1026 | * The webhook UUID.
1027 | *
1028 | * @return array
1029 | * An array of data including the filter UUID, if succeeds.
1030 | *
1031 | * @throws \GuzzleHttp\Exception\RequestException
1032 | * @throws \Exception
1033 | */
1034 | public function listFiltersForWebhook($webhook_id) {
1035 | return $this::getResponseJson($this->get("settings/webhooks/$webhook_id/filters"));
1036 | }
1037 |
1038 | /**
1039 | * Attaches a filter to a webhook.
1040 | *
1041 | * @param string $filter_id
1042 | * The filter UUID.
1043 | * @param string $webhook_id
1044 | * The Webhook UUID.
1045 | *
1046 | * @return array
1047 | * An array of data including the filter UUID, if succeeds.
1048 | *
1049 | * @throws \GuzzleHttp\Exception\RequestException
1050 | * @throws \Exception
1051 | */
1052 | public function addFilterToWebhook($filter_id, $webhook_id) {
1053 | $data = ['filter_id' => $filter_id];
1054 | $options = ['body' => json_encode($data)];
1055 |
1056 | return self::getResponseJson($this->post("settings/webhooks/$webhook_id/filters", $options));
1057 | }
1058 |
1059 | /**
1060 | * Detaches filter from webhook.
1061 | *
1062 | * @param string $filter_id
1063 | * Filter UUID.
1064 | * @param string $webhook_id
1065 | * Webhook UUID.
1066 | *
1067 | * @return mixed
1068 | * Response.
1069 | *
1070 | * @throws \Exception
1071 | */
1072 | public function removeFilterFromWebhook($filter_id, $webhook_id) {
1073 | $options = ['body' => json_encode(['filter_id' => $filter_id])];
1074 | $response = $this->delete("settings/webhooks/$webhook_id/filters", $options);
1075 |
1076 | return self::getResponseJson($response);
1077 | }
1078 |
1079 | /**
1080 | * Appends search criteria header.
1081 | *
1082 | * @param array $args
1083 | * Method arguments.
1084 | *
1085 | * @return array
1086 | * Processed arguments.
1087 | */
1088 | protected function addSearchCriteriaHeader(array $args) {
1089 | $result = explode('?', $args[0] ?? '');
1090 | if (count($result) < 2) {
1091 | return $args;
1092 | }
1093 | [, $queryString] = $result;
1094 | if (empty($queryString)) {
1095 | return $args;
1096 | }
1097 | parse_str($queryString, $parsedQueryString);
1098 |
1099 | $languages = $this->getConfig(self::OPTION_NAME_LANGUAGES);
1100 | if (!empty($languages) && is_array($languages)) {
1101 | $parsedQueryString['languages'] = $languages;
1102 | }
1103 |
1104 | /** @var \Acquia\ContentHubClient\SearchCriteria\SearchCriteria $criteria */
1105 | $criteria = SearchCriteriaBuilder::createFromArray($parsedQueryString);
1106 | $args[1]['headers'] = $args[1]['headers'] ?? [];
1107 | $args[1]['headers'][SearchCriteria::HEADER_NAME] = base64_encode(json_encode($criteria));
1108 |
1109 | return $args;
1110 | }
1111 |
1112 | /**
1113 | * Fetch snapshots.
1114 | *
1115 | * @return mixed
1116 | * Response.
1117 | *
1118 | * @throws \Exception
1119 | */
1120 | public function getSnapshots() {
1121 | return self::getResponseJson($this->get('snapshots'));
1122 | }
1123 |
1124 | /**
1125 | * Create a snapshot.
1126 | *
1127 | * @return mixed
1128 | * Response.
1129 | *
1130 | * @throws \Exception
1131 | */
1132 | public function createSnapshot() {
1133 | return self::getResponseJson($this->post('snapshots'));
1134 | }
1135 |
1136 | /**
1137 | * Deletes a snapshot.
1138 | *
1139 | * @param string $name
1140 | * The name of the snapshot.
1141 | *
1142 | * @return mixed
1143 | * Response from backend call.
1144 | *
1145 | * @throws \GuzzleHttp\Exception\RequestException
1146 | */
1147 | public function deleteSnapshot($name) {
1148 | return self::getResponseJson($this->delete("snapshots/$name"));
1149 | }
1150 |
1151 | /**
1152 | * Restore a snapshot.
1153 | *
1154 | * @param string $name
1155 | * The name of the snapshot.
1156 | *
1157 | * @return mixed
1158 | * Response from backend call.
1159 | *
1160 | * @throws \GuzzleHttp\Exception\RequestException
1161 | */
1162 | public function restoreSnapshot(string $name) {
1163 | return self::getResponseJson($this->put("snapshots/$name/restore"));
1164 | }
1165 |
1166 | /**
1167 | * Initiates Scroll API request chain.
1168 | *
1169 | * @param string $scroll_time_window
1170 | * How long the scroll cursor will be retained inside memory. Must be
1171 | * suffixed with duration unit (m, s, ms etc.).
1172 | * @param int $size
1173 | * Amount of entities to return.
1174 | * @param array $query
1175 | * Search query.
1176 | *
1177 | * @return array
1178 | * Response from scroll API.
1179 | *
1180 | * @throws \Exception
1181 | */
1182 | public function startScroll(string $scroll_time_window = '30m', int $size = 100, array $query = []): array {
1183 | $options['body'] = json_encode($query);
1184 | $options['query'] = [
1185 | 'scroll' => $scroll_time_window,
1186 | 'size' => $size,
1187 | ];
1188 | return self::getResponseJson($this->post('scroll', $options));
1189 | }
1190 |
1191 | /**
1192 | * Initiates Scroll API request chain.
1193 | *
1194 | * @param string $filter_uuid
1195 | * Filter uuid to execute by.
1196 | * @param string|int $scroll_time_window
1197 | * How long the scroll cursor will be retained inside memory. Must be
1198 | * suffixed with duration unit (m, s, ms etc.).
1199 | * @param int $size
1200 | * Amount of entities to return.
1201 | *
1202 | * @return array
1203 | * Response from backend call.
1204 | *
1205 | * @throws \Exception
1206 | */
1207 | public function startScrollByFilter(string $filter_uuid, $scroll_time_window, int $size): array {
1208 | return self::getResponseJson($this->post("filters/$filter_uuid/scroll", [
1209 | 'query' => [
1210 | 'scroll' => $scroll_time_window,
1211 | 'size' => $size,
1212 | ],
1213 | ]));
1214 | }
1215 |
1216 | /**
1217 | * Continue Scroll API request chain.
1218 | *
1219 | * Notice: scroll id is changing continuously once you make a call.
1220 | *
1221 | * @param string $scroll_id
1222 | * Scroll id.
1223 | * @param string|int $scroll_time_window
1224 | * How long the scroll cursor will be retained inside memory.
1225 | *
1226 | * @return array
1227 | * Response from backend call.
1228 | *
1229 | * @throws \Exception
1230 | */
1231 | public function continueScroll(string $scroll_id, $scroll_time_window): array {
1232 | $options = [
1233 | 'body' => json_encode([
1234 | 'scroll_id' => $scroll_id,
1235 | 'scroll' => $scroll_time_window,
1236 | ]),
1237 | ];
1238 |
1239 | return self::getResponseJson($this->post('scroll/continue', $options));
1240 | }
1241 |
1242 | /**
1243 | * Cancel Scroll API request chain.
1244 | *
1245 | * @param string $scroll_id
1246 | * Scroll id.
1247 | *
1248 | * @return array|null
1249 | * Response from backend call.
1250 | *
1251 | * @throws \Exception
1252 | */
1253 | public function cancelScroll(string $scroll_id): ?array {
1254 | $options = [
1255 | 'body' => json_encode([
1256 | 'scroll_id' => [$scroll_id],
1257 | ]),
1258 | ];
1259 |
1260 | return self::getResponseJson($this->delete("scroll", $options));
1261 | }
1262 |
1263 | /**
1264 | * Checks whether the given account is featured.
1265 | *
1266 | * @return bool
1267 | * True if the account is featured.
1268 | *
1269 | * @throws \Exception
1270 | */
1271 | public function isFeatured(): bool {
1272 | $remote = $this->getRemoteSettings();
1273 | return $remote['featured'] ?? FALSE;
1274 | }
1275 |
1276 | }
1277 |
--------------------------------------------------------------------------------