Skip to content

Commit d71c1eb

Browse files
Handling Components (#13)
* Handling Components * Update README.md * Raising Exceptions in the case the component is not valid * Make the API Prefix path as constant
1 parent fa06e7b commit d71c1eb

20 files changed

+1166
-14
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
# Changelog
22

3+
## 1.0.2 - WIP
4+
- Implementing ComponentApi class for handling components
5+
36
## 1.0.1 - 2025-05-09
47
- Fixing getting list of Stories. Issue #10
58
- Adding new plans in `StoryblokUtils::getPlanDescription()` method
69
- Reviewing README
7-
- Adding dependecies license checker
10+
- Adding dependencies license checker
811

912
## 1.0.0 - 2025-03-14
1013
- Releasing v 1.0.0

README.md

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,72 @@ foreach ($file as $row) {
426426
$createdStories = iterator_to_array($storyBulkApi->createStories($stories));
427427
```
428428

429+
## Handling components
430+
431+
You can use the `ComponentApi` class to fetch all components from a specific space:
432+
433+
```php
434+
use Storyblok\ManagementApi\ManagementApiClient;
435+
use Storyblok\ManagementApi\Api\ComponentApi;
436+
use Psr\Log\NullLogger;
437+
438+
$client = new ManagementApiClient($storyblokPersonalAccessToken);
439+
440+
// Define your space ID
441+
$spaceId = "YOUR_SPACE_ID";
442+
443+
// Initialize the Component API
444+
$componentApi = new ComponentApi($client, $spaceId, new NullLogger());
445+
446+
// Retrieve all components
447+
$componentsResponse = $componentApi->all();
448+
$components = $componentsResponse->data();
449+
450+
// Loop through and print component names and IDs
451+
foreach ($components as $component) {
452+
echo $component->name() . " - " . $component->id() . PHP_EOL;
453+
}
454+
455+
```
456+
With the same response you can retrieve the component folders.
457+
You can use the `dataFolders()` method:
458+
459+
```php
460+
$folders = $componentsResponse->dataFolders();
461+
```
462+
463+
464+
### Creating a new component
465+
466+
You can programmatically create a new component in a space:
467+
468+
```php
469+
// Define a new component
470+
$component = new Component("my-component-1234567");
471+
$component->setDisplayName("My Component");
472+
$component->setRoot(); // Mark as a root component
473+
$component->setPreviewField("title");
474+
475+
// Add fields
476+
$component->setField("title", ["type" => "text"]);
477+
$component->setField("headline", ["type" => "text"]);
478+
$component->setField("image", ["type" => "asset"]);
479+
480+
try {
481+
// Create the component in Storyblok
482+
$componentResponse = $componentApi->create($component);
483+
$newComponent = $componentResponse->data();
484+
485+
// Output the new component's ID
486+
echo "Component created with ID: " . $newComponent->id() . PHP_EOL;
487+
488+
// Dump full component details (for debugging)
489+
$newComponent->dump();
490+
} catch (Exception $e) {
491+
echo "Error creating component: " . $e->getMessage();
492+
}
493+
```
494+
429495
## Handling users
430496

431497
For using the `UserApi` class you have to import:
@@ -466,7 +532,6 @@ echo ($currentUser->hasPartner() ? " HAS PARTNER" : "NO PARTNER") . PHP_EOL;;
466532

467533
```
468534

469-
470535
Typically, all the data object provides you some helper methods like:
471536
- `toArray()` to obtain the data in a PHP array;
472537
- `toJson()` to obtain a JSON string;
@@ -516,6 +581,7 @@ foreach ($assets as $key => $asset) {
516581
```
517582

518583
### Filtering assets
584+
519585
Using the `AssetsParams` class you can set up filters for filtering the assets.
520586

521587
```php

src/Data/BaseData.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,4 +305,15 @@ public function getString(mixed $key, string $defaultValue = "", string $charNes
305305

306306
return $defaultValue;
307307
}
308+
309+
public function getStringNullable(mixed $key, string|null $defaultValue = null, string $charNestedKey = "."): string|null
310+
{
311+
$returnValue = $this->get($key, $defaultValue, $charNestedKey);
312+
313+
if (is_scalar($returnValue)) {
314+
return strval($returnValue);
315+
}
316+
317+
return $defaultValue;
318+
}
308319
}

src/Data/Component.php

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Storyblok\ManagementApi\Data;
6+
7+
use Storyblok\ManagementApi\Exceptions\StoryblokFormatException;
8+
9+
class Component extends BaseData
10+
{
11+
public const DEFAULT_DATE_FORMAT = "Y-m-d\TH:i:s.vT";
12+
13+
/**
14+
* @param string $name the component name
15+
*/
16+
public function __construct(
17+
string $name,
18+
) {
19+
$this->data = [];
20+
$this->data['name'] = $name;
21+
}
22+
23+
/**
24+
* @param mixed[] $data
25+
* @throws StoryblokFormatException
26+
*/
27+
public static function make(array $data = []): self
28+
{
29+
$dataObject = new StoryblokData($data);
30+
if (!($dataObject->hasKey('name'))) {
31+
throw new StoryblokFormatException("Component is not valid, missing the name");
32+
}
33+
34+
$component = new Component(
35+
$dataObject->getString("name")
36+
);
37+
$component->setData($dataObject->toArray());
38+
// validate
39+
if (! $component->isValid()) {
40+
if ($dataObject->getString("name") === "") {
41+
throw new StoryblokFormatException("Component is not valid, missing the name");
42+
}
43+
44+
throw new StoryblokFormatException("Component <" . $dataObject->getString("name") . "> is not valid");
45+
}
46+
47+
return $component;
48+
49+
}
50+
51+
public function setName(string $name): void
52+
{
53+
$this->set('name', $name);
54+
}
55+
56+
/**
57+
* Technical name used for component property in entries
58+
*/
59+
public function name(): string
60+
{
61+
return $this->getString('name');
62+
}
63+
64+
/**
65+
* Component name based on the technical name or display name
66+
*/
67+
public function realName(): string
68+
{
69+
return $this->getString('real_name');
70+
}
71+
72+
/**
73+
* Name that will be used in the editor interface
74+
*/
75+
public function displayName(): string
76+
{
77+
return $this->getString('display_name');
78+
}
79+
80+
/**
81+
* Name that will be used in the editor interface
82+
*/
83+
public function setDisplayName(string $displayName): void
84+
{
85+
$this->set('display_name', $displayName);
86+
}
87+
88+
/**
89+
* URL to the preview image, if uploaded
90+
*/
91+
public function image(): string|null
92+
{
93+
return $this->getStringNullable('image');
94+
}
95+
96+
/**
97+
* URL to the preview image, if uploaded
98+
*/
99+
public function setImage(string $url): void
100+
{
101+
$this->set('image', $url);
102+
}
103+
104+
/**
105+
* The field that is for preview in the interface (Preview Field)
106+
*/
107+
public function previewField(): string
108+
{
109+
return $this->getString('preview_field');
110+
}
111+
112+
/**
113+
* The field that is for preview in the interface (Preview Field)
114+
*/
115+
public function setPreviewField(string $value): void
116+
{
117+
$this->set('preview_field', $value);
118+
}
119+
120+
/**
121+
* Creation date
122+
*/
123+
public function createdAt(string $format = self::DEFAULT_DATE_FORMAT): null|string
124+
{
125+
return $this->getFormattedDateTime('created_at', "", format: $format);
126+
}
127+
128+
/**
129+
* Latest update date
130+
*/
131+
public function updatedAt(string $format = self::DEFAULT_DATE_FORMAT): null|string
132+
{
133+
return $this->getFormattedDateTime('updated_at', "", format: $format);
134+
}
135+
136+
/**
137+
* The numeric ID in string format "12345678"
138+
*/
139+
public function id(): string
140+
{
141+
return $this->getString('id');
142+
}
143+
144+
/**
145+
* True if the component can be used as a Content Type
146+
*/
147+
public function isRoot(): bool
148+
{
149+
return $this->getBoolean('is_root');
150+
}
151+
152+
/**
153+
* If the component can be used as a Content Type
154+
*/
155+
public function setRoot(bool $isRoot = true): void
156+
{
157+
$this->set('is_root', $isRoot);
158+
}
159+
160+
public function uuid(): string
161+
{
162+
return $this->getString('uuid');
163+
}
164+
165+
/**
166+
* @return mixed[]
167+
*/
168+
public function getSchema(): array
169+
{
170+
return $this->getArray('schema');
171+
}
172+
173+
/**
174+
* @param mixed[] $schema
175+
*/
176+
public function setSchema(array $schema): void
177+
{
178+
$this->set('schema', $schema);
179+
}
180+
181+
/**
182+
* @param mixed[] $fieldAttributes
183+
*/
184+
public function setField(string $name, array $fieldAttributes): void
185+
{
186+
$this->set('schema.' . $name, $fieldAttributes);
187+
}
188+
189+
/**
190+
* Validates if the component data contains all required fields and valid values
191+
*/
192+
public function isValid(): bool
193+
{
194+
return $this->hasKey('name');
195+
}
196+
197+
/**
198+
* Set tags for Component, from a `Tags` collection
199+
* @return $this
200+
*/
201+
public function setTags(Tags $tags): self
202+
{
203+
204+
return $this->setTagsFromArray($tags->getTagsArray());
205+
206+
}
207+
208+
/**
209+
* Set tags for Component, from a string of arrays like ["tag1", "tag2"]
210+
* @param string[] $tagsArray
211+
* @return $this
212+
*/
213+
public function setTagsFromArray(array $tagsArray): self
214+
{
215+
$this->set("internal_tag_ids", $tagsArray);
216+
return $this;
217+
}
218+
}

0 commit comments

Comments
 (0)