sensiolabs-de / storyblok-api
API for Storyblok
Installs: 17 244
Dependents: 1
Suggesters: 0
Security: 0
Stars: 5
Watchers: 2
Forks: 1
Open Issues: 1
Requires
- php: >=8.3
- oskarstark/enum-helper: ^1.5
- oskarstark/trimmed-non-empty-string: ^1.1
- psr/log: ^3.0
- symfony/cache: ^7.0
- symfony/cache-contracts: ^3.5
- symfony/http-client: ^6.0 || ^7.0
- thecodingmachine/safe: ^2.0
- webmozart/assert: ^1.11
Requires (Dev)
- ergebnis/composer-normalize: ^2.2
- ergebnis/data-provider: ^3.2
- ergebnis/php-cs-fixer-config: ^6.28
- ergebnis/test-util: ^1.5
- phpstan/extension-installer: ^1.0
- phpstan/phpstan: ^1.0
- phpstan/phpstan-webmozart-assert: ^1.0
- phpunit/phpunit: ^9.0
- thecodingmachine/phpstan-safe-rule: ^1.0
- dev-master
- 3.5.0
- 3.4.0
- 3.3.2
- 3.3.1
- 3.3.0
- 3.2.0
- 3.1.0
- 3.0.0
- 2.x-dev
- 2.4.0
- 2.3.1
- 2.3.0
- 2.2.0
- 2.1.1
- 2.1.0
- 2.0.0
- 1.6.1
- 1.6.0
- 1.5.0
- 1.4.1
- 1.4.0
- 1.3.4
- 1.3.3
- 1.3.2
- 1.3.1
- 1.3.0
- 1.2.4
- 1.2.3
- 1.2.2
- 1.2.1
- 1.2.0
- 1.1.1
- 1.1.0
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
- dev-dependabot/github_actions/codecov/codecov-action-5.1.1
- dev-feature/adds-version-for-get-action
This package is auto-updated.
Last update: 2024-12-14 20:57:00 UTC
README
Symfony
Use the symfony bundle sensiolabs-de/storyblok-bundle to integrate this library into your Symfony application.
Usage
Installation
composer require sensiolabs-de/storyblok-api
Setup
use SensioLabs\Storyblok\Api\StoryblokClient; $client = new StoryblokClient( baseUri: 'https://api.storyblok.com', token: '***********', timeout: 10 // optional ); // you can now request any endpoint which needs authentication $client->request('GET', '/api/something', $options);
Spaces
In your code you should type-hint to SensioLabs\Storyblok\Api\SpacesApiInterface
Get the current space
Returns the space associated with the current token.
use SensioLabs\Storyblok\Api\SpacesApi; use SensioLabs\Storyblok\Api\StoryblokClient; $client = new StoryblokClient(/* ... */); $spacesApi = new SpacesApi($client); $response = $spacesApi->me();
Stories
In your code you should type-hint to SensioLabs\Storyblok\Api\StoriesApiInterface
Get all available stories
use SensioLabs\Storyblok\Api\StoriesApi; use SensioLabs\Storyblok\Api\StoryblokClient; $client = new StoryblokClient(/* ... */); $storiesApi = new StoriesApi($client); $response = $storiesApi->all(locale: 'de');
Fetch by Version (draft
, published
)
Global
use SensioLabs\Storyblok\Api\StoriesApi; use SensioLabs\Storyblok\Api\StoryblokClient; use SensioLabs\Storyblok\Api\Domain\Value\Dto\Version; $client = new StoryblokClient(/* ... */); $storiesApi = new StoriesApi($client, Version::Draft); $response = $storiesApi->bySlug( locale: 'de', slug: '/my-story/', );
Method Call
use SensioLabs\Storyblok\Api\StoriesApi; use SensioLabs\Storyblok\Api\StoryblokClient; use SensioLabs\Storyblok\Api\Domain\Value\Dto\Version; $client = new StoryblokClient(/* ... */); $storiesApi = new StoriesApi($client, Version::Published); $response = $storiesApi->bySlug( locale: 'de', slug: '/my-story/', version: Version::Draft, // This overrides the global "version" );
Pagination
use SensioLabs\Storyblok\Api\StoriesApi; use SensioLabs\Storyblok\Api\StoryblokClient; use SensioLabs\Storyblok\Api\Domain\Value\Dto\Pagination; $client = new StoryblokClient(/* ... */); $storiesApi = new StoriesApi($client); $response = $storiesApi->all( locale: 'de', pagination: new Pagination(page: 1, perPage: 30) );
Sorting
use SensioLabs\Storyblok\Api\StoriesApi; use SensioLabs\Storyblok\Api\StoryblokClient; use SensioLabs\Storyblok\Api\Domain\Value\Dto\SortBy; use SensioLabs\Storyblok\Api\Domain\Value\Dto\Direction; $client = new StoryblokClient(/* ... */); $storiesApi = new StoriesApi($client); $response = $storiesApi->all( locale: 'de', sortBy: new SortBy(field: 'title', direction: Direction::Desc) );
Filtering
use SensioLabs\Storyblok\Api\StoriesApi; use SensioLabs\Storyblok\Api\StoryblokClient; use SensioLabs\Storyblok\Api\Domain\Value\Filter\FilterCollection; use SensioLabs\Storyblok\Api\Domain\Value\Dto\Direction; use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\InFilter; $client = new StoryblokClient(/* ... */); $storiesApi = new StoriesApi($client); $response = $storiesApi->all( locale: 'de', filters: new FilterCollection([ new InFilter(field: 'single_reference_field', value: 'f2fdb571-a265-4d8a-b7c5-7050d23c2383') ]) );
Available filters
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\AllInArrayFilter; new AllInArrayFilter(field: 'tags', value: ['foo', 'bar', 'baz']);
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\AnyInArrayFilter; new AnyInArrayFilter(field: 'tags', value: ['foo', 'bar', 'baz']);
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\GreaterThanDateFilter; new GreaterThanDateFilter(field: 'created_at', value: new \DateTimeImmutable());
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\LessThanDateFilter; new LessThanDateFilter(field: 'created_at', value: new \DateTimeImmutable());
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\GreaterThanFloatFilter; new GreaterThanFloatFilter(field: 'price', value: 39.99);
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\LessThanFloatFilter; new LessThanFloatFilter(field: 'price', value: 199.99);
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\GreaterThanIntFilter; new GreaterThanIntFilter(field: 'stock', value: 0);
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\LessThanIntFilter; new LessThanIntFilter(field: 'stock', value: 100);
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\InFilter; new InFilter(field: 'text', value: 'Hello World!'); // or new InFilter(field: 'text', value: ['Hello Symfony!', 'Hello SensioLabs!']);
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\NotInFilter; new NotInFilter(field: 'text', value: 'Hello World!'); // or new NotInFilter(field: 'text', value: ['Bye Symfony!', 'Bye SensioLabs!']);
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\IsFilter; // You can use one of the following constants: // IsFilter::EMPTY_ARRAY // IsFilter::NOT_EMPTY_ARRAY // IsFilter::EMPTY // IsFilter::NOT_EMPTY // IsFilter::TRUE // IsFilter::FALSE // IsFilter::NULL // IsFilter::NOT_NULL new IsFilter(field: 'text', value: IsFilter::EMPTY);
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\LikeFilter; new LikeFilter(field: 'description', value: '*I love Symfony*');
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\NotLikeFilter; new NotLikeFilter(field: 'description', value: '*Text*');
Example:
use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\OrFilter; use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\LikeFilter; use SensioLabs\Storyblok\Api\Domain\Value\Filter\Filters\NotLikeFilter; new OrFilter( new LikeFilter(field: 'text', value: 'Yes!*'), new LikeFilter(field: 'text', value: 'Maybe!*'), // ... );
Get all available stories by Content Type (string
)
use SensioLabs\Storyblok\Api\StoriesApi; use SensioLabs\Storyblok\Api\StoryblokClient; $client = new StoryblokClient(/* ... */); $storiesApi = new StoriesApi($client); $response = $storiesApi->allByContentType('custom_content_type', locale: 'de');
Get by uuid (SensioLabs\Storyblok\Api\Domain\Value\Uuid
)
use SensioLabs\Storyblok\Api\StoriesApi; use SensioLabs\Storyblok\Api\StoryblokClient; use SensioLabs\Storyblok\Api\Domain\Value\Uuid; $uuid = new Uuid(/** ... */); $client = new StoryblokClient(/* ... */); $storiesApi = new StoriesApi($client); $response = $storiesApi->byUuid($uuid, locale: 'de');
Get by slug (string
)
use SensioLabs\Storyblok\Api\StoriesApi; use SensioLabs\Storyblok\Api\StoryblokClient; $client = new StoryblokClient(/* ... */); $storiesApi = new StoriesApi($client); $response = $storiesApi->bySlug('folder/slug', locale: 'de');
Get by id (SensioLabs\Storyblok\Api\Domain\Value\Id
)
use SensioLabs\Storyblok\Api\StoriesApi; use SensioLabs\Storyblok\Api\StoryblokClient; use SensioLabs\Storyblok\Api\Domain\Value\Id; $id = new Id(/** ... */); $client = new StoryblokClient(/* ... */); $storiesApi = new StoriesApi($client); $response = $storiesApi->byId($id, locale: 'de');
Links
In your code you should type-hint to SensioLabs\Storyblok\Api\LinksApiInterface
Get all available links
use SensioLabs\Storyblok\Api\LinksApi; use SensioLabs\Storyblok\Api\StoryblokClient; $client = new StoryblokClient(/* ... */); $linksApi = new LinksApi($client); $response = $linksApi->all();
Pagination
use SensioLabs\Storyblok\Api\LinksApi; use SensioLabs\Storyblok\Api\StoryblokClient; use SensioLabs\Storyblok\Api\Domain\Value\Dto\Pagination; $client = new StoryblokClient(/* ... */); $linksApi = new LinksApi($client); $response = $linksApi->all( pagination: new Pagination(page: 1, perPage: 1000) );
Get by parent (SensioLabs\Storyblok\Api\Domain\Value\Id
)
use SensioLabs\Storyblok\Api\LinksApi; use SensioLabs\Storyblok\Api\StoryblokClient; use SensioLabs\Storyblok\Api\Domain\Value\Id; $id = new Id(/** ... */); $client = new StoryblokClient(/* ... */); $linksApi = new LinksApi($client); $response = $linksApi->byParent($id);
Get all root links
use SensioLabs\Storyblok\Api\LinksApi; use SensioLabs\Storyblok\Api\StoryblokClient; $client = new StoryblokClient(/* ... */); $linksApi = new LinksApi($client); $response = $linksApi->roots($id);
Datasource
In your code you should type-hint to SensioLabs\Storyblok\Api\DatasourceApiInterface
Get by name (string
)
use SensioLabs\Storyblok\Api\DatasourceApi; use SensioLabs\Storyblok\Api\StoryblokClient; $client = new StoryblokClient(/* ... */); $api = new DatasourceApi($client); $response = $api->byName('tags'); // returns SensioLabs\Storyblok\Api\Domain\Value\Datasource
If it has more than one dimension, you can get the entries by
use SensioLabs\Storyblok\Api\DatasourceApi; use SensioLabs\Storyblok\Api\StoryblokClient; use SensioLabs\Storyblok\Api\Domain\Value\Datasource\Dimension; $client = new StoryblokClient(/* ... */); $api = new DatasourceApi($client); $response = $api->byName('tags', new Dimension('de')); // returns SensioLabs\Storyblok\Api\Domain\Value\Datasource
Tags
In your code you should type-hint to SensioLabs\Storyblok\Api\TagsApiInterface
Get all available tags
use SensioLabs\Storyblok\Api\TagsApi; use SensioLabs\Storyblok\Api\StoryblokClient; $client = new StoryblokClient(/* ... */); $api = new TagsApi($client); $response = $api->all(); // returns SensioLabs\Storyblok\Api\Response\TagsResponse
Assets
To use the assets API you have to configure the Assets client.
use SensioLabs\Storyblok\Api\StoryblokClient; use SensioLabs\Storyblok\Api\AssetsApi; $client = new StoryblokClient( baseUri: 'https://api.storyblok.com', token: 'assets-api-token', timeout: 10 // optional ); $assetsApi = new AssetsApi($assetsClient); $assetsApi->get('filename.png')
DX Enhancement through Abstract Collections
To improve developer experience (DX), especially when working with content types like stories, the following abstract class is provided to manage collections of specific content types. This class simplifies data handling and ensures type safety while dealing with large amounts of content from Storyblok.
Abstract ContentTypeCollection Class
The ContentTypeCollection class provides a structured way to work with Storyblok content types. It makes managing pagination, filtering, and sorting more intuitive and reusable, saving time and reducing boilerplate code.
<?php declare(strict_types=1); namespace App\ContentType; use IteratorAggregate; use SensioLabs\Storyblok\Api\Response\StoriesResponse; /** * @template T of ContentTypeInterface * * @implements IteratorAggregate<int, T> */ abstract readonly class ContentTypeCollection implements \Countable, \IteratorAggregate { public int $total; public int $perPage; public int $curPage; public int $lastPage; public ?int $prevPage; public ?int $nextPage; /** * @var list<T> */ private array $items; final public function __construct(StoriesResponse $response) { $this->items = array_values(array_map($this->createItem(...), $response->stories)); $this->total = $response->total->value; $this->curPage = $response->pagination->page; $this->perPage = $response->pagination->perPage; $this->lastPage = (int) ceil($this->total / $this->perPage); $this->prevPage = 1 < $this->curPage ? $this->curPage - 1 : null; $this->nextPage = $this->curPage < $this->lastPage ? $this->curPage + 1 : null; } /** * @return \Traversable<int, T> */ final public function getIterator(): \Traversable { return new \ArrayIterator($this->items); } final public function count(): int { return \count($this->items); } /** * @param array<string, mixed> $values * * @return T */ abstract protected function createItem(array $values): ContentTypeInterface; }
Benefits of Using the Abstract Collection:
- Simplified Data Handling: Instead of dealing with raw arrays of stories, this abstract class helps you manage collections of content types, like blog posts or articles, in an organized manner. It abstracts away the repetitive work of pagination and mapping response data to objects.
- Enhanced Readability: Using a well-structured collection class makes the code easier to read and maintain. Instead of handling pagination and raw data structures in controllers or services, you simply instantiate the collection and let it handle the data.
- Reusability: The class is flexible and reusable across different content types. Once implemented, you can easily create new collections for other Storyblok content types with minimal extra code.
- Pagination and Metadata Management: The collection class comes with built-in properties for pagination and metadata (e.g., total items, current page, etc.), making it much easier to manage paginated data efficiently.
Example Usage with a Collection
Here is an example of how to use the ContentTypeCollection to manage blog posts in your Symfony project:
<?php declare(strict_types=1); namespace App\ContentType\BlogPost; use App\ContentType\ContentTypeCollection; use App\ContentType\ContentTypeFactory; /** * @extends ContentTypeCollection<BlogPost> */ final readonly class BlogPostCollection extends ContentTypeCollection { protected function createItem(array $values): BlogPost { return ContentTypeFactory::create($values, BlogPost::class); } }
new BlogPostCollection( $this->stories->allByContentType( BlogPost::type(), new StoriesRequest( language: $this->localeSwitcher->getLocale(), pagination: new Pagination($this->curPage, self::PER_PAGE), sortBy: new SortBy('first_published_at', Direction::Desc), filters: $filters, excludeFields: new FieldCollection([ new Field('body'), new Field('additional_contents'), ]), ), ), );