Content::delete()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace CloudPlayDev\ConfluenceClient\Api;
5
6
use CloudPlayDev\ConfluenceClient\Entity\AbstractContent;
7
use CloudPlayDev\ConfluenceClient\Entity\ContentHistory;
8
use CloudPlayDev\ConfluenceClient\Entity\ContentSearchResult;
9
use CloudPlayDev\ConfluenceClient\Entity\ContentBody;
10
use CloudPlayDev\ConfluenceClient\Entity\Hydratable;
11
use CloudPlayDev\ConfluenceClient\Exception\ConfluencePhpClientException;
12
use Http\Client\Exception as HttpClientException;
13
use JsonException;
14
use Psr\Http\Message\ResponseInterface;
15
use Webmozart\Assert\Assert;
16
use function count;
17
use function in_array;
18
19
/**
20
 * @see https://docs.atlassian.com/atlassian-confluence/REST/6.6.0/#content
21
 */
22
class Content extends AbstractApi
23
{
24
    /**
25
     * ContentType for confluence attachments
26
     */
27
    public const CONTENT_TYPE_ATTACHMENT = 'attachment';
28
29
    /**
30
     * ContentType for confluence comments
31
     */
32
    public const CONTENT_TYPE_COMMENT = 'comment';
33
34
    /**
35
     * ContentType for confluence page content
36
     */
37
    public const CONTENT_TYPE_PAGE = 'page';
38
39
    /**
40
     * ContentType for confluence global content
41
     */
42
    public const CONTENT_TYPE_GLOBAL = 'global';
43
44
    /**
45
     * default value for expand query parameter
46
     */
47
    private const DEFAULT_EXPAND = 'space,version,body.storage,container';
48
    private const DEFAULT_HISTORY_EXPAND = 'content,content.space,content.version,content.body.storage,content.container';
49
50
    /**
51
     * @see https://docs.atlassian.com/atlassian-confluence/REST/6.6.0/#content-getContent
52
     * @throws ConfluencePhpClientException
53
     * @throws HttpClientException
54
     * @throws JsonException
55
     */
56
    public function get(int $contentId, ?int $version = null): ?AbstractContent
57
    {
58
        $fetchUri = ['content', $contentId];
59
        $parameter = ['expand' => self::DEFAULT_EXPAND];
60
61
        if ($version !== null) {
62
            $fetchUri[] = 'version';
63
            $fetchUri[] = $version;
64
65
            $parameter = ['expand' => self::DEFAULT_HISTORY_EXPAND];
66
        }
67
68
        $response = $this->httpGet(self::getRestfulUri(...$fetchUri), $parameter);
69
70
        return $this->hydrateResponse($response, AbstractContent::class);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->hydrateRes...AbstractContent::class) returns the type CloudPlayDev\ConfluenceClient\Entity\Hydratable which includes types incompatible with the type-hinted return CloudPlayDev\ConfluenceC...ty\AbstractContent|null.
Loading history...
71
    }
72
73
74
    /**
75
     * @see https://docs.atlassian.com/atlassian-confluence/REST/6.6.0/#content-getContent
76
     * @param array{title?: string, spaceKey?: string, type?: string, id?: int|string} $searchParameter
77
     * @param int|null $limit Limit the number of results. Usual default is 25
78
     * @param int|null $start Start the results at a particular index
79
     * @return ContentSearchResult
80
     * @throws ConfluencePhpClientException
81
     */
82
    public function find(array $searchParameter, ?int $limit = null, ?int $start = null): ContentSearchResult
