Total Complexity | 41 |
Total Lines | 357 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 1 | Features | 1 |
Complex classes like Export 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.
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 Export, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
26 | abstract class Export |
||
27 | { |
||
28 | use Formats; |
||
29 | |||
30 | /** @var object */ |
||
31 | protected $media; |
||
32 | |||
33 | /** @var array */ |
||
34 | protected $path_info; |
||
35 | |||
36 | /** @var string */ |
||
37 | protected $strict = "-2"; |
||
38 | |||
39 | /** @var string */ |
||
40 | protected $tmp_dir; |
||
41 | |||
42 | /** |
||
43 | * Export constructor. |
||
44 | * @param Media $media |
||
45 | */ |
||
46 | public function __construct(Media $media) |
||
47 | { |
||
48 | $this->media = $media; |
||
49 | $this->path_info = pathinfo($media->getPath()); |
||
50 | } |
||
51 | |||
52 | /** |
||
53 | * @param string $path |
||
54 | * @param array $clouds |
||
55 | * @param bool $metadata |
||
56 | * @return mixed |
||
57 | * @throws Exception |
||
58 | */ |
||
59 | public function save(string $path = null, array $clouds = [], bool $metadata = true) |
||
60 | { |
||
61 | /** |
||
62 | * Synopsis |
||
63 | * ------------------------------------------------------------------------------ |
||
64 | * 1. Create directory path, path info array, and temporary folders(if it is required). |
||
65 | * 2. Build object and run FFmpeg to package media content and save on the local machine. |
||
66 | * 3. If the cloud is specified, entire packaged files will be uploaded to clouds. |
||
67 | * 4. If files were saved into a tmp folder, then they will be moved to the local path(if the path is specified). |
||
68 | * 5. Return all video and also streams' metadata and save as a json file on the local machine(it won't save metadata to clouds because of some security concerns). |
||
69 | * 6. In the end, clear all tmp files. |
||
70 | * ------------------------------------------------------------------------------ |
||
71 | */ |
||
72 | |||
73 | $this->createPathInfoAndTmpDir($path, $clouds); |
||
74 | $this->runFFmpeg(); |
||
75 | CloudManager::saveToClouds($clouds, $this->tmp_dir); |
||
76 | $this->moveTmpFolder($path); |
||
77 | |||
78 | return $metadata ? (new Metadata($this))->extract() : $this; |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * @param $path |
||
83 | * @param $clouds |
||
84 | * @throws Exception |
||
85 | */ |
||
86 | private function createPathInfoAndTmpDir($path, $clouds): void |
||
87 | { |
||
88 | if (null !== $path) { |
||
89 | $this->path_info = pathinfo($path); |
||
90 | FileManager::makeDir($this->path_info["dirname"]); |
||
91 | } |
||
92 | |||
93 | if ($clouds) { |
||
94 | $this->tmpDirectory($path); |
||
95 | } |
||
96 | |||
97 | if (null === $path && $this->media->isTmp() && !$clouds) { |
||
98 | throw new InvalidArgumentException("You need to specify a path. It is not possible to save to a tmp directory"); |
||
99 | } |
||
100 | } |
||
101 | |||
102 | /** |
||
103 | * @param $path |
||
104 | * @throws Exception |
||
105 | */ |
||
106 | private function tmpDirectory($path) |
||
107 | { |
||
108 | if (null !== $path) { |
||
109 | $basename = pathinfo($path, PATHINFO_BASENAME); |
||
110 | } else { |
||
111 | $basename = Helper::randomString(); |
||
112 | } |
||
113 | |||
114 | $this->tmp_dir = FileManager::tmpDir(); |
||
115 | $this->path_info = pathinfo($this->tmp_dir . $basename); |
||
116 | } |
||
117 | |||
118 | /** |
||
119 | * Run FFmpeg to package media content |
||
120 | */ |
||
121 | private function runFFmpeg(): void |
||
122 | { |
||
123 | try { |
||
124 | $this->media |
||
125 | ->addFilter($this->getFilter()) |
||
126 | ->save($this->getFormat(), $this->getPath()); |
||
127 | } catch (ExceptionInterface $e) { |
||
128 | throw new RuntimeException(sprintf("There was an error saving files: \n\n reason: \n %s", $e->getMessage()), |
||
129 | $e->getCode(), |
||
130 | $e |
||
131 | ); |
||
132 | } |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * @return Filter |
||
137 | */ |
||
138 | abstract protected function getFilter(): Filter; |
||
139 | |||
140 | /** |
||
141 | * @return string |
||
142 | */ |
||
143 | private function getPath(): string |
||
144 | { |
||
145 | $dirname = str_replace("\\", "/", $this->path_info["dirname"]); |
||
146 | $filename = substr($this->path_info["filename"], -100); |
||
147 | $path = ''; |
||
148 | |||
149 | if ($this instanceof DASH) { |
||
150 | $path = $dirname . "/" . $filename . ".mpd"; |
||
151 | } elseif ($this instanceof HLS) { |
||
152 | $representations = $this->getRepresentations(); |
||
153 | $path = $dirname . "/" . $filename . "_" . end($representations)->getHeight() . "p.m3u8"; |
||
154 | ExportHLSPlaylist::savePlayList($dirname . DIRECTORY_SEPARATOR . $filename . ".m3u8", $this->getRepresentations(), $filename); |
||
155 | } |
||
156 | |||
157 | return $path; |
||
158 | } |
||
159 | |||
160 | /** |
||
161 | * @param string|null $path |
||
162 | * @throws Exception |
||
163 | */ |
||
164 | private function moveTmpFolder(?string $path) |
||
165 | { |
||
166 | if ($this->tmp_dir && $path) { |
||
167 | FileManager::moveDir($this->tmp_dir, pathinfo($path, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR); |
||
168 | $this->path_info = pathinfo($path); |
||
169 | $this->tmp_dir = ''; |
||
170 | } |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * @return array |
||
175 | */ |
||
176 | public function getPathInfo(): array |
||
177 | { |
||
178 | return $this->path_info; |
||
179 | } |
||
180 | |||
181 | /** |
||
182 | * @return object|Media |
||
183 | */ |
||
184 | public function getMedia(): Media |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * @param string $strict |
||
191 | * @return Export |
||
192 | */ |
||
193 | public function setStrict(string $strict): Export |
||
194 | { |
||
195 | $this->strict = $strict; |
||
196 | return $this; |
||
197 | } |
||
198 | |||
199 | /** |
||
200 | * @return string |
||
201 | */ |
||
202 | public function getStrict(): string |
||
203 | { |
||
204 | return $this->strict; |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * @return bool |
||
209 | */ |
||
210 | public function isTmpDir(): bool |
||
211 | { |
||
212 | return (bool)$this->tmp_dir; |
||
213 | } |
||
214 | |||
215 | /** |
||
216 | * clear tmp files |
||
217 | */ |
||
218 | public function __destruct() |
||
219 | { |
||
220 | sleep(1); |
||
221 | |||
222 | if ($this->media->isTmp()) { |
||
223 | @unlink($this->media->getPath()); |
||
|
|||
224 | } |
||
225 | |||
226 | if ($this->tmp_dir) { |
||
227 | FileManager::deleteDirectory($this->tmp_dir); |
||
228 | } |
||
229 | |||
230 | if ($this instanceof HLS && $this->tmp_key_info_file) { |
||
231 | @unlink($this->getHlsKeyInfoFile()); |
||
232 | } |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * @param string $url |
||
237 | * @param string $name |
||
238 | * @param string|null $path |
||
239 | * @param string $method |
||
240 | * @param array $headers |
||
241 | * @param array $options |
||
242 | * @return mixed |
||
243 | * @throws Exception |
||
244 | * @deprecated this method is deprecated |
||
245 | */ |
||
246 | // @TODO: should be removed in the next releases. |
||
247 | public function saveToCloud( |
||
248 | string $url, |
||
249 | string $name, |
||
250 | string $path = null, |
||
251 | string $method = 'GET', |
||
252 | array $headers = [], |
||
253 | array $options = [] |
||
254 | ) |
||
255 | { |
||
256 | @trigger_error('saveToCloud method is deprecated and will be removed in a future release. Use Cloud instead', E_USER_DEPRECATED); |
||
257 | if ($this instanceof HLS && $this->getTsSubDirectory()) { |
||
258 | throw new InvalidArgumentException("It is not possible to create subdirectory in a cloud"); |
||
259 | } |
||
260 | $results = $this->saveToTemporaryFolder($path); |
||
261 | sleep(1); |
||
262 | |||
263 | $cloud = new Cloud($url, $method, $options); |
||
264 | $cloud->uploadDirectory($this->tmp_dir, ['name' => $name, 'headers' => $headers]); |
||
265 | |||
266 | $this->moveTmpFolder($path); |
||
267 | |||
268 | return $results; |
||
269 | } |
||
270 | |||
271 | /** |
||
272 | * @param array $config |
||
273 | * @param string $dest |
||
274 | * @param string|null $path |
||
275 | * @return mixed |
||
276 | * @throws Exception |
||
277 | * @deprecated this method is deprecated |
||
278 | */ |
||
279 | // @TODO: should be removed in the next releases. |
||
280 | public function saveToS3( |
||
296 | } |
||
297 | |||
298 | /** |
||
299 | * @param array $config |
||
300 | * @param string $bucket |
||
301 | * @param string|null $path |
||
302 | * @param array $options |
||
303 | * @param bool $userProject |
||
304 | * @return mixed |
||
305 | * @throws Exception |
||
306 | * @deprecated this method is deprecated |
||
307 | */ |
||
308 | // @TODO: should be removed in the next releases. |
||
309 | public function saveToGCS( |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * @param string $connectionString |
||
335 | * @param string $container |
||
336 | * @param string|null $path |
||
337 | * @return mixed |
||
338 | * @throws Exception |
||
339 | * @deprecated this method is deprecated |
||
340 | */ |
||
341 | // @TODO: should be removed in the next releases. |
||
342 | public function saveToMAS( |
||
343 | string $connectionString, |
||
344 | string $container, |
||
345 | string $path = null |
||
346 | ) |
||
347 | { |
||
348 | @trigger_error('saveToMAS method is deprecated and will be removed in a future release. Use MicrosoftAzure instead', E_USER_DEPRECATED); |
||
349 | |||
350 | if ($this instanceof HLS && $this->getTsSubDirectory()) { |
||
351 | throw new InvalidArgumentException("It is not possible to create subdirectory in a cloud"); |
||
352 | } |
||
353 | |||
354 | $results = $this->saveToTemporaryFolder($path); |
||
355 | sleep(1); |
||
356 | |||
357 | $google_cloud = new MicrosoftAzure($connectionString); |
||
358 | $google_cloud->uploadDirectory($this->tmp_dir, ['container' => $container]); |
||
359 | |||
360 | $this->moveTmpFolder($path); |
||
361 | |||
362 | return $results; |
||
363 | } |
||
364 | |||
365 | /** |
||
366 | * @param $path |
||
367 | * @return array |
||
368 | * @throws Exception |
||
369 | * @deprecated this method is deprecated |
||
370 | */ |
||
371 | // @TODO: should be removed in the next releases. |
||
372 | private function saveToTemporaryFolder($path) |
||
383 | } |
||
384 | } |
If you suppress an error, we recommend checking for the error condition explicitly: