Skip to content

Commit 97655c3

Browse files
committed
Adding AssetFolderApi endpoint for managing asset folders
1 parent 6ba014a commit 97655c3

File tree

10 files changed

+530
-2
lines changed

10 files changed

+530
-2
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## 1.2.0 - WIP
44
- Adding `AssetApi::update()` method for updating asset metadata (alt, title, asset_folder_id, internal_tag_ids, etc.)
5+
- Adding `AssetFolderApi` endpoint for managing asset folders (list, get, create, update, delete)
6+
- Adding `AssetFolder`, `AssetFolders` data classes
7+
- Adding `AssetFolderResponse`, `AssetFoldersResponse` response classes
58

69

710
## 1.1.5 - 2026-04-08

README.md

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ $client = new ManagementApiClient($storyblokPersonalAccessToken);
129129

130130
The Storyblok **Management API Client** provides two main approaches for interacting with the API:
131131

132-
- Using specific API classes (like `StoryApi` or `SpaceApi` or `AssetApi` or `TagApi` or `UserApi`)
132+
- Using specific API classes (like `StoryApi` or `SpaceApi` or `AssetApi` or `AssetFolderApi` or `TagApi` or `UserApi`)
133133
- Using specific API classes for handling bulk data (like `StoryBulkApi`)
134134
- Using the `ManagementApi` class
135135

@@ -139,11 +139,12 @@ Alternatively, you can leverage dedicated classes like `SpaceApi`, which are tai
139139

140140
If a dedicated API class like `SpaceApi` or `StoryApi` does not exist for your desired endpoint, you can always fall back to the more versatile `ManagementApi` class.
141141

142-
In addition to the general-purpose `ManagementApi` class, the Storyblok Management PHP client also provides specific classes such as `SpaceApi`, `StoryApi`, `TagApi` and `AssetApi`. These classes function similarly to the `ManagementApi` but are tailored for specific scenarios, offering additional methods or data types to work with particular resources.
142+
In addition to the general-purpose `ManagementApi` class, the Storyblok Management PHP client also provides specific classes such as `SpaceApi`, `StoryApi`, `TagApi`, `AssetApi` and `AssetFolderApi`. These classes function similarly to the `ManagementApi` but are tailored for specific scenarios, offering additional methods or data types to work with particular resources.
143143

144144
- `SpaceApi` focuses on managing space-level operations, such as retrieving space information, performing backup etc.
145145
- `StoryApi` specializes in handling stories and their content, including creating, updating, retrieving, and deleting stories. This class also provides methods that deal with the structure and fields specific to stories.
146146
- `AssetApi` designed to manage assets like images, files, and other media. It provides methods to upload, retrieve, and manage assets, offering features specific to media management.
147+
- `AssetFolderApi` designed to manage asset folders, including creating, retrieving, updating, and deleting folders for organizing assets.
147148
- `TagApi` designed to manage tags.
148149
- `UserApi` designed to handle the current user. "Current" means the user related to the access token used for instancing the `ManagementApiClient` object.
149150