83
    {
84
        $allowedSearchParameter = ['title', 'spaceKey', 'type', 'id'];
85
        $queryParameter = array_filter($searchParameter, static fn(string $searchKey): bool => in_array($searchKey, $allowedSearchParameter, true), ARRAY_FILTER_USE_KEY);
86
87
        $queryParameter['expand'] = self::DEFAULT_EXPAND;
88
89
        if($limit !== null) {
90
            $queryParameter['limit'] = $limit;
91
        }
92
93
        if($start !== null) {
94
            $queryParameter['start'] = $start;
95
        }
96
97
        $searchResponse = $this->httpGet('content', $queryParameter);
98
99
        return $this->hydrateResponse($searchResponse, ContentSearchResult::class);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->hydrateRes...entSearchResult::class) returns the type CloudPlayDev\ConfluenceClient\Entity\Hydratable which includes types incompatible with the type-hinted return CloudPlayDev\ConfluenceC...ity\ContentSearchResult.
Loading history...
100
    }
101
102
    /**
103
     * @see https://docs.atlassian.com/atlassian-confluence/REST/6.6.0/#content-update
104
     * @param AbstractContent $content
105
     * @return AbstractContent
106
     * @throws JsonException
107
     * @throws HttpClientException
108
     */
109
    public function update(AbstractContent $content): AbstractContent
110
    {
111
        $contentId = $content->getId();
112
        Assert::integer($contentId, 'The content can only be changed when it has already been created. To do this, use the "create" method.');
113
114
        $data = [
115
            'id' => $contentId,
116
            'type' => $content->getType(),
117
            'title' => $content->getTitle(),
118
            'space' => ['key' => $content->getSpace()],
119
            'body' => [
120
                'storage' => [
121
                    'value' => $content->getContent(),
122
                    'representation' => 'storage',
123
                ],
124
            ],
125
            'version' => ['number' => $content->getVersion() + 1]
126
        ];
127
128
        return $this->hydrateResponse(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->hydrateRes...AbstractContent::class) returns the type CloudPlayDev\ConfluenceClient\Entity\Hydratable which includes types incompatible with the type-hinted return CloudPlayDev\ConfluenceC...\Entity\AbstractContent.
Loading history...
129
            $this->httpPut(self::getRestfulUri('content', $contentId), $data),
130
            AbstractContent::class
131
        );
132
    }
133
134
135
    /**
136
     * @see https://docs.atlassian.com/atlassian-confluence/REST/6.6.0/#content-createContent
137
     * @param AbstractContent $content
138
     * @return AbstractContent
139
     * @throws ConfluencePhpClientException
140
     * @throws HttpClientException
141
     * @throws JsonException
142
     */
143
    public function create(AbstractContent $content): AbstractContent
144
    {
145
        Assert::null($content->getId(), 'Only pages not already saved can be created.');
146
147
        $data = [
148
            'type' => $content->getType(),
149
            'title' => $content->getTitle(),
150
            'space' => ['key' => $content->getSpace()],
151
            'body' => [
152
                'storage' => [
153
                    'value' => $content->getContent(),
154
                    'representation' => 'storage',
155
                ],
156
            ],
157
        ];
158
159
        if (count($content->getAncestors()) > 0) {
160
            $ancestorsData = array_map(static fn(int $id) => ['id' => $id], $content->getAncestors());
161
162
            $data['ancestors'] = $ancestorsData;
163
        }
164
165
        /* attach content to content */
166
        if (null !== $content->getContainerId()) {
167
            $data['container'] = [
168
                'id' => $content->getContainerId(),
169
                'type' => $content->getContainerType(),
170
            ];
171
        }
172
173
        $response = $this->httpPost(self::getRestfulUri('content'), [], $data);
174
        return $this->hydrateResponse($response, AbstractContent::class);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->hydrateRes...AbstractContent::class) returns the type CloudPlayDev\ConfluenceClient\Entity\Hydratable which includes types incompatible with the type-hinted return CloudPlayDev\ConfluenceC...\Entity\AbstractContent.
Loading history...
175
176
    }
177
178
    /**
179
     * @see https://docs.atlassian.com/atlassian-confluence/REST/6.6.0/#content-delete
180
     * @param AbstractContent $content
181
     * @return ResponseInterface
182
     */
