Complex classes like AbstractApiClient often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use AbstractApiClient, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 30 | abstract class AbstractApiClient extends AbstractCoreApiClient implements ApiClientInterface |
||
| 31 | { |
||
| 32 | use LoggerAwareTrait; |
||
| 33 | use SearchEndpointTrait; |
||
| 34 | use ChannelTrait; |
||
| 35 | |||
| 36 | /** |
||
| 37 | * @throws \Exception |
||
| 38 | */ |
||
| 39 | public function getChannels(int $videoManagerId): Channel |
||
| 40 | { |
||
| 41 | $response = $this->makeRequest('GET', 'channels', [ |
||
| 42 | self::OPT_VIDEO_MANAGER_ID => $videoManagerId, |
||
| 43 | ]); |
||
| 44 | |||
| 45 | $rootChannel = $this->deserialize($response->getBody()->getContents(), Channel::class); |
||
| 46 | $rootChannel->setChildren($this->sortChannels($rootChannel->getChildren())); |
||
| 47 | |||
| 48 | return $rootChannel; |
||
| 49 | } |
||
| 50 | |||
| 51 | /** |
||
| 52 | * Since the VMPro API doesn't sort any more the returned channels, we have to do it on our side. |
||
| 53 | * |
||
| 54 | * @throws \Exception |
||
| 55 | */ |
||
| 56 | protected function sortChannels(ArrayCollection $channels) |
||
| 57 | { |
||
| 58 | $channels->map(function ($channel) { |
||
| 59 | $channel->setChildren($this->sortChannels($channel->getChildren())); |
||
| 60 | }); |
||
| 61 | |||
| 62 | $iterator = $channels->getIterator(); |
||
| 63 | $iterator->uasort(function ($a, $b) { |
||
| 64 | /* @var Channel $a */ |
||
| 65 | /* @var Channel $b */ |
||
| 66 | return $a->getName() > $b->getName(); |
||
| 67 | }); |
||
| 68 | |||
| 69 | return new ArrayCollection(iterator_to_array($iterator)); |
||
| 70 | } |
||
| 71 | |||
| 72 | public function createVideo( |
||
| 73 | int $videoManagerId, |
||
| 74 | string $fileName, |
||
| 75 | ?string $title = '', |
||
| 76 | ?string $description = '', |
||
| 77 | ?int $channel = null, |
||
| 78 | ?string $group = null, |
||
| 79 | ?array $keywords = [], |
||
| 80 | ?bool $autoPublish = null |
||
| 81 | ): string { |
||
| 82 | $response = $this->makeRequest('POST', 'videos', [ |
||
| 83 | self::OPT_VIDEO_MANAGER_ID => $videoManagerId, |
||
| 84 | 'json' => $this->buildJsonParameters( |
||
| 85 | compact('fileName'), // Required parameters |
||
| 86 | compact('title', 'description', 'channel', 'group', 'keywords', 'autoPublish') // Optional parameters |
||
| 87 | ), |
||
| 88 | ]); |
||
| 89 | |||
| 90 | $videoLocation = $response->getHeader('location')[0]; |
||
| 91 | |||
| 92 | $pieces = explode('/', $videoLocation); |
||
| 93 | |||
| 94 | return end($pieces); |
||
| 95 | } |
||
| 96 | |||
| 97 | public function getVideos(int $videoManagerId, ?VideosRequestParameters $parameters = null): ArrayCollection |
||
| 98 | { |
||
| 99 | $options = [ |
||
| 100 | self::OPT_VIDEO_MANAGER_ID => $videoManagerId, |
||
| 101 | ]; |
||
| 102 | |||
| 103 | if ($parameters) { |
||
| 104 | $query = http_build_query($parameters->getContainer(), '', '&', PHP_QUERY_RFC3986); |
||
| 105 | $options['query'] = preg_replace('/%5B[0-9]+%5D/simU', '%5B%5D', $query); |
||
| 106 | } |
||
| 107 | |||
| 108 | $response = $this->makeRequest('GET', 'videos', $options); |
||
| 109 | $response = json_encode(json_decode($response->getBody()->getContents(), true)['videos']); |
||
| 110 | |||
| 111 | return $this->deserialize($response, 'ArrayCollection<'.Video::class.'>'); |
||
| 112 | } |
||
| 113 | |||
| 114 | public function getCount(int $videoManagerId, ?VideosRequestParameters $parameters = null): int |
||
| 115 | { |
||
| 116 | $options = [ |
||
| 117 | self::OPT_VIDEO_MANAGER_ID => $videoManagerId, |
||
| 118 | ]; |
||
| 119 | |||
| 120 | if ($parameters) { |
||
| 121 | $query = http_build_query($parameters->getContainer(), '', '&', PHP_QUERY_RFC3986); |
||
| 122 | $options['query'] = preg_replace('/%5B[0-9]+%5D/simU', '%5B%5D', $query); |
||
| 123 | } |
||
| 124 | |||
| 125 | $response = $this->makeRequest('GET', 'videos', $options); |
||
| 126 | |||
| 127 | return json_decode($response->getBody()->getContents(), true)['total']; |
||
| 128 | } |
||
| 129 | |||
| 130 | public function getVideoUploadUrl(int $videoManagerId, string $videoId): string |
||
| 131 | { |
||
| 132 | $response = $this->makeRequest('GET', sprintf('videos/%s/url', $videoId), [ |
||
| 133 | self::OPT_VIDEO_MANAGER_ID => $videoManagerId, |
||
| 134 | ]); |
||
| 135 | |||
| 136 | return $response->getHeader('location')[0]; |
||
| 137 | } |
||
| 138 | |||
| 139 | public function updateVideo( |
||
| 140 | int $videoManagerId, |
||
| 141 | string $videoId, |
||
| 142 | string $title, |
||
| 143 | string $description, |
||
| 144 | ?bool $autoPublish = null |
||
| 145 | ): void { |
||
| 146 | $this->makeRequest('PATCH', sprintf('videos/%s', $videoId), [ |
||
| 147 | self::OPT_VIDEO_MANAGER_ID => $videoManagerId, |
||
| 148 | 'json' => $this->buildJsonParameters([], compact('title', 'description', 'autoPublish')), |
||
| 149 | ]); |
||
| 150 | } |
||
| 151 | |||
| 152 | public function addVideoToChannel(int $videoManagerId, string $videoId, int $channelId): void |
||
| 153 | { |
||
| 154 | $this->makeRequest('POST', sprintf('channels/%u/videos/%s', $channelId, $videoId), [ |
||
| 155 | self::OPT_VIDEO_MANAGER_ID => $videoManagerId, |
||
| 156 | ]); |
||
| 157 | } |
||
| 158 | |||
| 159 | public function removeVideoFromChannel(int $videoManagerId, string $videoId, int $channelId): void |
||
| 160 | { |
||
| 161 | $this->makeRequest('DELETE', sprintf('channels/%u/videos/%s', $channelId, $videoId), [ |
||
| 162 | self::OPT_VIDEO_MANAGER_ID => $videoManagerId, |
||
| 163 | ]); |
||
| 164 | } |
||
| 165 | |||
| 166 | public function setCustomMetaData(int $videoManagerId, string $videoId, array $metadata): void |
||
| 167 | { |
||
| 168 | $this->makeRequest('PATCH', sprintf('videos/%s/metadata', $videoId), [ |
||
| 169 | self::OPT_VIDEO_MANAGER_ID => $videoManagerId, |
||
| 170 | 'json' => $metadata, |
||
| 171 | ]); |
||
| 172 | } |
||
| 173 | |||
| 174 | public function getEmbedCode( |
||
| 175 | int $videoManagerId, |
||
| 176 | string $videoId, |
||
| 177 | string $playerDefinitionId, |
||
| 178 | string $embedType = 'html' |
||
| 179 | ): EmbedCode { |
||
| 180 | $url = sprintf( |
||
| 181 | 'videos/%s/embed-codes?player_definition_id=%s&embed_type=%s', |
||
| 182 | $videoId, |
||
| 183 | $playerDefinitionId, |
||
| 184 | $embedType |
||
| 185 | ); |
||
| 186 | |||
| 187 | if ($this->cacheTtl) { |
||
| 188 | $url = sprintf('%s&token_lifetime_in_seconds=%s', $url, $this->cacheTtl); |
||
| 189 | } |
||
| 190 | |||
| 191 | $response = $this->makeRequest('GET', $url, [self::OPT_VIDEO_MANAGER_ID => $videoManagerId]); |
||
| 192 | |||
| 193 | $data = \json_decode($response->getBody()->getContents(), true); |
||
| 194 | $embedCode = new EmbedCode(); |
||
| 195 | $embedCode->setCode($data['embedCode']); |
||
| 196 | |||
| 197 | return $embedCode; |
||
| 198 | } |
||
| 199 | |||
| 200 | public function deleteVideo(int $videoManagerId, string $videoId): void |
||
| 201 | { |
||
| 202 | $this->makeRequest('DELETE', sprintf('videos/%s', $videoId), [ |
||
| 203 | self::OPT_VIDEO_MANAGER_ID => $videoManagerId, |
||
| 204 | ]); |
||
| 205 | } |
||
| 206 | |||
| 207 | public function getVideo(int $videoManagerId, string $videoId, ?VideoRequestParameters $parameters = null): Video |
||
| 208 | { |
||
| 209 | $options = [ |
||
| 210 | self::OPT_VIDEO_MANAGER_ID => $videoManagerId, |
||
| 211 | ]; |
||
| 212 | |||
| 213 | if ($parameters) { |
||
| 214 | $options['query'] = $parameters->getContainer(); |
||
| 215 | } |
||
| 216 | |||
| 217 | $response = $this->makeRequest( |
||
| 218 | 'GET', |
||
| 219 | sprintf('videos/%s', $videoId), |
||
| 220 | $options |
||
| 221 | ); |
||
| 222 | |||
| 223 | return $this->deserialize($response->getBody()->getContents(), Video::class); |
||
| 224 | } |
||
| 225 | |||
| 226 | private function buildAttachment(array $data): ?Attachment |
||
| 227 | { |
||
| 228 | if (isset($data['data']['id'], $data['data']['fileName'], $data['data']['downloadUrl'], $data['data']['fileSize'], $data['type']['name'])) { |
||
| 229 | $attachment = new Attachment(); |
||
| 230 | $attachment->setId($data['data']['id']); |
||
| 231 | $attachment->setFileName($data['data']['fileName']); |
||
| 232 | $attachment->setDownloadUrl($data['data']['downloadUrl']); |
||
| 233 | $attachment->setFileSize($data['data']['fileSize']); |
||
| 234 | $attachment->setType($data['type']['name']); |
||
| 235 | |||
| 236 | return $attachment; |
||
| 237 | } |
||
| 238 | |||
| 239 | return null; |
||
| 240 | } |
||
| 241 | |||
| 242 | /** |
||
| 243 | * {@inheritDoc} |
||
| 244 | */ |
||
| 245 | public function getAttachments(int $videoManagerId, string $videoId): ArrayCollection |
||
| 246 | { |
||
| 247 | $response = $this->makeRequest( |
||
| 248 | 'GET', |
||
| 249 | sprintf('videos/%s/attachments', $videoId), |
||
| 250 | [self::OPT_VIDEO_MANAGER_ID => $videoManagerId] |
||
| 251 | ); |
||
| 252 | |||
| 253 | $collection = new ArrayCollection(); |
||
| 254 | |||
| 255 | foreach (json_decode($response->getBody()->getContents(), true) as $row) { |
||
| 256 | if ($attachment = $this->buildAttachment($row)) { |
||
|
|
|||
| 257 | $collection->add($attachment); |
||
| 258 | } |
||
| 259 | } |
||
| 260 | |||
| 261 | return $collection; |
||
| 262 | } |
||
| 263 | |||
| 264 | /** |
||
| 265 | * {@inheritDoc} |
||
| 266 | */ |
||
| 267 | public function getChannelAttachments(int $videoManagerId, int $channelId): ArrayCollection |
||
| 268 | { |
||
| 269 | $response = $this->makeRequest( |
||
| 270 | 'GET', |
||
| 271 | sprintf('channels/%u/attachments', $channelId), |
||
| 272 | [self::OPT_VIDEO_MANAGER_ID => $videoManagerId] |
||
| 273 | ); |
||
| 274 | |||
| 275 | $collection = new ArrayCollection(); |
||
| 276 | |||
| 277 | foreach (json_decode($response->getBody()->getContents(), true) as $row) { |
||
| 278 | if ($attachment = $this->buildAttachment($row)) { |
||
| 279 | $collection->add($attachment); |
||
| 280 | } |
||
| 281 | } |
||
| 282 | |||
| 283 | return $collection; |
||
| 284 | } |
||
| 285 | |||
| 286 | /** |
||
| 287 | * {@inheritDoc} |
||
| 288 | */ |
||
| 289 | public function getKeywords(int $videoManagerId, ?string $videoId): ArrayCollection |
||
| 290 | { |
||
| 291 | $uri = is_null($videoId) |
||
| 292 | ? 'keyword/find' |
||
| 293 | : sprintf('videos/%s/keywords', $videoId); |
||
| 294 | |||
| 295 | $response = $this->makeRequest( |
||
| 296 | 'GET', |
||
| 297 | $uri, |
||
| 298 | [self::OPT_VIDEO_MANAGER_ID => $videoManagerId] |
||
| 299 | ); |
||
| 300 | |||
| 301 | return $this->deserialize($response->getBody()->getContents(), 'ArrayCollection<'.Keyword::class.'>'); |
||
| 302 | } |
||
| 303 | |||
| 304 | public function updateKeywords(int $videoManagerId, string $videoId, array $keywords): void |
||
| 305 | { |
||
| 306 | //remove all keywords |
||
| 307 | foreach ($this->getKeywords($videoManagerId, $videoId) as $keyword) { |
||
| 308 | $this->deleteKeyword($videoManagerId, $videoId, $keyword->getId()); |
||
| 309 | } |
||
| 310 | |||
| 311 | //add new |
||
| 312 | foreach ($keywords as $keyword) { |
||
| 313 | $this->makeRequest('POST', sprintf('videos/%s/keywords', $videoId), [ |
||
| 314 | self::OPT_VIDEO_MANAGER_ID => $videoManagerId, |
||
| 315 | 'json' => ['text' => $keyword], |
||
| 316 | ]); |
||
| 317 | } |
||
| 318 | } |
||
| 319 | |||
| 320 | public function deleteKeyword(int $videoManagerId, string $videoId, int $keywordId): void |
||
| 326 | |||
| 327 | public function searchVideos( |
||
| 328 | int $videoManagerId, |
||
| 329 | ?VideosRequestParameters $parameters = null, |
||
| 330 | ?string $searchQuery = null |
||
| 331 | ): VideoCollection { |
||
| 332 | $options = $this->getRequestOptionsForSearchVideosEndpoint($videoManagerId, $parameters); |
||
| 333 | if ($searchQuery) { |
||
| 334 | $options['query'] = sprintf('(%s) AND (%s)', $options['query'], $searchQuery); |
||
| 335 | } |
||
| 336 | $response = $this->makeRequest('POST', 'search', ['json' => $options]); |
||
| 337 | $response = $this->normalizeSearchVideosResponse($response->getBody()->getContents()); |
||
| 338 | |||
| 339 | return $this->deserialize($response, VideoCollection::class); |
||
| 340 | } |
||
| 341 | |||
| 342 | public function searchChannels( |
||
| 343 | int $videoManagerId, |
||
| 344 | ?ChannelsRequestParameters $parameters = null |
||
| 345 | ): ChannelCollection { |
||
| 358 | |||
| 359 | /** |
||
| 360 | * {@inheritDoc} |
||
| 361 | */ |
||
| 362 | public function getVideoManagers(): ArrayCollection |
||
| 368 | |||
| 369 | /** |
||
| 370 | * {@inheritDoc} |
||
| 371 | */ |
||
| 372 | public function getVideoDownloadUrls(int $videoManagerId, string $videoId): ArrayCollection |
||
| 386 | |||
| 387 | public function createThumbnailByTimestamp(int $videoManagerId, string $videoId, int $timestamp): ?ThumbnailInterface |
||
| 405 | |||
| 406 | public function getThumbnail(int $videoManagerId, string $videoId, int $thumbnailId): ?ThumbnailInterface |
||
| 428 | |||
| 429 | public function updateThumbnail(int $videoManagerId, string $videoId, int $thumbnailId, bool $active): void |
||
| 442 | |||
| 443 | public function getUserInfo(string $token): UserInfo |
||
| 461 | |||
| 462 | /** |
||
| 463 | * {@inheritdoc} |
||
| 464 | */ |
||
| 465 | public function getTranscodingStatus(int $videoManagerId, string $videoId): ArrayCollection |
||
| 481 | |||
| 482 | public function getPlayers(int $videoManagerId): ArrayCollection |
||
| 496 | } |
||
| 497 |
This check looks for function or method calls that always return null and whose return value is assigned to a variable.
The method
getObject()can return nothing but null, so it makes no sense to assign that value to a variable.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.