Passed
Push — main ( a33de3...4370d9 )
by Artem
02:12
created

Content::findOneBy()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

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