183
    public function delete(AbstractContent $content): ResponseInterface
184
    {
185
        $contentId = $content->getId();
186
        Assert::integer($contentId, 'The content must already be saved to be deleted.');
187
        return $this->httpDelete(self::getRestfulUri('content', $contentId));
188
    }
189
190
    /**
191
     * @param AbstractContent $content
192
     * @param string|null $contentType
193
     * @return ContentSearchResult
194
     * @throws HttpClientException
195
     * @throws JsonException
196
     */
197
    public function children(AbstractContent $content, ?string $contentType = null): ContentSearchResult
198
    {
199
        return $this->hydrateResponse(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->hydrateRes...entSearchResult::class) returns the type CloudPlayDev\ConfluenceClient\Entity\Hydratable which includes types incompatible with the type-hinted return CloudPlayDev\ConfluenceC...ity\ContentSearchResult.
Loading history...
200
            $this->httpGet(self::getRestfulUri('content', $content->getId(), 'child', $contentType), ['expand' => self::DEFAULT_EXPAND]),
201
            ContentSearchResult::class
202
        );
203
    }
204
205
    /**
206
     * @param AbstractContent $content
207
     * @param string|null $contentType
208
     * @return ContentSearchResult
209
     * @throws HttpClientException
210
     * @throws JsonException
211
     */
212
    public function descendants(AbstractContent $content, ?string $contentType = null): ContentSearchResult
213
    {
214
        return $this->hydrateResponse(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->hydrateRes...entSearchResult::class) returns the type CloudPlayDev\ConfluenceClient\Entity\Hydratable which includes types incompatible with the type-hinted return CloudPlayDev\ConfluenceC...ity\ContentSearchResult.
Loading history...
215
            $this->httpGet(self::getRestfulUri('content', $content->getId(), 'descendant', $contentType)),
216
            ContentSearchResult::class
217
        );
218
    }
219
220
    /**
221
     * @see https://docs.atlassian.com/atlassian-confluence/REST/6.6.0/#contentbody/convert/{to}-convert
222
     * @param ContentBody $convertBody
223
     * @param string $to
224
     * @param AbstractContent|null $abstractContent
225
     * @return ContentBody
226
     */
227
    public function convert(ContentBody $convertBody, string $to = 'view', ?AbstractContent $abstractContent = null): ContentBody
228
    {
229
        $queryParameter = [];
230
231
        if ($abstractContent && $abstractContent->getId() !== null) {
232
            $queryParameter['pageIdContext'] = $abstractContent->getId();
233
        }
234
235
        if ($abstractContent && $abstractContent->getSpace() !== null) {
236
            $queryParameter['spaceKeyContext'] = $abstractContent->getSpace();
237
        }
238
239
        Assert::true(ContentBody::isSupported($to), 'This conversion target is not supported.');
240
241
        $data = [
242
            'representation' => $convertBody->getRepresentation(),
243
            'value' => $convertBody->getValue()
244
        ];
245
246
        return $this->hydrateResponse(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->hydrateRes...ity\ContentBody::class) returns the type CloudPlayDev\ConfluenceClient\Entity\Hydratable which includes types incompatible with the type-hinted return CloudPlayDev\ConfluenceClient\Entity\ContentBody.
Loading history...
247
            $this->httpPost(
248
                self::getRestfulUri('contentbody', 'convert', $to),
249
                $queryParameter,
250
                $data
251
            ),
252
            ContentBody::class
253
        );
254
255
    }
256
257
    /**
258
     * Returns the history of a particular piece of content, sorted by version number in descending order.
259
     *
260
     * @param int $contentId
261
     * @return Hydratable
262
     * @throws HttpClientException
263
     */
264
    public function history(int $contentId): Hydratable
265
    {
266
        return $this->hydrateResponse(
267
            $this->httpGet(self::getRestfulUri('content', $contentId, 'history')),
268
            ContentHistory::class
269
        );
270
    }
271
}
272