33
44namespace CloudPlayDev \ConfluenceClient \Api ;
55
6- use CloudPlayDev \ConfluenceClient \Entity \Content as ContentEntity ;
6+ use CloudPlayDev \ConfluenceClient \Entity \AbstractContent ;
7+ use CloudPlayDev \ConfluenceClient \Entity \ContentComment ;
8+ use CloudPlayDev \ConfluenceClient \Entity \ContentPage ;
79use CloudPlayDev \ConfluenceClient \Exception \Exception ;
810use CloudPlayDev \ConfluenceClient \Exception \RequestException ;
911use Http \Client \Exception as HttpClientException ;
1012use JsonException ;
1113use Psr \Http \Message \ResponseInterface ;
14+ use function assert ;
1215use function count ;
1316use function in_array ;
1417use function is_array ;
18+ use function is_int ;
19+ use function is_string ;
1520
21+ /**
22+ * Class Content
23+ * @package CloudPlayDev\ConfluenceClient\Api
24+ */
1625class Content extends AbstractApi
1726{
1827 /**
19- * @param int|null $contentId
28+ * ContentType for confluence attachments
29+ */
30+ public const CONTENT_TYPE_ATTACHMENT = 'attachment ' ;
31+
32+ /**
33+ * ContentType for confluence comments
34+ */
35+ public const CONTENT_TYPE_COMMENT = 'comment ' ;
36+
37+ /**
38+ * ContentType for confluence page content
39+ */
40+ public const CONTENT_TYPE_PAGE = 'page ' ;
41+
42+ /**
43+ * @param string|int|null ...$parameter
2044 * @return string
2145 */
22- private static function getContentUri (? int $ contentId = null ): string
46+ private static function getContentUri (... $ parameter ): string
2347 {
2448 $ uri = 'content ' ;
25- if (null !== $ contentId ) {
26- $ uri .= '/ ' . $ contentId ;
49+ $ parameterString = implode ('/ ' , array_filter ($ parameter ));
50+
51+ if (!empty ($ parameterString )) {
52+ $ uri .= '/ ' . $ parameterString ;
2753 }
2854
29- return $ uri ;
55+ return $ uri . ' ? ' ;
3056 }
3157
3258 /**
3359 * @param int $contentId
34- * @return ContentEntity
60+ * @return AbstractContent
3561 * @throws Exception
3662 * @throws JsonException
3763 * @throws RequestException
3864 * @throws HttpClientException
3965 */
40- public function findOneById (int $ contentId ): ContentEntity
66+ public function findOneById (int $ contentId ): AbstractContent
4167 {
42- $ response = $ this ->get (self ::getContentUri ($ contentId ));
68+ $ response = $ this ->get (self ::getContentUri ($ contentId ), [ ' expand ' => ' space,version,body.storage ' ] );
4369
4470 if ($ response ->getStatusCode () !== 200 ) {
4571 throw new RequestException ($ response );
@@ -49,13 +75,13 @@ public function findOneById(int $contentId): ContentEntity
4975 }
5076
5177 /**
52- * @param ContentEntity $page
78+ * @param AbstractContent $page
5379 * @return ResponseInterface
5480 * @throws Exception
5581 * @throws JsonException
5682 * @throws HttpClientException
5783 */
58- public function update (ContentEntity $ page ): ResponseInterface
84+ public function update (AbstractContent $ page ): ResponseInterface
5985 {
6086 $ contentId = $ page ->getId ();
6187 if (null === $ contentId ) {
@@ -80,13 +106,13 @@ public function update(ContentEntity $page): ResponseInterface
80106 }
81107
82108 /**
83- * @param ContentEntity $page
84- * @return ContentEntity
109+ * @param AbstractContent $page
110+ * @return AbstractContent
85111 * @throws Exception
86112 * @throws HttpClientException
87113 * @throws JsonException
88114 */
89- public function create (ContentEntity $ page ): ContentEntity
115+ public function create (AbstractContent $ page ): AbstractContent
90116 {
91117 if (null !== $ page ->getId ()) {
92118 throw new Exception ('Only new pages can be created. ' );
@@ -115,10 +141,10 @@ public function create(ContentEntity $page): ContentEntity
115141 }
116142
117143 /**
118- * @param ContentEntity $page
144+ * @param AbstractContent $page
119145 * @return ResponseInterface
120146 */
121- public function remove (ContentEntity $ page ): ResponseInterface
147+ public function remove (AbstractContent $ page ): ResponseInterface
122148 {
123149 $ contentId = $ page ->getId ();
124150 if (null === $ contentId ) {
@@ -128,43 +154,95 @@ public function remove(ContentEntity $page): ResponseInterface
128154 }
129155
130156 /**
131- * @param array{title?: string, spaceKey?: string, type?: string, id?: int|string, expand?: string} $searchParameter
132- * @return ContentEntity|null
157+ * @param AbstractContent $content
158+ * @param string|null $contentType
159+ * @return AbstractContent[]
160+ * @throws HttpClientException
161+ * @throws JsonException
162+ */
163+ public function children (AbstractContent $ content , ?string $ contentType = null ): array
164+ {
165+ return $ this ->parseSearchResults (
166+ $ this ->get (
167+ self ::getContentUri ($ content ->getId (), 'child ' , $ contentType ),
168+ ['expand ' => 'space,version,body.storage ' ]
169+ ),
170+ );
171+ }
172+
173+ /**
174+ * @param AbstractContent $content
175+ * @param string|null $contentType
176+ * @return AbstractContent[]
177+ * @throws HttpClientException
178+ * @throws JsonException
179+ */
180+ public function descendants (AbstractContent $ content , ?string $ contentType = null ): array
181+ {
182+ return $ this ->parseSearchResults ($ this ->get (self ::getContentUri ($ content ->getId (), 'descendant ' , $ contentType )));
183+ }
184+
185+ /**
186+ * @param array{title?: string, spaceKey?: string, type?: string, id?: int|string} $searchParameter
187+ * @return AbstractContent|null
133188 * @throws Exception
134189 * @throws JsonException
135190 */
136- public function findOneBy (array $ searchParameter ): ?ContentEntity
191+ public function findOneBy (array $ searchParameter ): ?AbstractContent
137192 {
138- $ allowedSearchParameter = ['title ' , 'spaceKey ' , 'type ' , 'id ' , ' expand ' ];
193+ $ allowedSearchParameter = ['title ' , 'spaceKey ' , 'type ' , 'id ' ];
139194 $ queryParameter = array_filter ($ searchParameter , static function (string $ searchKey ) use ($ allowedSearchParameter ) {
140195 return in_array ($ searchKey , $ allowedSearchParameter , true );
141196 }, ARRAY_FILTER_USE_KEY );
142197
198+ $ queryParameter ['expand ' ] = 'space,version,body.storage ' ;
199+
143200 $ searchResponse = $ this ->get ('content? ' , $ queryParameter );
144201
145202 if ($ searchResponse ->getStatusCode () !== 200 ) {
146203 throw new RequestException ($ searchResponse );
147204 }
148205
149- $ decodedSearchResponse = (array )json_decode ($ searchResponse ->getBody ()->getContents (), true , 512 , JSON_THROW_ON_ERROR );
206+ $ searchResults = $ this ->parseSearchResults ($ searchResponse );
207+ if (count ($ searchResults ) > 0 ) {
208+ return reset ($ searchResults );
209+ }
210+
211+ return null ;
212+ }
213+
214+ /**
215+ * @param ResponseInterface $response
216+ * @return AbstractContent[]
217+ * @throws JsonException
218+ */
219+ private function parseSearchResults (ResponseInterface $ response ): array
220+ {
221+ $ decodedSearchResponse = json_decode ($ response ->getBody ()->getContents (), true , 512 , JSON_THROW_ON_ERROR );
222+ assert (is_array ($ decodedSearchResponse ));
223+ assert (isset ($ decodedSearchResponse ['results ' ], $ decodedSearchResponse ['size ' ]));
224+ assert (is_array ($ decodedSearchResponse ['results ' ]));
225+ assert (is_int ($ decodedSearchResponse ['size ' ]));
226+
227+ $ results = [];
228+ if ($ decodedSearchResponse ['size ' ] >= 1 && count ($ decodedSearchResponse ['results ' ]) >= 1 ) {
150229
151- if (isset ($ decodedSearchResponse ['results ' ], $ decodedSearchResponse ['size ' ]) && is_array ($ decodedSearchResponse ['results ' ]) && $ decodedSearchResponse ['size ' ] >= 1 && count ($ decodedSearchResponse ['results ' ]) >= 1 ) {
152- $ firstPage = (array )reset ($ decodedSearchResponse ['results ' ]);
153- if (isset ($ firstPage ['id ' ])) {
154- return $ this ->findOneById ((int )$ firstPage ['id ' ]);
230+ foreach ($ decodedSearchResponse ['results ' ] as $ resultEntity ) {
231+ assert (is_array ($ resultEntity ));
232+ $ results [] = $ this ->deserializeContent ($ resultEntity );
155233 }
156234 }
157235
158- return null ;
236+ return $ results ;
159237 }
160238
161239 /**
162240 * @param ResponseInterface $response
163- * @return ContentEntity
241+ * @return AbstractContent
164242 * @throws Exception
165243 * @throws JsonException
166244 */
167- private function deserialize (ResponseInterface $ response ): ContentEntity
245+ private function deserialize (ResponseInterface $ response ): AbstractContent
168246 {
169247 $ responseData = $ response ->getBody ()->getContents ();
170248
@@ -179,29 +257,42 @@ private function deserialize(ResponseInterface $response): ContentEntity
179257
180258 /**
181259 * @param mixed[] $decodedData
182- * @return ContentEntity
260+ * @return AbstractContent
183261 * @throws Exception
184262 */
185- private function deserializeContent (array $ decodedData ): ContentEntity
263+ private function deserializeContent (array $ decodedData ): AbstractContent
186264 {
187- if (! isset ($ decodedData ['id ' ],
265+ assert ( isset ($ decodedData ['id ' ],
188266 $ decodedData ['type ' ],
189267 $ decodedData ['title ' ],
190- $ decodedData ['_links ' ]['self ' ],
191- $ decodedData ['space ' ]['key ' ],
192- $ decodedData ['version ' ]['number ' ])
193- ) {
194- throw new Exception ('Invalid content data ' );
268+ $ decodedData ['_links ' ]['self ' ]));
269+ assert (is_string ($ decodedData ['type ' ]));
270+
271+ switch ($ decodedData ['type ' ]) {
272+ case self ::CONTENT_TYPE_PAGE :
273+ $ content = new ContentPage ();
274+ break ;
275+ case self ::CONTENT_TYPE_COMMENT :
276+ $ content = new ContentComment ();
277+ break ;
278+ default :
279+ throw new Exception ('Invalid content type: ' . $ decodedData ['type ' ]);
195280 }
196281
197- $ page = new ContentEntity ();
198- $ page ->setId ((int )$ decodedData ['id ' ]);
199- $ page ->setType ((string )$ decodedData ['type ' ]);
200- $ page ->setTitle ((string )$ decodedData ['title ' ]);
201- $ page ->setUrl ((string )$ decodedData ['_links ' ]['self ' ]);
202- $ page ->setSpace (str_replace ('/rest/api/space/ ' , '' , (string )$ decodedData ['space ' ]['key ' ]));
203- $ page ->setVersion ((int )$ decodedData ['version ' ]['number ' ]);
282+ $ content ->setId ((int )$ decodedData ['id ' ]);
283+ $ content ->setType ($ decodedData ['type ' ]);
284+ $ content ->setTitle ((string )$ decodedData ['title ' ]);
285+ $ content ->setUrl ((string )$ decodedData ['_links ' ]['self ' ]);
286+ if (isset ($ decodedData ['space ' ]['key ' ])) {
287+ $ content ->setSpace ((string )$ decodedData ['space ' ]['key ' ]);
288+ }
289+ if (isset ($ decodedData ['version ' ]['number ' ])) {
290+ $ content ->setVersion ((int )$ decodedData ['version ' ]['number ' ]);
291+ }
292+ if (isset ($ decodedData ['body ' ]['storage ' ]['value ' ])) {
293+ $ content ->setContent ($ decodedData ['body ' ]['storage ' ]['value ' ]);
294+ }
204295
205- return $ page ;
296+ return $ content ;
206297 }
207298}
0 commit comments