Complex classes like DocxMustache 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 DocxMustache, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 9 | class DocxMustache |
||
| 10 | { |
||
| 11 | public $items; |
||
| 12 | public $word_doc; |
||
| 13 | public $template_file_name; |
||
| 14 | public $template_file; |
||
| 15 | public $local_path; |
||
| 16 | public $storageDisk; |
||
| 17 | public $storagePathPrefix; |
||
| 18 | public $zipper; |
||
| 19 | public $imageManipulation; |
||
| 20 | public $verbose; |
||
| 21 | |||
| 22 | public function __construct($items, $local_template_file) |
||
| 23 | { |
||
| 24 | $this->items = $items; |
||
| 25 | $this->template_file_name = basename($local_template_file); |
||
| 26 | $this->template_file = $local_template_file; |
||
| 27 | $this->word_doc = false; |
||
| 28 | $this->zipper = new \Chumper\Zipper\Zipper(); |
||
| 29 | |||
| 30 | //name of disk for storage |
||
| 31 | $this->storageDisk = 'local'; |
||
| 32 | |||
| 33 | //prefix within your storage path |
||
| 34 | $this->storagePathPrefix = 'app/'; |
||
| 35 | |||
| 36 | //if you use img urls that support manipulation via parameter |
||
| 37 | $this->imageManipulation = ''; //'&w=1800'; |
||
| 38 | |||
| 39 | $this->verbose = false; |
||
| 40 | } |
||
| 41 | |||
| 42 | public function Execute() |
||
| 43 | { |
||
| 44 | $this->CopyTmplate(); |
||
| 45 | $this->ReadTeamplate(); |
||
| 46 | } |
||
| 47 | |||
| 48 | /** |
||
| 49 | * @param string $file |
||
| 50 | */ |
||
| 51 | public function StoragePath($file) |
||
| 52 | { |
||
| 53 | return storage_path($file); |
||
| 54 | } |
||
| 55 | |||
| 56 | /** |
||
| 57 | * @param string $msg |
||
| 58 | */ |
||
| 59 | protected function Log($msg) |
||
| 60 | { |
||
| 61 | //introduce logging method here to keep track of process |
||
| 62 | // can be overwritten in extended class to log with custom preocess logger |
||
| 63 | if ($this->verbose) { |
||
| 64 | Log::error($msg); |
||
| 65 | } |
||
| 66 | } |
||
| 67 | |||
| 68 | public function CleanUpTmpDirs() |
||
| 69 | { |
||
| 70 | $now = time(); |
||
| 71 | $isExpired = ($now - (60 * 240)); |
||
| 72 | $disk = \Storage::disk($this->storageDisk); |
||
| 73 | $all_dirs = $disk->directories($this->storagePathPrefix.'DocxMustache'); |
||
| 74 | foreach ($all_dirs as $dir) { |
||
| 75 | //delete dirs older than 20min |
||
| 76 | if ($disk->lastModified($dir) < $isExpired) { |
||
| 77 | $disk->deleteDirectory($dir); |
||
| 78 | } |
||
| 79 | } |
||
| 80 | } |
||
| 81 | |||
| 82 | public function GetTmpDir() |
||
| 83 | { |
||
| 84 | $this->CleanUpTmpDirs(); |
||
| 85 | $path = $this->storagePathPrefix.'DocxMustache/'.uniqid($this->template_file).'/'; |
||
| 86 | \File::makeDirectory($this->StoragePath($path), 0775, true); |
||
| 87 | |||
| 88 | return $path; |
||
| 89 | } |
||
| 90 | |||
| 91 | public function CopyTmplate() |
||
| 92 | { |
||
| 93 | $this->Log('Get Copy of Template'); |
||
| 94 | $this->local_path = $this->GetTmpDir(); |
||
| 95 | \Storage::disk($this->storageDisk)->copy($this->storagePathPrefix.$this->template_file, $this->local_path.$this->template_file_name); |
||
| 96 | } |
||
| 97 | |||
| 98 | protected function exctractOpenXmlFile($file) |
||
| 103 | |||
| 104 | protected function ReadOpenXmlFile($file, $type = 'file') |
||
| 122 | |||
| 123 | protected function SaveOpenXmlFile($file, $folder, $content) |
||
| 124 | { |
||
| 125 | \Storage::disk($this->storageDisk) |
||
| 126 | ->put($this->local_path.$file, $content); |
||
| 127 | //add new content to word doc |
||
| 128 | if ($folder) { |
||
| 129 | $this->zipper->folder($folder) |
||
| 130 | ->add($this->StoragePath($this->local_path.$file)); |
||
| 131 | } else { |
||
| 132 | $this->zipper |
||
| 133 | ->add($this->StoragePath($this->local_path.$file)); |
||
| 134 | } |
||
| 135 | } |
||
| 136 | |||
| 137 | protected function SaveOpenXmlObjectToFile($xmlObject, $file, $folder) |
||
| 138 | { |
||
| 139 | if ($xmlString = $xmlObject->asXML()) { |
||
| 140 | $this->SaveOpenXmlFile($file, $folder, $xmlString); |
||
| 141 | } else { |
||
| 142 | throw new Exception('Cannot generate xml for '.$file); |
||
| 143 | } |
||
| 144 | } |
||
| 145 | |||
| 146 | public function ReadTeamplate() |
||
| 147 | { |
||
| 148 | $this->Log('Analyze Template'); |
||
| 149 | //get the main document out of the docx archive |
||
| 150 | $this->word_doc = $this->ReadOpenXmlFile('word/document.xml', 'file'); |
||
| 151 | |||
| 152 | $this->Log('Merge Data into Template'); |
||
| 153 | |||
| 154 | $this->word_doc = MustacheRender::render($this->items, $this->word_doc); |
||
| 155 | |||
| 156 | $this->word_doc = HtmlConversion::convert($this->word_doc); |
||
| 157 | |||
| 158 | $this->ImageReplacer(); |
||
| 159 | |||
| 160 | $this->Log('Compact Template with Data'); |
||
| 161 | |||
| 162 | $this->SaveOpenXmlFile('word/document.xml', 'word', $this->word_doc); |
||
| 163 | $this->zipper->close(); |
||
| 164 | } |
||
| 165 | |||
| 166 | protected function AddContentType($imageCt = 'jpeg') |
||
| 193 | |||
| 194 | protected function FetchReplaceableImages(&$main_file, $ns) |
||
| 195 | { |
||
| 196 | //set up basic arrays to keep track of imgs |
||
| 197 | $imgs = []; |
||
| 198 | $imgs_replaced = []; // so they can later be removed from media and relation file. |
||
| 199 | $newIdCounter = 1; |
||
| 200 | |||
| 201 | //iterate through all drawing containers of the xml document |
||
| 202 | foreach ($main_file->xpath('//w:drawing') as $k=>$drawing) { |
||
| 238 | |||
| 239 | protected function RemoveReplaceImages($imgs_replaced, &$rels_file) |
||
| 254 | |||
| 255 | protected function InsertImages($ns, &$imgs, &$rels_file, &$main_file) |
||
| 301 | |||
| 302 | protected function ImageReplacer() |
||
| 334 | |||
| 335 | /** |
||
| 336 | * @param string $string |
||
| 337 | */ |
||
| 338 | protected function AnalyseImgUrlString($string) |
||
| 368 | |||
| 369 | public function SaveAsPdf() |
||
| 388 | } |
||
| 389 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.