@@ -1035,6 +1036,76 @@ try {
10351036
}
10361037
```
10371038

1039+
## Handling asset folders
1040+
1041+
For using the `AssetFolderApi` class you have to import:
1042+
1043+
```php
1044+
use Storyblok\ManagementApi\Endpoints\AssetFolderApi;
1045+
```
1046+
1047+
For using the `AssetFolder` class you have to import:
1048+
1049+
```php
1050+
use Storyblok\ManagementApi\Data\AssetFolder;
1051+
```
1052+
1053+
### Getting the AssetFolderApi instance
1054+
1055+
```php
1056+
$assetFolderApi = new AssetFolderApi($client, $spaceId);
1057+
```
1058+
1059+
### Listing asset folders
1060+
1061+
```php
1062+
$folders = $assetFolderApi->page()->data();
1063+
1064+
foreach ($folders as $folder) {
1065+
echo $folder->id() . PHP_EOL;
1066+
echo $folder->name() . PHP_EOL;
1067+
echo $folder->parentId() . PHP_EOL;
1068+
}
1069+
```
1070+
1071+
### Getting one asset folder
1072+
1073+
```php
1074+
$folder = $assetFolderApi->get($folderId)->data();
1075+
echo $folder->id() . PHP_EOL;
1076+
echo $folder->name() . PHP_EOL;
1077+
```
1078+
1079+
### Creating an asset folder
1080+
1081+
```php
1082+
$folder = new AssetFolder("My New Folder");
1083+
$created = $assetFolderApi->create($folder)->data();
1084+
echo "Created folder, ID: " . $created->id() . PHP_EOL;
1085+
```
1086+
1087+
To create a subfolder, set the `parent_id`:
1088+
1089+
```php
1090+
$folder = new AssetFolder("Subfolder");
1091+
$folder->set("parent_id", $parentFolderId);
1092+
$created = $assetFolderApi->create($folder)->data();
1093+
```
1094+
1095+
### Updating an asset folder
1096+
1097+
```php
1098+
$folder = $assetFolderApi->get($folderId)->data();
1099+
$folder->set("name", "Renamed Folder");
1100+
$updated = $assetFolderApi->update($folderId, $folder)->data();
1101+
```
1102+
1103+
### Deleting an asset folder
1104+
1105+
```php
1106+
$assetFolderApi->delete($folderId);
1107+
```
1108+
10381109
## Handling tags
10391110

10401111
For using the `TagApi` class you have to import:

src/Data/AssetFolder.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Storyblok\ManagementApi\Data;
6+
7+
use Storyblok\ManagementApi\Exceptions\StoryblokFormatException;
8+
9+
class AssetFolder extends BaseData
10+
{
11+
public function __construct(string $name)
12+
{
13+
$this->data = [];
14+
$this->data["name"] = $name;
15+
}
16+
17+
/**
18+
* @param mixed[] $data
19+
* @throws StoryblokFormatException
20+
*/
21+
public static function make(array $data = []): self
22+
{
23+
$dataObject = new StoryblokData($data);
24+
if (!($dataObject->hasKey("name"))) {
25+
// is not valid
26+
}
27+
28+
$assetFolder = new AssetFolder(
29+
$dataObject->getString("name"),
30+
);
31+
$assetFolder->setData($dataObject->toArray());
32+
if (!$assetFolder->isValid()) {
33+
throw new StoryblokFormatException("AssetFolder is not valid");
34+
}
35+
36+
return $assetFolder;
37+
}
38+
39+
public function isValid(): bool
40+
{
41+
return $this->hasKey("name");
42+
}
43+
44+
public function id(): string
45+
{
46+
return $this->getString("id");
47+
}
48+
49+
public function name(): string
50+
{
51+
return $this->getString("name");
52+
}
53+
54+
public function parentId(): int|null
55+
{
56+
return $this->getInt("parent_id");
57+
}
58+
}

src/Data/AssetFolders.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Storyblok\ManagementApi\Data;
6+
7+
class AssetFolders extends StoryblokData
8+
{
9+
#[\Override]
10+
public function getDataClass(): string
11+
{
12+
return AssetFolder::class;
13+
}
14+
15+
/**
16+
* @param mixed[] $data
17+
*/
18+
#[\Override]
19+
public static function make(array $data = []): self
20+
{
21+
return new self($data);
22+
}
23+
}

src/Endpoints/AssetFolderApi.php

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Storyblok\ManagementApi\Endpoints;
6+
7+
use Storyblok\ManagementApi\Data\AssetFolder;
8+
use Storyblok\ManagementApi\Response\AssetFolderResponse;
9+
use Storyblok\ManagementApi\Response\AssetFoldersResponse;
10+
11+
class AssetFolderApi extends EndpointSpace
12+
{
13+
/**
14+
* Retrieve all asset folders.
15+
* @link https://www.storyblok.com/docs/api/management/core-resources/asset-folders/retrieve-multiple-asset-folders
16+
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
17+
*/
18+
public function page(): AssetFoldersResponse
19+
{
20+
$httpResponse = $this->makeHttpRequest(
21+
"GET",
22+
"/v1/spaces/" . $this->spaceId . "/asset_folders",
23+
);
24+
return new AssetFoldersResponse($httpResponse);
25+
}
26+
27+
/**
28+
* Retrieve a single asset folder.
29+
* @link https://www.storyblok.com/docs/api/management/core-resources/asset-folders/retrieve-one-asset-folder
30+
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
31+
*/
32+
public function get(string|int $assetFolderId): AssetFolderResponse
33+
{
34+
$httpResponse = $this->makeHttpRequest(
35+
"GET",
36+
"/v1/spaces/" . $this->spaceId . "/asset_folders/" . $assetFolderId,
37+
);
38+
return new AssetFolderResponse($httpResponse);
39+
}
40+
41+
/**
42+
* Create a new asset folder.
43+
* @link https://www.storyblok.com/docs/api/management/core-resources/asset-folders/create-an-asset-folder
44+
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
45+
*/
46+
public function create(AssetFolder $assetFolderData): AssetFolderResponse
47+
{
48+
$httpResponse = $this->makeHttpRequest(
49+
"POST",
50+
"/v1/spaces/" . $this->spaceId . "/asset_folders",
51+
[
52+
"body" => json_encode(["asset_folder" => $assetFolderData->toArray()]),
53+
],
54+
);
55+
return new AssetFolderResponse($httpResponse);
56+
}
57+
58+
/**
59+
* Update an existing asset folder.
60+
* @link https://www.storyblok.com/docs/api/management/core-resources/asset-folders/update-an-asset-folder
61+
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
62+
*/
63+
public function update(string|int $assetFolderId, AssetFolder $assetFolderData): AssetFolderResponse
64+
{
65+
$httpResponse = $this->makeHttpRequest(
66+
"PUT",
67+
"/v1/spaces/" . $this->spaceId . "/asset_folders/" . $assetFolderId,
68+
[
69+
"body" => json_encode(["asset_folder" => $assetFolderData->toArray()]),
70+
],
71+
);
72+
return new AssetFolderResponse($httpResponse);
73+
}
74+
75+
/**
76+
* Delete an asset folder.
77+
* @link https://www.storyblok.com/docs/api/management/core-resources/asset-folders/delete-an-asset-folder
78+
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
79+
*/
80+
public function delete(string|int $assetFolderId): AssetFolderResponse
81+
{
82+
$httpResponse = $this->makeHttpRequest(
83+
"DELETE",
84+
"/v1/spaces/" . $this->spaceId . "/asset_folders/" . $assetFolderId,
85+
);
86+
return new AssetFolderResponse($httpResponse);
87+
}
88+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Storyblok\ManagementApi\Response;
6+
7+
use Storyblok\ManagementApi\Data\AssetFolder;
8+
use Storyblok\ManagementApi\Exceptions\StoryblokFormatException;
9+
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
10+
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
11+
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
12+
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
13+
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
14+
15+
class AssetFolderResponse extends StoryblokResponse implements StoryblokResponseInterface
16+
{
17+
/**
18+
* @throws TransportExceptionInterface
19+
* @throws ServerExceptionInterface
20+
* @throws RedirectionExceptionInterface
21+
* @throws DecodingExceptionInterface
22+
* @throws StoryblokFormatException
23+
* @throws ClientExceptionInterface
24+
*/
25+
#[\Override]
26+
public function data(): AssetFolder
27+
{
28+
$key = "asset_folder";
29+
$array = $this->toArray();
30+
if (array_key_exists($key, $array)) {
31+
return AssetFolder::make($array[$key]);
32+
}
33+
34+
throw new StoryblokFormatException(sprintf("Expected '%s' in the response.", $key));
35+
}
36+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Storyblok\ManagementApi\Response;
6+
7+
use Storyblok\ManagementApi\Data\AssetFolders;
8+
use Storyblok\ManagementApi\Exceptions\StoryblokFormatException;
9+
10+
class AssetFoldersResponse extends StoryblokResponse implements StoryblokResponseInterface
11+
{
12+
#[\Override]
13+
public function data(): AssetFolders
14+
{
15+
$key = "asset_folders";
16+
$array = $this->toArray();
17+
if (array_key_exists($key, $array)) {
18+
return new AssetFolders($array[$key]);
19+
}
20+
21+
throw new StoryblokFormatException(sprintf("Expected '%s' in the response.", $key));
22+
}
23+
}

0 commit comments

Comments
 (0)