From 50b855dc768fbdbfddefff8e6930f2b9178902f5 Mon Sep 17 00:00:00 2001 From: Roberto Butti Date: Fri, 16 Dec 2022 21:37:30 +0100 Subject: [PATCH 1/3] Feature: Introducing Static Code Analysis, PHPStan and refactor at level 2 --- .github/workflows/tests.yml | 5 +- composer.json | 12 +- phpstan.neon | 2 +- src/Storyblok/BaseClient.php | 201 +------------------------------- src/Storyblok/Client.php | 216 +++++++++++++++++++++++++++++++++-- 5 files changed, 227 insertions(+), 209 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4ff7e98..2cc1d3a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -65,5 +65,8 @@ jobs: - name: Install dependencies run: composer install --prefer-dist --no-progress --no-suggest + - name: Run Static Code Analysis + run: composer phpstan + - name: Run test suite - run: ./vendor/bin/pest --ci + run: composer test-ci diff --git a/composer.json b/composer.json index 1f76032..cde70ec 100644 --- a/composer.json +++ b/composer.json @@ -30,8 +30,8 @@ } ], "autoload": { - "psr-0": { - "Storyblok": "src" + "psr-4": { + "Storyblok\\": "src/Storyblok" } }, "autoload-dev": { @@ -49,13 +49,21 @@ }, "scripts": { "test": "vendor/bin/pest", + "test-ci": "vendor/bin/pest --ci", "phpstan": "phpstan analyse", "test-coverage": "vendor/bin/pest --coverage", "format": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix --allow-risky=yes --using-cache=no", "cs": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix --dry-run --using-cache=no", "all-check": [ "@format", + "@phpstan", "@test" + ], + "all-check-ci": [ + "@cs", + "@phpstan", + "@test-ci" ] + } } diff --git a/phpstan.neon b/phpstan.neon index 35123d6..093e815 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,4 +1,4 @@ parameters: - level: 0 + level: 2 paths: - src diff --git a/src/Storyblok/BaseClient.php b/src/Storyblok/BaseClient.php index b6e2568..5953049 100644 --- a/src/Storyblok/BaseClient.php +++ b/src/Storyblok/BaseClient.php @@ -21,12 +21,12 @@ class BaseClient const DEFAULT_PER_PAGE = 25; /** - * @var stdClass + * @var \stdClass */ public $responseBody; /** - * @var stdClass + * @var \stdClass */ public $responseHeaders; @@ -63,18 +63,6 @@ class BaseClient * @var string */ private $apiKey; - /** - * List of resolved relations. - * - * @var array - */ - private $resolvedRelations; - /** - * List of resolved relations. - * - * @var array - */ - private $resolvedLinks; /** * @param string $apiKey @@ -140,7 +128,7 @@ public function retryDecider() /** * delay 1s 2s 3s 4s 5s. * - * @return Closure + * @return \Closure */ public function retryDelay() { @@ -312,9 +300,11 @@ public function responseHandler($responseObj, $queryString = []) $result->httpResponseCode = $httpResponseCode; $result->httpResponseHeaders = $responseObj->getHeaders(); + /* if (\is_array($result->httpResponseBody) && isset($result->httpResponseBody['story']) || isset($result->httpResponseBody['stories'])) { $result->httpResponseBody = $this->enrichStories($result->httpResponseBody, $queryString); } + */ return $result; } @@ -357,114 +347,6 @@ public function getCode() return $this->responseCode; } - /** - * Enrich the Stories with resolved links and stories. - * - * @param \stdClass - * @param mixed $data - * - * @return \stdClass - */ - function enrichContent($data) - { - $enrichedContent = $data; - - if (\is_array($data) && isset($data['component'])) { - if (!isset($story['_stopResolving'])) { - foreach ($data as $fieldName => $fieldValue) { - $enrichedContent[$fieldName] = $this->insertRelations($data['component'], $fieldName, $fieldValue); - $enrichedContent[$fieldName] = $this->insertLinks($enrichedContent[$fieldName]); - $enrichedContent[$fieldName] = $this->enrichContent($enrichedContent[$fieldName]); - } - } - } elseif (\is_array($data)) { - foreach ($data as $key => $value) { - $enrichedContent[$key] = $this->enrichContent($value); - } - } - - return $enrichedContent; - } - - /** - * Retrieve or resolve the relations. - * - * @param \stdClass $data - * @param array $queryString - */ - function getResolvedRelations($data, $queryString) - { - $this->resolvedRelations = []; - $relations = []; - - if (isset($data['rels'])) { - $relations = $data['rels']; - } elseif (isset($data['rel_uuids'])) { - $relSize = \count($data['rel_uuids']); - $chunks = []; - $chunkSize = 50; - - for ($i = 0; $i < $relSize; $i += $chunkSize) { - $end = min($relSize, $i + $chunkSize); - $chunks[] = \array_slice($data['rel_uuids'], $i, $end); - } - - for ($chunkIndex = 0; $chunkIndex < \count($chunks); ++$chunkIndex) { - $relationsParams = [ - 'per_page' => $chunkSize, - 'by_uuids' => implode(',', $chunks[$chunkIndex]), - ]; - if (isset($queryString['language'])) { - $relationsParams['language'] = $queryString['language']; - } - $relationsRes = $this->getStories($relationsParams); - - $relations = array_merge($relations, $relationsRes->responseBody['stories']); - } - } - - foreach ($relations as $rel) { - $this->resolvedRelations[$rel['uuid']] = $rel; - } - } - - /** - * Retrieve or resolve the Links. - * - * @param \stdClass $data - */ - function getResolvedLinks($data, array $queryString) - { - $this->resolvedLinks = []; - $links = []; - - if (isset($data['links'])) { - $links = $data['links']; - } elseif (isset($data['link_uuids'])) { - $linksSize = \count($data['link_uuids']); - $chunks = []; - $chunkSize = 50; - - for ($i = 0; $i < $linksSize; $i += $chunkSize) { - $end = min($linksSize, $i + $chunkSize); - $chunks[] = \array_slice($data['link_uuids'], $i, $end); - } - - for ($chunkIndex = 0; $chunkIndex < \count($chunks); ++$chunkIndex) { - $linksRes = $this->getStories([ - 'per_page' => $chunkSize, - 'language' => isset($queryString['language']) ? $queryString['language'] : 'default', - 'by_uuids' => implode(',', $chunks[$chunkIndex]), - ]); - - $links = array_merge($links, $linksRes->responseBody['stories']); - } - } - foreach ($links as $link) { - $this->resolvedLinks[$link['uuid']] = $link; - } - } - /** * @return string */ @@ -509,77 +391,4 @@ private function generateEndpoint($apiEndpoint, $apiVersion, $ssl, $apiRegion) return $protocol . $apiEndpoint . '/' . $apiVersion . $prefix . '/'; } - - private function enrichStories($data, $queryString) - { - $enrichedData = $data; - $this->getResolvedRelations($data, $queryString); - $this->getResolvedLinks($data, $queryString); - - if (isset($data['story'])) { - $enrichedData['story']['content'] = $this->enrichContent($data['story']['content']); - } elseif (isset($data['stories'])) { - $stories = []; - foreach ($data['stories'] as $index => $story) { - $story = $data['stories'][$index]; - $story['content'] = $this->enrichContent($story['content']); - $stories[] = $story; - } - $enrichedData['stories'] = $stories; - } - - return $enrichedData; - } - - /** - * Insert the resolved relations in a story. - * - * @param string $component - * @param string $field - * @param array|string $value - */ - private function insertRelations($component, $field, $value) - { - $filteredNode = $value; - if (isset($this->_relationsList[$component]) && $field === $this->_relationsList[$component]) { - if (\is_string($value)) { - if (isset($this->resolvedRelations[$value])) { - $filteredNode = $this->resolvedRelations[$value]; - $filteredNode['_stopResolving'] = true; - } - } elseif (\is_array($value)) { - $filteredNode = []; - foreach ($value as $item) { - if (\is_string($item) && isset($this->resolvedRelations[$item])) { - $story = $this->resolvedRelations[$item]; - $story['_stopResolving'] = true; - $filteredNode[] = $story; - } - } - } - } - - return $filteredNode; - } - - /** - * Insert the resolved links in a story. - * - * @param \stdClass $node - * - * @return \stdClass - */ - private function insertLinks($node) - { - $filteredNode = $node; - if (isset($node['fieldtype']) && 'multilink' === $node['fieldtype'] && 'story' === $node['linktype']) { - if (isset($node['id']) && \is_string($node['id']) && isset($this->resolvedLinks[$node['id']])) { - $filteredNode['story'] = $this->resolvedLinks[$node['id']]; - } elseif (isset($node['uuid']) && \is_string($node['uuid']) && isset($this->resolvedLinks[$node['uuid']])) { - $filteredNode['story'] = $this->resolvedLinks[$node['uuid']]; - } - } - - return $filteredNode; - } } diff --git a/src/Storyblok/Client.php b/src/Storyblok/Client.php index 642a80c..a8d75b8 100644 --- a/src/Storyblok/Client.php +++ b/src/Storyblok/Client.php @@ -2,9 +2,9 @@ namespace Storyblok; +use Symfony\Component\Cache\Adapter\AbstractAdapter; use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\PdoAdapter; -use Symfony\Component\Cache as SymfonyCache; /** * Storyblok Client. @@ -20,7 +20,7 @@ class Client extends BaseClient public $cacheVersion; /** - * @var SymfonyCache + * @var AbstractAdapter */ protected $cache; @@ -59,6 +59,18 @@ class Client extends BaseClient */ private $resolveLinks; + /** + * List of resolved relations. + * + * @var array + */ + private $resolvedRelations; + /** + * List of resolved relations. + * + * @var array + */ + private $resolvedLinks; /** * @var bool */ @@ -603,6 +615,124 @@ public function cacheClear() $this->cache->clear(); } + /** + * Retrieve or resolve the relations. + * + * @param \stdClass $data + * @param array $queryString + */ + function getResolvedRelations($data, $queryString) + { + $this->resolvedRelations = []; + $relations = []; + + if (isset($data['rels'])) { + $relations = $data['rels']; + } elseif (isset($data['rel_uuids'])) { + $relSize = \count($data['rel_uuids']); + $chunks = []; + $chunkSize = 50; + + for ($i = 0; $i < $relSize; $i += $chunkSize) { + $end = min($relSize, $i + $chunkSize); + $chunks[] = \array_slice($data['rel_uuids'], $i, $end); + } + + for ($chunkIndex = 0; $chunkIndex < \count($chunks); ++$chunkIndex) { + $relationsParams = [ + 'per_page' => $chunkSize, + 'by_uuids' => implode(',', $chunks[$chunkIndex]), + ]; + if (isset($queryString['language'])) { + $relationsParams['language'] = $queryString['language']; + } + $relationsRes = $this->getStories($relationsParams); + + $relations = array_merge($relations, $relationsRes->responseBody['stories']); + } + } + + foreach ($relations as $rel) { + $this->resolvedRelations[$rel['uuid']] = $rel; + } + } + + /** + * Retrieve or resolve the Links. + * + * @param \stdClass $data + */ + function getResolvedLinks($data, array $queryString) + { + $this->resolvedLinks = []; + $links = []; + + if (isset($data['links'])) { + $links = $data['links']; + } elseif (isset($data['link_uuids'])) { + $linksSize = \count($data['link_uuids']); + $chunks = []; + $chunkSize = 50; + + for ($i = 0; $i < $linksSize; $i += $chunkSize) { + $end = min($linksSize, $i + $chunkSize); + $chunks[] = \array_slice($data['link_uuids'], $i, $end); + } + + for ($chunkIndex = 0; $chunkIndex < \count($chunks); ++$chunkIndex) { + $linksRes = $this->getStories([ + 'per_page' => $chunkSize, + 'language' => isset($queryString['language']) ? $queryString['language'] : 'default', + 'by_uuids' => implode(',', $chunks[$chunkIndex]), + ]); + + $links = array_merge($links, $linksRes->responseBody['stories']); + } + } + foreach ($links as $link) { + $this->resolvedLinks[$link['uuid']] = $link; + } + } + + /** + * Enrich the Stories with resolved links and stories. + * + * @param \stdClass $data + * + * @return \stdClass + */ + public function enrichContent($data) + { + $enrichedContent = $data; + + if (\is_array($data) && isset($data['component'])) { + if (!isset($data['_stopResolving'])) { + foreach ($data as $fieldName => $fieldValue) { + $enrichedContent[$fieldName] = $this->insertRelations($data['component'], $fieldName, $fieldValue); + $enrichedContent[$fieldName] = $this->insertLinks($enrichedContent[$fieldName]); + $enrichedContent[$fieldName] = $this->enrichContent($enrichedContent[$fieldName]); + } + } + } elseif (\is_array($data)) { + foreach ($data as $key => $value) { + $enrichedContent[$key] = $this->enrichContent($value); + } + } + + return $enrichedContent; + } + + public function responseHandler($responseObj, $queryString = []) + { + $result = parent::responseHandler($responseObj, $queryString); + + if (\is_array($result->httpResponseBody) && isset($result->httpResponseBody['story']) || isset($result->httpResponseBody['stories'])) { + $result->httpResponseBody = $this->enrichStories($result->httpResponseBody, $queryString); + } + + return $result; + } + /** * Gets a list of stories. * @@ -671,6 +801,79 @@ private function getStory($slug, $byUuid = false) return $this; } + private function enrichStories($data, $queryString) + { + $enrichedData = $data; + $this->getResolvedRelations($data, $queryString); + $this->getResolvedLinks($data, $queryString); + + if (isset($data['story'])) { + $enrichedData['story']['content'] = $this->enrichContent($data['story']['content']); + } elseif (isset($data['stories'])) { + $stories = []; + foreach ($data['stories'] as $index => $story) { + $story = $data['stories'][$index]; + $story['content'] = $this->enrichContent($story['content']); + $stories[] = $story; + } + $enrichedData['stories'] = $stories; + } + + return $enrichedData; + } + + /** + * Insert the resolved relations in a story. + * + * @param string $component + * @param string $field + * @param array|string $value + */ + private function insertRelations($component, $field, $value) + { + $filteredNode = $value; + if (isset($this->_relationsList[$component]) && $field === $this->_relationsList[$component]) { + if (\is_string($value)) { + if (isset($this->resolvedRelations[$value])) { + $filteredNode = $this->resolvedRelations[$value]; + $filteredNode['_stopResolving'] = true; + } + } elseif (\is_array($value)) { + $filteredNode = []; + foreach ($value as $item) { + if (\is_string($item) && isset($this->resolvedRelations[$item])) { + $story = $this->resolvedRelations[$item]; + $story['_stopResolving'] = true; + $filteredNode[] = $story; + } + } + } + } + + return $filteredNode; + } + + /** + * Insert the resolved links in a story. + * + * @param \stdClass $node + * + * @return \stdClass + */ + private function insertLinks($node) + { + $filteredNode = $node; + if (isset($node['fieldtype']) && 'multilink' === $node['fieldtype'] && 'story' === $node['linktype']) { + if (isset($node['id']) && \is_string($node['id']) && isset($this->resolvedLinks[$node['id']])) { + $filteredNode['story'] = $this->resolvedLinks[$node['id']]; + } elseif (isset($node['uuid']) && \is_string($node['uuid']) && isset($this->resolvedLinks[$node['uuid']])) { + $filteredNode['story'] = $this->resolvedLinks[$node['uuid']]; + } + } + + return $filteredNode; + } + /** * Automatically delete the cache of one item if client sends published parameter. * @@ -762,9 +965,7 @@ private function cacheGet(string $key) /** * Assigns the httpResponseBody and httpResponseHeader to '$this';. * - * @param array $response - * @param string $key - * @param string $version + * @param mixed $response */ private function _assignState($response) { @@ -776,10 +977,7 @@ private function _assignState($response) /** * prepares to Options for the cache key. Fixes some issues for too long filenames if filecache is used. * - * @param array $response - * @param string $key - * @param string $version - * @param mixed $options + * @param mixed $options */ private function _prepareOptionsForKey($options) { From b8e211f51c0d555925f181fe602457bcff1fe01b Mon Sep 17 00:00:00 2001 From: Roberto Butti Date: Fri, 16 Dec 2022 23:59:00 +0100 Subject: [PATCH 2/3] Add tests for resolve relations --- README.md | 9 + tests/Data/v2/stories-relations.json | 358 +++++++++++++++++++++ tests/Storyblok/ClientTest.php | 28 ++ tests/Storyblok/Integration/ClientTest.php | 14 +- 4 files changed, 402 insertions(+), 7 deletions(-) create mode 100644 tests/Data/v2/stories-relations.json diff --git a/README.md b/README.md index 0899b16..3e69108 100644 --- a/README.md +++ b/README.md @@ -452,6 +452,15 @@ $client->resolveRelations('component_name1.field_name1,component_name2.field_nam $client->getStoryBySlug('home'); ``` +Another example: + +```php +use Storyblok\Client; +$client = new Client('your-storyblok-private-token'); +$client->resolveRelations('popular-articles.articles'); +$result = $client->getStoryBySlug("home")->getBody(); +``` + In order to resolve links, you can use the `resolveLinks` method passing the specific type of resolving you want to perform among `url`, `story` or `link`: ```php diff --git a/tests/Data/v2/stories-relations.json b/tests/Data/v2/stories-relations.json new file mode 100644 index 0000000..127d84c --- /dev/null +++ b/tests/Data/v2/stories-relations.json @@ -0,0 +1,358 @@ +{ + "story": { + "name": "Home", + "created_at": "2022-08-08T06:05:15.980Z", + "published_at": "2022-09-02T11:08:48.787Z", + "id": 172977095, + "uuid": "6a88bcc1-9044-4dac-a1c0-afc2e6a26d6d", + "content": { + "_uid": "64fab05d-561c-4ff5-867c-a8d1aa78198a", + "body": [{ + "_uid": "f3ccc640-3902-4edc-9b88-3481faa97f28", + "layout": "full-width", + "headline": "My Blog Website", + "component": "hero", + "subheadline": "Welcome to my blog!", + "background_image": { + "id": 5301405, + "alt": "", + "name": "", + "focus": "", + "title": "", + "filename": "https://a.storyblok.com/f/166654/3500x2338/ec04ef8f35/hero.jpeg", + "copyright": "", + "fieldtype": "asset", + "is_external_url": false + } + }, { + "_uid": "716dd139-d270-446b-834d-d74b52d65d32", + "articles": ["997cfee2-cec3-4cad-9e06-7ef3d72f5b7d", "ba307a05-2b91-4ce8-ab24-bf328da1adb4", "c3a321a5-1163-4281-8643-2c79c13e22a3"], + "headline": "Popular Articles", + "component": "popular-articles" + }], + "component": "page" + }, + "slug": "home", + "full_slug": "home", + "sort_by_date": null, + "position": 0, + "tag_list": [], + "is_startpage": false, + "parent_id": 0, + "meta_data": null, + "group_id": "057fa20c-8439-47bc-b9e3-c7719e9dd3a4", + "first_published_at": "2022-07-17T06:24:25.863Z", + "release_id": null, + "lang": "default", + "path": "/", + "alternates": [], + "default_full_slug": null, + "translated_slugs": null + }, + "cv": 1667846352, + "rels": [{ + "name": "Article 1", + "created_at": "2022-08-08T06:11:19.146Z", + "published_at": "2022-09-02T09:51:11.060Z", + "id": 172977141, + "uuid": "997cfee2-cec3-4cad-9e06-7ef3d72f5b7d", + "content": { + "_uid": "feda96dd-65b0-4da1-9746-4834c7285e9e", + "image": { + "id": 5507332, + "alt": "", + "name": "", + "focus": "", + "title": "", + "filename": "https://a.storyblok.com/f/169999/6000x4000/087731406e/blog_one.jpeg", + "copyright": "", + "fieldtype": "asset", + "is_external_url": false + }, + "title": "Article One Heading", + "teaser": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus metus orci, interdum ac laoreet in, laoreet ut purus. Cras orci nulla, sagittis sit amet mauris vitae, volutpat finibus lorem. Vivamus suscipit odio fermentum augue interdum, vel imperdiet nibh venenatis. ", + "content": { + "type": "doc", + "content": [{ + "type": "paragraph", + "content": [{ + "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus metus orci, interdum ac laoreet in, laoreet ut purus. Cras orci nulla, sagittis sit amet mauris vitae, volutpat finibus lorem. Vivamus suscipit odio fermentum augue interdum, vel imperdiet nibh venenatis. Quisque iaculis tempor ornare. Cras rutrum ac nisi vel ornare. In hac habitasse platea dictumst. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed et ligula sagittis, dignissim mauris ac, rutrum tortor. Praesent tincidunt ultricies feugiat. Morbi sit amet felis at lacus semper accumsan sed sagittis neque. Ut consectetur mi non sollicitudin tempor. Vivamus dapibus ante tempus aliquam molestie. Nunc at malesuada quam. Suspendisse dictum sapien in posuere congue. Etiam eget sapien sit amet metus condimentum vehicula sit amet a velit. Fusce vulputate consectetur augue quis rhoncus.", + "type": "text" + }] + }, { + "type": "paragraph", + "content": [{ + "text": "Suspendisse nisi nunc, maximus quis interdum ut, aliquam id urna. Donec in orci auctor nunc iaculis sollicitudin nec eget metus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec ultricies eros odio, nec sodales lacus rutrum nec. Phasellus quis vestibulum nisi, non dapibus nulla. Mauris libero enim, semper sed ultrices mollis, faucibus ac nisi. Mauris lorem ex, porta ac gravida nec, feugiat id tortor. Vestibulum ut metus posuere, pellentesque tellus at, interdum nibh. Cras tincidunt bibendum vestibulum. Mauris tristique sem at tellus facilisis hendrerit. Nam a lacus posuere, accumsan augue non, auctor sem. Etiam suscipit metus ut mi eleifend dapibus ut vel augue.", + "type": "text" + }] + }, { + "type": "paragraph", + "content": [{ + "text": "Suspendisse dui dui, tristique id justo ut, auctor consequat nunc. Nam nunc eros, rutrum eget dolor eu, lacinia fermentum ipsum. Curabitur dapibus metus quis interdum faucibus. Aenean eu iaculis nunc. Mauris turpis nunc, imperdiet quis efficitur non, eleifend imperdiet nulla. Suspendisse eget commodo diam. Integer tempor varius tellus, sed feugiat diam tincidunt in. Donec bibendum vitae nisl in hendrerit. Nullam est orci, pellentesque non orci id, congue finibus erat. Mauris porttitor bibendum porttitor. In hac habitasse platea dictumst. Aenean cursus volutpat justo, in facilisis lorem imperdiet ut. Donec malesuada orci non leo rutrum sollicitudin. Nulla erat nisi, tincidunt eu accumsan id, pretium id ante. Phasellus pharetra felis vel risus euismod egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", + "type": "text" + }] + }, { + "type": "paragraph", + "content": [{ + "text": "Nunc consectetur ac augue ac scelerisque. Vestibulum pellentesque nisl non faucibus rhoncus. Nullam a porta augue. Aenean et tincidunt dui. In vel arcu nulla. Vestibulum a libero vitae risus feugiat ultrices id a eros. Curabitur fringilla velit et lobortis condimentum. Quisque lectus sapien, consequat vitae erat vitae, pretium egestas eros. Suspendisse id pellentesque dui. Quisque erat nibh, eleifend vel bibendum non, commodo malesuada lorem. Morbi non dapibus justo. Aenean tortor elit, aliquet vitae tellus sed, facilisis placerat sapien. Nam efficitur, lorem nec convallis tempor, enim nibh hendrerit libero, faucibus sollicitudin lacus ipsum at arcu. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", + "type": "text" + }] + }, { + "type": "paragraph", + "content": [{ + "text": "Donec aliquam hendrerit egestas. Fusce et venenatis est. Nullam convallis felis urna, nec varius erat pellentesque vitae. Vestibulum rutrum bibendum egestas. Nam accumsan egestas felis. Phasellus iaculis elementum tortor, quis viverra nunc sagittis a. Donec tincidunt convallis urna.", + "type": "text" + }] + }] + }, + "subtitle": "Phasellus metus orci, interdum ac laoreet in", + "component": "article" + }, + "slug": "article-1", + "full_slug": "blog/article-1", + "sort_by_date": null, + "position": 0, + "tag_list": [], + "is_startpage": false, + "parent_id": 172977134, + "meta_data": null, + "group_id": "308974eb-31fc-4ce6-a309-469ae2a0f378", + "first_published_at": "2022-08-08T06:12:44.073Z", + "release_id": null, + "lang": "default", + "path": null, + "alternates": [{ + "id": 172977145, + "name": "Article 2", + "slug": "article-2", + "published": true, + "full_slug": "blog/article-2", + "is_folder": false, + "parent_id": 172977134 + }, { + "id": 172977146, + "name": "Article 3", + "slug": "article-3", + "published": true, + "full_slug": "blog/article-3", + "is_folder": false, + "parent_id": 172977134 + }, { + "id": 172977147, + "name": "Article 4", + "slug": "article-4", + "published": true, + "full_slug": "blog/article-4", + "is_folder": false, + "parent_id": 172977134 + }], + "default_full_slug": null, + "translated_slugs": null + }, { + "name": "Article 2", + "created_at": "2022-08-08T06:12:30.820Z", + "published_at": "2022-09-02T09:51:14.414Z", + "id": 172977145, + "uuid": "c3a321a5-1163-4281-8643-2c79c13e22a3", + "content": { + "_uid": "feda96dd-65b0-4da1-9746-4834c7285e9e", + "image": { + "id": 5507331, + "alt": "", + "name": "", + "focus": "", + "title": "", + "filename": "https://a.storyblok.com/f/169999/4518x3388/27e6eb91da/blog_two.jpeg", + "copyright": "", + "fieldtype": "asset", + "is_external_url": false + }, + "title": "Article Two Heading", + "teaser": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus metus orci, interdum ac laoreet in, laoreet ut purus. Cras orci nulla, sagittis sit amet mauris vitae.", + "content": { + "type": "doc", + "content": [{ + "type": "paragraph", + "content": [{ + "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus metus orci, interdum ac laoreet in, laoreet ut purus. Cras orci nulla, sagittis sit amet mauris vitae, volutpat finibus lorem. Vivamus suscipit odio fermentum augue interdum, vel imperdiet nibh venenatis. Quisque iaculis tempor ornare. Cras rutrum ac nisi vel ornare. In hac habitasse platea dictumst. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed et ligula sagittis, dignissim mauris ac, rutrum tortor. Praesent tincidunt ultricies feugiat. Morbi sit amet felis at lacus semper accumsan sed sagittis neque. Ut consectetur mi non sollicitudin tempor. Vivamus dapibus ante tempus aliquam molestie. Nunc at malesuada quam. Suspendisse dictum sapien in posuere congue. Etiam eget sapien sit amet metus condimentum vehicula sit amet a velit. Fusce vulputate consectetur augue quis rhoncus.", + "type": "text" + }] + }, { + "type": "paragraph", + "content": [{ + "text": "Suspendisse nisi nunc, maximus quis interdum ut, aliquam id urna. Donec in orci auctor nunc iaculis sollicitudin nec eget metus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec ultricies eros odio, nec sodales lacus rutrum nec. Phasellus quis vestibulum nisi, non dapibus nulla. Mauris libero enim, semper sed ultrices mollis, faucibus ac nisi. Mauris lorem ex, porta ac gravida nec, feugiat id tortor. Vestibulum ut metus posuere, pellentesque tellus at, interdum nibh. Cras tincidunt bibendum vestibulum. Mauris tristique sem at tellus facilisis hendrerit. Nam a lacus posuere, accumsan augue non, auctor sem. Etiam suscipit metus ut mi eleifend dapibus ut vel augue.", + "type": "text" + }] + }, { + "type": "paragraph", + "content": [{ + "text": "Suspendisse dui dui, tristique id justo ut, auctor consequat nunc. Nam nunc eros, rutrum eget dolor eu, lacinia fermentum ipsum. Curabitur dapibus metus quis interdum faucibus. Aenean eu iaculis nunc. Mauris turpis nunc, imperdiet quis efficitur non, eleifend imperdiet nulla. Suspendisse eget commodo diam. Integer tempor varius tellus, sed feugiat diam tincidunt in. Donec bibendum vitae nisl in hendrerit. Nullam est orci, pellentesque non orci id, congue finibus erat. Mauris porttitor bibendum porttitor. In hac habitasse platea dictumst. Aenean cursus volutpat justo, in facilisis lorem imperdiet ut. Donec malesuada orci non leo rutrum sollicitudin. Nulla erat nisi, tincidunt eu accumsan id, pretium id ante. Phasellus pharetra felis vel risus euismod egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", + "type": "text" + }] + }, { + "type": "paragraph", + "content": [{ + "text": "Nunc consectetur ac augue ac scelerisque. Vestibulum pellentesque nisl non faucibus rhoncus. Nullam a porta augue. Aenean et tincidunt dui. In vel arcu nulla. Vestibulum a libero vitae risus feugiat ultrices id a eros. Curabitur fringilla velit et lobortis condimentum. Quisque lectus sapien, consequat vitae erat vitae, pretium egestas eros. Suspendisse id pellentesque dui. Quisque erat nibh, eleifend vel bibendum non, commodo malesuada lorem. Morbi non dapibus justo. Aenean tortor elit, aliquet vitae tellus sed, facilisis placerat sapien. Nam efficitur, lorem nec convallis tempor, enim nibh hendrerit libero, faucibus sollicitudin lacus ipsum at arcu. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", + "type": "text" + }] + }, { + "type": "paragraph", + "content": [{ + "text": "Donec aliquam hendrerit egestas. Fusce et venenatis est. Nullam convallis felis urna, nec varius erat pellentesque vitae. Vestibulum rutrum bibendum egestas. Nam accumsan egestas felis. Phasellus iaculis elementum tortor, quis viverra nunc sagittis a. Donec tincidunt convallis urna.", + "type": "text" + }] + }] + }, + "subtitle": "Phasellus metus orci, interdum ac laoreet in", + "component": "article" + }, + "slug": "article-2", + "full_slug": "blog/article-2", + "sort_by_date": null, + "position": 0, + "tag_list": [], + "is_startpage": false, + "parent_id": 172977134, + "meta_data": null, + "group_id": "308974eb-31fc-4ce6-a309-469ae2a0f378", + "first_published_at": "2022-08-08T06:12:40.888Z", + "release_id": null, + "lang": "default", + "path": null, + "alternates": [{ + "id": 172977141, + "name": "Article 1", + "slug": "article-1", + "published": true, + "full_slug": "blog/article-1", + "is_folder": false, + "parent_id": 172977134 + }, { + "id": 172977146, + "name": "Article 3", + "slug": "article-3", + "published": true, + "full_slug": "blog/article-3", + "is_folder": false, + "parent_id": 172977134 + }, { + "id": 172977147, + "name": "Article 4", + "slug": "article-4", + "published": true, + "full_slug": "blog/article-4", + "is_folder": false, + "parent_id": 172977134 + }], + "default_full_slug": null, + "translated_slugs": null + }, { + "name": "Article 4", + "created_at": "2022-08-08T06:13:05.423Z", + "published_at": "2022-09-02T11:21:37.025Z", + "id": 172977147, + "uuid": "ba307a05-2b91-4ce8-ab24-bf328da1adb4", + "content": { + "_uid": "feda96dd-65b0-4da1-9746-4834c7285e9e", + "image": { + "id": 5507333, + "alt": "", + "name": "", + "focus": "", + "title": "", + "filename": "https://a.storyblok.com/f/169999/4395x2933/40ddf50d47/blog_four.jpeg", + "copyright": "", + "fieldtype": "asset", + "is_external_url": false + }, + "title": "Article Four Heading", + "teaser": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus metus orci, interdum ac laoreet in, laoreet ut purus. Cras orci nulla, sagittis sit amet mauris vitae, volutpat finibus lorem. Vivamus suscipit odio fermentum augue interdum, vel imperdiet nibh venenatis. ", + "content": { + "type": "doc", + "content": [{ + "type": "paragraph", + "content": [{ + "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ", + "type": "text" + }, { + "text": "Phasellus metus", + "type": "text", + "marks": [{ + "type": "bold" + }] + }, { + "text": " orci, interdum ac laoreet in, laoreet ut purus. Cras orci nulla, sagittis sit amet mauris vitae, volutpat finibus lorem. Vivamus suscipit odio fermentum augue interdum, vel imperdiet nibh venenatis. Quisque iaculis tempor ornare. Cras rutrum ac nisi vel ornare. In hac habitasse platea dictumst. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed et ligula sagittis, dignissim mauris ac, rutrum tortor. Praesent tincidunt ultricies feugiat. Morbi sit amet felis at lacus semper accumsan sed sagittis neque. Ut consectetur mi non sollicitudin tempor. Vivamus dapibus ante tempus aliquam molestie. Nunc at malesuada quam. Suspendisse dictum sapien in posuere congue. Etiam eget sapien sit amet metus condimentum vehicula sit amet a velit. Fusce vulputate consectetur augue quis rhoncus.", + "type": "text" + }] + }, { + "type": "paragraph", + "content": [{ + "text": "Suspendisse nisi nunc, maximus quis interdum ut, aliquam id urna. Donec in orci auctor nunc iaculis sollicitudin nec eget metus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec ultricies eros odio, nec sodales lacus rutrum nec. Phasellus quis vestibulum nisi, non dapibus nulla. Mauris libero enim, semper sed ultrices mollis, faucibus ac nisi. Mauris lorem ex, porta ac gravida nec, feugiat id tortor. Vestibulum ut metus posuere, pellentesque tellus at, interdum nibh. Cras tincidunt bibendum vestibulum. Mauris tristique sem at tellus facilisis hendrerit. Nam a lacus posuere, accumsan augue non, auctor sem. Etiam suscipit metus ut mi eleifend dapibus ut vel augue.", + "type": "text" + }] + }, { + "type": "paragraph", + "content": [{ + "text": "Suspendisse dui dui, tristique id justo ut, auctor consequat nunc. Nam nunc eros, rutrum eget dolor eu, lacinia fermentum ipsum. Curabitur dapibus metus quis interdum faucibus. Aenean eu iaculis nunc. Mauris turpis nunc, imperdiet quis efficitur non, eleifend imperdiet nulla. Suspendisse eget commodo diam. Integer tempor varius tellus, sed feugiat diam tincidunt in. Donec bibendum vitae nisl in hendrerit. Nullam est orci, pellentesque non orci id, congue finibus erat. Mauris porttitor bibendum porttitor. In hac habitasse platea dictumst. Aenean cursus volutpat justo, in facilisis lorem imperdiet ut. Donec malesuada orci non leo rutrum sollicitudin. Nulla erat nisi, tincidunt eu accumsan id, pretium id ante. Phasellus pharetra felis vel risus euismod egestas. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", + "type": "text" + }] + }, { + "type": "paragraph", + "content": [{ + "text": "Nunc consectetur ac augue ac scelerisque. Vestibulum pellentesque nisl non faucibus rhoncus. Nullam a porta augue. Aenean et tincidunt dui. In vel arcu nulla. Vestibulum a libero vitae risus feugiat ultrices id a eros. Curabitur fringilla velit et lobortis condimentum. Quisque lectus sapien, consequat vitae erat vitae, pretium egestas eros. Suspendisse id pellentesque dui. Quisque erat nibh, eleifend vel bibendum non, commodo malesuada lorem. Morbi non dapibus justo. Aenean tortor elit, aliquet vitae tellus sed, facilisis placerat sapien. Nam efficitur, lorem nec convallis tempor, enim nibh hendrerit libero, faucibus sollicitudin lacus ipsum at arcu. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.", + "type": "text" + }] + }, { + "type": "paragraph", + "content": [{ + "text": "Donec aliquam hendrerit egestas. Fusce et venenatis est. Nullam convallis felis urna, nec varius erat pellentesque vitae. Vestibulum rutrum bibendum egestas. Nam accumsan egestas felis. Phasellus iaculis elementum tortor, quis viverra nunc sagittis a. Donec tincidunt convallis urna.", + "type": "text" + }] + }] + }, + "subtitle": "Phasellus metus orci, interdum ac laoreet in", + "component": "article" + }, + "slug": "article-4", + "full_slug": "blog/article-4", + "sort_by_date": null, + "position": 0, + "tag_list": [], + "is_startpage": false, + "parent_id": 172977134, + "meta_data": null, + "group_id": "308974eb-31fc-4ce6-a309-469ae2a0f378", + "first_published_at": "2022-08-08T06:12:44.073Z", + "release_id": null, + "lang": "default", + "path": null, + "alternates": [{ + "id": 172977141, + "name": "Article 1", + "slug": "article-1", + "published": true, + "full_slug": "blog/article-1", + "is_folder": false, + "parent_id": 172977134 + }, { + "id": 172977145, + "name": "Article 2", + "slug": "article-2", + "published": true, + "full_slug": "blog/article-2", + "is_folder": false, + "parent_id": 172977134 + }, { + "id": 172977146, + "name": "Article 3", + "slug": "article-3", + "published": true, + "full_slug": "blog/article-3", + "is_folder": false, + "parent_id": 172977134 + }], + "default_full_slug": null, + "translated_slugs": null + }], + "links": [] +} \ No newline at end of file diff --git a/tests/Storyblok/ClientTest.php b/tests/Storyblok/ClientTest.php index 560d87e..655226f 100644 --- a/tests/Storyblok/ClientTest.php +++ b/tests/Storyblok/ClientTest.php @@ -138,6 +138,34 @@ $this->assertArrayHasKey('links', $story); }); +test('v2: get stories with Relations', function () { + $client = new Client('test', null, $version = 'v2'); + // $client->editMode(false); + $client->mockable([ + mockResponse('stories-relations', ['x-test' => 1], $version), + ]); + $client->resolveRelations('popular-articles.articles'); + $story = $client->getStoryBySlug('home')->getBody(); + $this->assertArrayHasKey('story', $story); + $this->assertEquals('Home', $story['story']['name']); + $this->assertCount( + 3, + $story['story']['content']['body'][1]['articles'] + ); + $this->assertEquals( + 'Article 1', + $story['story']['content']['body'][1]['articles'][0]['name'] + ); + $this->assertEquals( + 'Article 4', + $story['story']['content']['body'][1]['articles'][1]['name'] + ); + $this->assertEquals( + 'Article 2', + $story['story']['content']['body'][1]['articles'][2]['name'] + ); +}); + test('v1: get tags', function () { $client = new Client('test', $endpoint = 'tags', $version = 'v1'); $client->mockable([ diff --git a/tests/Storyblok/Integration/ClientTest.php b/tests/Storyblok/Integration/ClientTest.php index 0b24778..e2eef45 100644 --- a/tests/Storyblok/Integration/ClientTest.php +++ b/tests/Storyblok/Integration/ClientTest.php @@ -8,7 +8,7 @@ $this->assertArrayHasKey('space', $space->httpResponseBody); $this->assertCount(5, $space->httpResponseBody['space']); $this->assertEquals('40101', $space->httpResponseBody['space']['id']); -})->setGroups(['integration']); +})->group('integration'); test('Integration: get All stories', function () { $client = new Client('Iw3XKcJb6MwkdZEwoQ9BCQtt'); @@ -16,14 +16,14 @@ $options['per_page'] = 3; $stories = $client->getAll('stories/', $options); $this->assertCount(8, $stories); -})->setGroups(['integration']); +})->group('integration'); test('Integration: get All stories with default pagination', function () { $client = new Client('Iw3XKcJb6MwkdZEwoQ9BCQtt'); $options = $client->getApiParameters(); $stories = $client->getAll('stories/', $options); $this->assertCount(8, $stories); -})->setGroups(['integration']); +})->group('integration'); test('Integration: get All responses stories', function () { $client = new Client('Iw3XKcJb6MwkdZEwoQ9BCQtt'); @@ -31,7 +31,7 @@ $options['per_page'] = 3; $responses = $client->getAll('stories/', $options, true); $this->assertCount(3, $responses); -})->setGroups(['integration']); +})->group('integration'); // useful for testing and reproduce the issue: https://github.com/storyblok/php-client/issues/54 /* @@ -45,7 +45,7 @@ $this->assertArrayHasKey('story', $body); $this->assertArrayHasKey('name', $body['story']); $this->assertEquals('home', $body['story']['name']); -})->setGroups(['integration']); +})->group('integration'); */ test('Integration: get one story with _storyblok_published', function () { @@ -57,11 +57,11 @@ $this->assertArrayHasKey('story', $body); $this->assertArrayHasKey('name', $body['story']); $this->assertEquals('home', $body['story']['name']); -})->setGroups(['integration']); +})->group('integration'); test('Integration: get All responses stories with default pagination', function () { $client = new Client('Iw3XKcJb6MwkdZEwoQ9BCQtt'); $options = $client->getApiParameters(); $responses = $client->getAll('stories/', $options, true); $this->assertCount(1, $responses); -})->setGroups(['integration']); +})->group('integration'); From 64ff83b2c38234019c6e264338149c1356a4b6c2 Mon Sep 17 00:00:00 2001 From: Roberto Butti Date: Sat, 17 Dec 2022 08:15:19 +0100 Subject: [PATCH 3/3] adding test for sorting relations Because the refactoring for reaching level 2 of phpstan involves the resolve relations function, I added more tests for that (for checking if, during the elaboration, it is to keep the order of the relations (because it is very important). This test is related to the issue (it is not an issue, is more a clarification): #76 --- tests/Storyblok/ClientTest.php | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/Storyblok/ClientTest.php b/tests/Storyblok/ClientTest.php index 655226f..dcce15c 100644 --- a/tests/Storyblok/ClientTest.php +++ b/tests/Storyblok/ClientTest.php @@ -166,6 +166,35 @@ ); }); +test('v2: check sorting for relations', function () { + $client = new Client('test', null, $version = 'v2'); + // $client->editMode(false); + $client->mockable([ + mockResponse('stories-relations', ['x-test' => 1], $version), + ]); + $client->resolveRelations('popular-articles.articles'); + $story = $client->getStoryBySlug('home')->getBody(); + $this->assertArrayHasKey('story', $story); + $this->assertArrayHasKey('rels', $story); + // With the dataset provided the right order should be + // ["997cfee2-cec3-4cad-9e06-7ef3d72f5b7d", "ba307a05-2b91-4ce8-ab24-bf328da1adb4", "c3a321a5-1163-4281-8643-2c79c13e22a3"] + $this->assertEquals( + '997cfee2-cec3-4cad-9e06-7ef3d72f5b7d', + $story['story']['content']['body'][1]['articles'][0]['uuid'], + 'checking the first relation' + ); + $this->assertEquals( + 'ba307a05-2b91-4ce8-ab24-bf328da1adb4', + $story['story']['content']['body'][1]['articles'][1]['uuid'], + 'checking the second relation' + ); + $this->assertEquals( + 'c3a321a5-1163-4281-8643-2c79c13e22a3', + $story['story']['content']['body'][1]['articles'][2]['uuid'], + 'checking the third relation' + ); +}); + test('v1: get tags', function () { $client = new Client('test', $endpoint = 'tags', $version = 'v1'); $client->mockable([