Complex classes like Xcloner_Archive 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 Xcloner_Archive, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
37 | class Xcloner_Archive extends Tar |
||
38 | { |
||
39 | /** |
||
40 | * Process file size per API request |
||
41 | * @var float|int |
||
42 | */ |
||
43 | private $file_size_per_request_limit = 52428800; //50MB = 52428800; 1MB = 1048576 |
||
44 | /** |
||
45 | * Files count to process per API request |
||
46 | * @var int |
||
47 | */ |
||
48 | private $files_to_process_per_request = 250; //block of 512 bytes |
||
49 | /** |
||
50 | * Compression level, 0-uncompressed, 9-maximum compression |
||
51 | * @var int |
||
52 | */ |
||
53 | private $compression_level = 0; //0-9 , 0 uncompressed |
||
54 | /** |
||
55 | * Split backup size limit |
||
56 | * Create a new backup archive file once the set size is reached |
||
57 | * @var float|int |
||
58 | */ |
||
59 | private $xcloner_split_backup_limit = 2048; //2048MB |
||
60 | /** |
||
61 | * Number of processed bytes |
||
62 | * @var int |
||
63 | */ |
||
64 | private $processed_size_bytes = 0; |
||
65 | |||
66 | /** |
||
67 | * Archive name |
||
68 | * @var string |
||
69 | */ |
||
70 | private $archive_name; |
||
71 | /** |
||
72 | * @var Tar |
||
73 | */ |
||
74 | private $backup_archive; |
||
75 | /** |
||
76 | * @var Xcloner_File_System |
||
77 | */ |
||
78 | private $filesystem; |
||
79 | /** |
||
80 | * @var Xcloner_Logger |
||
81 | */ |
||
82 | private $logger; |
||
83 | /** |
||
84 | * @var Xcloner_Settings |
||
85 | */ |
||
86 | private $xcloner_settings; |
||
87 | |||
88 | /** |
||
89 | * [__construct description] |
||
90 | * @param Xcloner $xcloner_container XCloner Container |
||
91 | * @param string $archive_name Achive Name |
||
92 | */ |
||
93 | public function __construct(Xcloner $xcloner_container, $archive_name = "") |
||
94 | { |
||
95 | $this->filesystem = $xcloner_container->get_xcloner_filesystem(); |
||
96 | $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_archive"); |
||
97 | $this->xcloner_settings = $xcloner_container->get_xcloner_settings(); |
||
98 | |||
99 | if ($value = $this->xcloner_settings->get_xcloner_option('xcloner_size_limit_per_request')) { |
||
100 | $this->file_size_per_request_limit = $value * 1024 * 1024; |
||
101 | } //MB |
||
102 | |||
103 | if ($value = $this->xcloner_settings->get_xcloner_option('xcloner_files_to_process_per_request')) { |
||
104 | $this->files_to_process_per_request = $value; |
||
105 | } |
||
106 | |||
107 | if ($value = get_option('xcloner_backup_compression_level')) { |
||
|
|||
108 | $this->compression_level = $value; |
||
109 | } |
||
110 | |||
111 | if ($value = get_option('xcloner_split_backup_limit')) { |
||
112 | $this->xcloner_split_backup_limit = $value; |
||
113 | } |
||
114 | |||
115 | $this->xcloner_split_backup_limit = $this->xcloner_split_backup_limit * 1024 * 1024; //transform to bytes |
||
116 | |||
117 | if (isset($archive_name) && $archive_name) { |
||
118 | $this->set_archive_name($archive_name); |
||
119 | } |
||
120 | } |
||
121 | |||
122 | /* |
||
123 | * Rename backup archive |
||
124 | * |
||
125 | * @param string $old_name |
||
126 | * @param string $new_name |
||
127 | * |
||
128 | */ |
||
129 | public function rename_archive($old_name, $new_name) |
||
130 | { |
||
131 | $this->logger->info(sprintf("Renaming backup archive %s to %s", $old_name, $new_name)); |
||
132 | $storage_filesystem = $this->filesystem->get_storage_filesystem(); |
||
133 | $storage_filesystem->rename($old_name, $new_name); |
||
134 | } |
||
135 | |||
136 | /* |
||
137 | * |
||
138 | * Set the backup archive name |
||
139 | * |
||
140 | */ |
||
141 | public function set_archive_name($name = "", $part = 0) |
||
142 | { |
||
143 | |||
144 | $this->archive_name = $this->filesystem->process_backup_name($name); |
||
145 | |||
146 | if ($diff_timestamp_start = $this->filesystem->get_diff_timestamp_start()) { |
||
147 | //$this->archive_name = $this->archive_name."-diff-".date("Y-m-d_H-i",$diff_timestamp_start); |
||
148 | $new_name = $this->archive_name; |
||
149 | |||
150 | if (!stristr($new_name, "-diff")) { |
||
151 | $new_name = $this->archive_name . "-diff" . date("Y-m-d_H-i", $diff_timestamp_start); |
||
152 | } |
||
153 | |||
154 | $this->archive_name = $new_name; |
||
155 | |||
156 | } |
||
157 | |||
158 | if (isset($part) and $part) { |
||
159 | $new_name = preg_replace('/-part(\d*)/', "-part" . $part, $this->archive_name); |
||
160 | if (!stristr($new_name, "-part")) { |
||
161 | $new_name = $this->archive_name . "-part" . $part; |
||
162 | } |
||
163 | |||
164 | $this->archive_name = $new_name; |
||
165 | } |
||
166 | |||
167 | return $this; |
||
168 | } |
||
169 | |||
170 | /* |
||
171 | * |
||
172 | * Returns the backup archive name |
||
173 | * |
||
174 | * @return string archive name |
||
175 | */ |
||
176 | public function get_archive_name() |
||
177 | { |
||
178 | return $this->archive_name; |
||
179 | } |
||
180 | |||
181 | /* |
||
182 | * |
||
183 | * Returns the multipart naming for the backup archive |
||
184 | * |
||
185 | * @return string multi-part backup name |
||
186 | */ |
||
187 | public function get_archive_name_multipart() |
||
188 | { |
||
189 | $new_name = preg_replace('/-part(\d*)/', "", $this->archive_name); |
||
190 | return $new_name . "-multipart" . $this->xcloner_settings->get_backup_extension_name(".csv"); |
||
191 | } |
||
192 | |||
193 | /* |
||
194 | * |
||
195 | * Returns the full backup name including extension |
||
196 | * |
||
197 | */ |
||
198 | public function get_archive_name_with_extension() |
||
199 | { |
||
200 | return $this->archive_name . $this->xcloner_settings->get_backup_extension_name(); |
||
201 | } |
||
202 | |||
203 | /* |
||
204 | * |
||
205 | * Send notification error by E-Mail |
||
206 | * |
||
207 | * @param $to |
||
208 | * @param $from |
||
209 | * @param $subject |
||
210 | * @param $backup_name |
||
211 | * @param $params |
||
212 | * @param $error_message |
||
213 | * |
||
214 | * @return bool |
||
215 | */ |
||
216 | |||
217 | /** |
||
218 | * @param string $error_message |
||
219 | */ |
||
220 | public function send_notification_error($to, $from, $subject, $backup_name, $params, $error_message) |
||
221 | { |
||
222 | |||
223 | $body = ""; |
||
224 | $body .= sprintf(__("Backup Site Url: %s"), get_site_url()); |
||
225 | $body .= "<br /><>"; |
||
226 | |||
227 | $body .= sprintf(__("Error Message: %s"), $error_message); |
||
228 | |||
229 | $this->logger->info(sprintf("Sending backup error notification to %s", $to)); |
||
230 | |||
231 | $admin_email = get_option("admin_email"); |
||
232 | |||
233 | $headers = array('Content-Type: text/html; charset=UTF-8'); |
||
234 | |||
235 | if ($admin_email and $from) { |
||
236 | $headers[] = 'From: ' . $from . ' <' . $admin_email . '>'; |
||
237 | } |
||
238 | |||
239 | $return = wp_mail($to, $subject, $body, $headers); |
||
240 | |||
241 | return $return; |
||
242 | } |
||
243 | |||
244 | /* |
||
245 | * |
||
246 | * Send backup archive notfication by E-Mail |
||
247 | * |
||
248 | * @param $to |
||
249 | * @param $from |
||
250 | * @param $subject |
||
251 | * @param $backup_name |
||
252 | * @param $params |
||
253 | * @param string $error_message |
||
254 | * @param array $additional |
||
255 | * |
||
256 | * @return bool |
||
257 | */ |
||
258 | public function send_notification( |
||
259 | $to, |
||
260 | $from, |
||
261 | $subject, |
||
262 | $backup_name, |
||
263 | $params, |
||
264 | $error_message = "", |
||
265 | $additional = array() |
||
266 | ) { |
||
267 | if (!$from) { |
||
268 | $from = "XCloner Backup"; |
||
269 | } |
||
270 | |||
271 | if (($error_message)) { |
||
272 | return $this->send_notification_error($to, $from, $subject, $backup_name, $params, $error_message); |
||
273 | } |
||
274 | |||
275 | $params = (array)$params; |
||
276 | |||
277 | if (!$subject) { |
||
278 | $subject = sprintf(__("New backup generated %s"), $backup_name); |
||
279 | } |
||
280 | |||
281 | $body = sprintf(__("Generated Backup Size: %s"), size_format($this->filesystem->get_backup_size($backup_name))); |
||
282 | $body .= "<br /><br />"; |
||
283 | |||
284 | if (isset($additional['lines_total'])) { |
||
285 | $body .= sprintf(__("Total files added: %s"), $additional['lines_total']); |
||
286 | $body .= "<br /><br />"; |
||
287 | } |
||
288 | |||
289 | $backup_parts = $this->filesystem->get_multipart_files($backup_name); |
||
290 | |||
291 | if (!$backups_counter = sizeof($backup_parts)) { |
||
292 | $backups_counter = 1; |
||
293 | } |
||
294 | |||
295 | $body .= sprintf(__("Backup Parts: %s"), $backups_counter); |
||
296 | $body .= "<br />"; |
||
297 | |||
298 | if (sizeof($backup_parts)) { |
||
299 | $body .= implode("<br />", $backup_parts); |
||
300 | $body .= "<br />"; |
||
301 | } |
||
302 | |||
303 | $body .= "<br />"; |
||
304 | |||
305 | $body .= sprintf(__("Backup Site Url: %s"), get_site_url()); |
||
306 | $body .= "<br />"; |
||
307 | |||
308 | if (isset($params['backup_params']->backup_comments)) { |
||
309 | $body .= __("Backup Comments: ").$params['backup_params']->backup_comments; |
||
310 | $body .= "<br /><br />"; |
||
311 | } |
||
312 | |||
313 | if ($this->xcloner_settings->get_xcloner_option('xcloner_enable_log')) { |
||
314 | $body .= __("Latest 50 Log Lines: ")."<br />".implode("<br />\n", |
||
315 | $this->logger->getLastDebugLines(50)); |
||
316 | } |
||
317 | |||
318 | $attachments = $this->filesystem->get_backup_attachments(); |
||
319 | |||
320 | $attachments_archive = $this->xcloner_settings->get_xcloner_tmp_path().DS."info.tgz"; |
||
321 | |||
322 | $tar = new Tar(); |
||
323 | $tar->create($attachments_archive); |
||
324 | |||
325 | foreach ($attachments as $key => $file) { |
||
326 | $tar->addFile($file, basename($file)); |
||
327 | } |
||
328 | $tar->close(); |
||
329 | |||
330 | $this->logger->info(sprintf("Sending backup notification to %s", $to)); |
||
331 | |||
332 | $admin_email = get_option("admin_email"); |
||
333 | |||
334 | $headers = array('Content-Type: text/html; charset=UTF-8', 'From: '.$from.' <'.$admin_email.'>'); |
||
335 | |||
336 | $return = wp_mail($to, $subject, $body, $headers, array($attachments_archive)); |
||
337 | |||
338 | return $return; |
||
339 | } |
||
340 | |||
341 | /* |
||
342 | * |
||
343 | * Incremental Backup method |
||
344 | * |
||
345 | */ |
||
346 | public function start_incremental_backup($backup_params, $extra_params, $init) |
||
576 | } |
||
577 | |||
578 | /* |
||
579 | * |
||
580 | * Write multipart file components |
||
581 | * |
||
582 | */ |
||
583 | private function write_multipart_file($path = "") |
||
584 | { |
||
585 | if (!$path) { |
||
586 | $path = $this->get_archive_name_with_extension(); |
||
587 | } |
||
588 | |||
589 | $file = $this->filesystem->get_filesystem("storage_filesystem_append")->getMetadata($path); |
||
590 | //print_r($file_info); |
||
591 | $line = '"'.$file['path'].'","'.$file['timestamp'].'","'.$file['size'].'"'.PHP_EOL; |
||
592 | |||
593 | |||
594 | $this->filesystem->get_filesystem("storage_filesystem_append") |
||
595 | ->write($this->get_archive_name_multipart(), $line); |
||
596 | } |
||
597 | |||
598 | /* |
||
599 | * |
||
600 | * Create a new backup part |
||
601 | * |
||
602 | */ |
||
603 | private function create_new_backup_part($part = 0) |
||
604 | { |
||
605 | //close the backup archive by adding 2*512 blocks of zero bytes |
||
606 | $this->logger->info(sprintf("Closing the backup archive %s with 2*512 zero bytes blocks.", |
||
607 | $this->get_archive_name_with_extension())); |
||
608 | $this->backup_archive->close(); |
||
609 | |||
610 | if (!$part) { |
||
611 | $old_name = $this->get_archive_name_with_extension(); |
||
612 | $this->set_archive_name($this->get_archive_name(), ++$part); |
||
613 | $this->rename_archive($old_name, $this->get_archive_name_with_extension()); |
||
614 | |||
615 | if ($this->filesystem->get_storage_filesystem()->has($this->get_archive_name_multipart())) { |
||
616 | $this->filesystem->get_storage_filesystem()->delete($this->get_archive_name_multipart()); |
||
617 | } |
||
618 | |||
619 | $this->write_multipart_file($this->get_archive_name_with_extension()); |
||
620 | |||
621 | } else { |
||
622 | $this->logger->info(sprintf("Creating new multipart info file %s", |
||
623 | $this->get_archive_name_with_extension())); |
||
624 | $this->write_multipart_file($this->get_archive_name_with_extension()); |
||
625 | } |
||
626 | |||
627 | $this->set_archive_name($this->get_archive_name(), ++$part); |
||
628 | |||
629 | $this->logger->info(sprintf("Creating new backup archive part %s", $this->get_archive_name_with_extension())); |
||
630 | |||
631 | $this->backup_archive = new Tar(); |
||
632 | $this->backup_archive->setCompression($this->compression_level); |
||
633 | $archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension()); |
||
634 | $this->backup_archive->create($archive_info->getPath().DS.$archive_info->getFilename()); |
||
635 | |||
636 | return array($archive_info, $part); |
||
637 | |||
638 | } |
||
639 | |||
640 | /* |
||
641 | * |
||
642 | * Add file to archive |
||
643 | * |
||
644 | */ |
||
645 | |||
646 | /** |
||
647 | * @param integer $append |
||
648 | */ |
||
649 | public function add_file_to_archive($file_info, $start_at_byte, $byte_limit = 0, $append, $filesystem) |
||
727 | } |
||
728 | |||
729 | /** |
||
730 | * Open a TAR archive and put the file cursor at the end for data appending |
||
731 | * |
||
732 | * If $file is empty, the tar file will be created in memory |
||
733 | * |
||
734 | * @param string $file |
||
735 | * @throws ArchiveIOException |
||
736 | */ |
||
737 | /* |
||
738 | public function openForAppend($file = '') |
||
739 | { |
||
740 | $this->file = $file; |
||
741 | $this->memory = ''; |
||
742 | $this->fh = 0; |
||
743 | |||
744 | if ($this->file) { |
||
745 | // determine compression |
||
746 | if ($this->comptype == Archive::COMPRESS_AUTO) { |
||
747 | $this->setCompression($this->complevel, $this->filetype($file)); |
||
748 | } |
||
749 | |||
750 | if ($this->comptype === Archive::COMPRESS_GZIP) { |
||
751 | $this->fh = @gzopen($this->file, 'ab'.$this->complevel); |
||
752 | } elseif ($this->comptype === Archive::COMPRESS_BZIP) { |
||
753 | $this->fh = @bzopen($this->file, 'a'); |
||
754 | } else { |
||
755 | $this->fh = @fopen($this->file, 'ab'); |
||
756 | } |
||
757 | |||
758 | if (!$this->fh) { |
||
759 | throw new ArchiveIOException('Could not open file for writing: '.$this->file); |
||
760 | } |
||
761 | } |
||
762 | $this->backup_archive->writeaccess = true; |
||
763 | $this->backup_archive->closed = false; |
||
764 | } |
||
765 | */ |
||
766 | |||
767 | /** |
||
768 | * Append data to a file to the current TAR archive using an existing file in the filesystem |
||
769 | * |
||
770 | * @param string $file path to the original file |
||
771 | * @param int $start starting reading position in file |
||
772 | * @param int $end end position in reading multiple with 512 |
||
773 | * @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with |
||
774 | * all meta data, empty to take from original |
||
775 | * @throws ArchiveIOException |
||
776 | */ |
||
777 | /* |
||
778 | * public function appendFileData($file, $fileinfo = '', $start = 0, $limit = 0) |
||
779 | { |
||
780 | $end = $start+($limit*512); |
||
781 | |||
782 | //check to see if we are at the begining of writing the file |
||
783 | if(!$start) |
||
784 | { |
||
785 | if (is_string($fileinfo)) { |
||
786 | $fileinfo = FileInfo::fromPath($file, $fileinfo); |
||
787 | } |
||
788 | } |
||
789 | |||
790 | if ($this->closed) { |
||
791 | throw new ArchiveIOException('Archive has been closed, files can no longer be added'); |
||
792 | } |
||
793 | |||
794 | $fp = fopen($file, 'rb'); |
||
795 | |||
796 | fseek($fp, $start); |
||
797 | |||
798 | if (!$fp) { |
||
799 | throw new ArchiveIOException('Could not open file for reading: '.$file); |
||
800 | } |
||
801 | |||
802 | // create file header |
||
803 | if(!$start) |
||
804 | $this->backup_archive->writeFileHeader($fileinfo); |
||
805 | |||
806 | $bytes = 0; |
||
807 | // write data |
||
808 | while ($end >=ftell($fp) and !feof($fp) ) { |
||
809 | $data = fread($fp, 512); |
||
810 | if ($data === false) { |
||
811 | break; |
||
812 | } |
||
813 | if ($data === '') { |
||
814 | break; |
||
815 | } |
||
816 | $packed = pack("a512", $data); |
||
817 | $bytes += $this->backup_archive->writebytes($packed); |
||
818 | } |
||
819 | |||
820 | |||
821 | |||
822 | //if we are not at the end of file, we return the current position for incremental writing |
||
823 | if(!feof($fp)) |
||
824 | $last_position = ftell($fp); |
||
825 | else |
||
826 | $last_position = -1; |
||
827 | |||
828 | fclose($fp); |
||
829 | |||
830 | return $last_position; |
||
831 | }*/ |
||
832 | |||
833 | /** |
||
834 | * Adds a file to a TAR archive by appending it's data |
||
835 | * |
||
836 | * @param string $archive name of the archive file |
||
837 | * @param string $file name of the file to read data from |
||
838 | * @param string $start start position from where to start reading data |
||
839 | * @throws ArchiveIOException |
||
840 | */ |
||
841 | /*public function addFileToArchive($archive, $file, $start = 0) |
||
842 | { |
||
843 | $this->openForAppend($archive); |
||
844 | return $start = $this->appendFileData($file, $start, $this->file_size_per_request_limit); |
||
845 | } |
||
846 | */ |
||
847 | |||
848 | } |
||
849 |