Skip to content

Commit 7cf0b35

Browse files
committed
Add typed accessors for story and workflow stage data
1 parent bb4df85 commit 7cf0b35

File tree

8 files changed

+164
-4
lines changed

8 files changed

+164
-4
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## 1.1.5 - 2026-04-08
4+
- Adding `contentType()` accessor to `StoryCollectionItem` for retrieving the root component name in list responses
5+
- Adding `hasUnpublishedChanges()` accessor to stories for checking draft changes status
6+
- Adding `workflowStageId()` accessor to stories for retrieving the workflow stage ID (returns `null` when not set)
7+
- Adding `color()` and `workflowId()` accessors to `WorkflowStageData`
8+
- Fixing `updatedAt()` signature to accept a `$format` parameter, consistent with `publishedAt()`, `createdAt()`, and `firstPublishedAt()`
9+
310
## 1.1.4 - 2026-03-23
411
- Adding `StoryApi::versions()` endpoint for listing story versions with pagination
512
- Fixing asset upload folder assignment: using `asset_folder_id` instead of `parent_id`

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,25 @@ foreach ($stories as $story) {
369369
}
370370
```
371371

372+
Each story item exposes typed accessors for commonly used fields:
373+
374+
```php
375+
foreach ($stories as $story) {
376+
echo $story->contentType() . PHP_EOL; // e.g. "article-page"
377+
echo $story->updatedAt() . PHP_EOL; // e.g. "2024-02-08"
378+
echo $story->updatedAt("Y-m-d H:i:s") . PHP_EOL; // e.g. "2024-02-08 16:27:10"
379+
380+
if ($story->hasUnpublishedChanges()) {
381+
echo "This story has unpublished draft changes" . PHP_EOL;
382+
}
383+
384+
$stageId = $story->workflowStageId(); // int or null
385+
if ($stageId !== null) {
386+
echo "Workflow stage ID: " . $stageId . PHP_EOL;
387+
}
388+
}
389+
```
390+
372391
In the case you need to retrieve the response to access to some additional information you can obtain a `StoriesResponse` via the `page()` method:
373392

374393
```php
@@ -1237,6 +1256,8 @@ $workflowStages = $response->data();
12371256
foreach ($workflowStages as $key => $workflowStage) {
12381257
echo "Workflow Stage: " . $workflowStage->name() . " - ";
12391258
echo $workflowStage->id() . PHP_EOL;
1259+
echo "Color: " . $workflowStage->color() . PHP_EOL; // e.g. "#2db47d"
1260+
echo "Workflow ID: " . $workflowStage->workflowId() . PHP_EOL;
12401261
}
12411262
```
12421263
### Creating a new custom workflow stage

src/Data/StoryBaseData.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ public function publishedAt(string $format = "Y-m-d"): null|string
6565
return $this->getFormattedDateTime("published_at", "", format: $format);
6666
}
6767

68-
public function updatedAt(): null|string
68+
public function updatedAt(string $format = "Y-m-d"): null|string
6969
{
70-
return $this->getFormattedDateTime("updated_at", "", format: "Y-m-d");
70+
return $this->getFormattedDateTime("updated_at", "", format: $format);
7171
}
7272

7373
/**
@@ -115,4 +115,16 @@ public function firstPublishedAt(string $format = "Y-m-d"): null|string
115115
{
116116
return $this->getFormattedDateTime("first_published_at", "", format: $format);
117117
}
118+
119+
public function hasUnpublishedChanges(): bool
120+
{
121+
return $this->getBoolean("unpublished_changes", false);
122+
}
123+
124+
public function workflowStageId(): ?int
125+
{
126+
$id = $this->getInt("stage.workflow_stage_id", 0);
127+
128+
return $id > 0 ? $id : null;
129+
}
118130
}

src/Data/StoryCollectionItem.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ public static function make(array $data = []): self
4747
return $storyItem;
4848
}
4949

50+
public function contentType(): string
51+
{
52+
return $this->getString("content_type");
53+
}
54+
5055
/**
5156
* Set tags for Story, from a `Tags` collection
5257
* @return $this

src/Data/WorkflowStageData.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,14 @@ public function id(): string
4242
{
4343
return $this->getString('id', "");
4444
}
45+
46+
public function color(): string
47+
{
48+
return $this->getString("color", "");
49+
}
50+
51+
public function workflowId(): string
52+
{
53+
return $this->getString("workflow_id", "");
54+
}
4555
}

tests/Feature/StoryApiTest.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ public function testOneStoryStoryData(): void
3535
$storyApi = new StoryApi($mapiClient, "222");
3636

3737
$storyblokResponse = $storyApi->get("111");
38-
/** @var Story $storyblokData */
3938
$storyblokData = $storyblokResponse->data();
4039

4140
$this->assertSame("My third post", $storyblokData->get("name"));
@@ -112,7 +111,6 @@ public function testCreateStoryEncodesDataCorrectlyAsJson(): void
112111
$this->assertTrue($response->isOk());
113112
$this->assertSame(201, $response->getResponseStatusCode());
114113

115-
/** @var Story $responseData */
116114
$responseData = $response->data();
117115
$this->assertSame("Test Story", $responseData->name());
118116
$this->assertSame("test-story", $responseData->slug());

tests/Unit/StoryBaseDataTest.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public function testUpdatedAtOnStory(): void
9595
{
9696
$story = $this->makeStory();
9797
$this->assertSame("2024-02-08", $story->updatedAt());
98+
$this->assertSame("2024-02-08 16:27:10", $story->updatedAt("Y-m-d H:i:s"));
9899
}
99100

100101
public function testUpdatedAtOnStoryCollectionItem(): void
@@ -224,4 +225,66 @@ public function testNameOnStoryCollectionItem(): void
224225
$item = $this->makeStoryCollectionItem();
225226
$this->assertSame("My third post", $item->name());
226227
}
228+
229+
public function testHasUnpublishedChangesOnStory(): void
230+
{
231+
$story = $this->makeStory();
232+
$this->assertFalse($story->hasUnpublishedChanges());
233+
}
234+
235+
public function testHasUnpublishedChangesTrue(): void
236+
{
237+
$item = StoryCollectionItem::make([
238+
"name" => "Draft story",
239+
"slug" => "draft-story",
240+
"unpublished_changes" => true,
241+
]);
242+
$this->assertTrue($item->hasUnpublishedChanges());
243+
}
244+
245+
public function testHasUnpublishedChangesDefault(): void
246+
{
247+
$item = $this->makeStoryCollectionItem();
248+
$this->assertFalse($item->hasUnpublishedChanges());
249+
}
250+
251+
public function testWorkflowStageIdOnStory(): void
252+
{
253+
$story = $this->makeStory();
254+
$this->assertNull($story->workflowStageId());
255+
}
256+
257+
public function testWorkflowStageIdWithValue(): void
258+
{
259+
$item = StoryCollectionItem::make([
260+
"name" => "Reviewed story",
261+
"slug" => "reviewed-story",
262+
"stage" => [
263+
"workflow_stage_id" => 653554,
264+
],
265+
]);
266+
$this->assertSame(653554, $item->workflowStageId());
267+
}
268+
269+
public function testWorkflowStageIdDefault(): void
270+
{
271+
$item = $this->makeStoryCollectionItem();
272+
$this->assertNull($item->workflowStageId());
273+
}
274+
275+
public function testContentTypeWithValue(): void
276+
{
277+
$item = StoryCollectionItem::make([
278+
"name" => "Article story",
279+
"slug" => "article-story",
280+
"content_type" => "page",
281+
]);
282+
$this->assertSame("page", $item->contentType());
283+
}
284+
285+
public function testContentTypeDefault(): void
286+
{
287+
$item = $this->makeStoryCollectionItem();
288+
$this->assertSame("", $item->contentType());
289+
}
227290
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Unit;
6+
7+
use Storyblok\ManagementApi\Data\WorkflowStageData;
8+
use Tests\TestCase;
9+
10+
final class WorkflowStageDataTest extends TestCase
11+
{
12+
private function makeWorkflowStage(): WorkflowStageData
13+
{
14+
$contentString = $this->mockData("one-workflow-stage");
15+
/** @var array<string, array<mixed>> $content */
16+
$content = json_decode($contentString, true);
17+
18+
return WorkflowStageData::makeFromResponse($content);
19+
}
20+
21+
public function testColorWithValue(): void
22+
{
23+
$stage = $this->makeWorkflowStage();
24+
$this->assertSame("#babcb6", $stage->color());
25+
}
26+
27+
public function testColorDefault(): void
28+
{
29+
$stage = WorkflowStageData::make([]);
30+
$this->assertSame("", $stage->color());
31+
}
32+
33+
public function testWorkflowIdWithValue(): void
34+
{
35+
$stage = $this->makeWorkflowStage();
36+
$this->assertSame("93606", $stage->workflowId());
37+
}
38+
39+
public function testWorkflowIdDefault(): void
40+
{
41+
$stage = WorkflowStageData::make([]);
42+
$this->assertSame("", $stage->workflowId());
43+
}
44+
}

0 commit comments

Comments
 (0)