Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
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) |
||
| 41 | |||
| 42 | public function execute() |
||
| 47 | |||
| 48 | /** |
||
| 49 | * @param string $file |
||
| 50 | */ |
||
| 51 | protected function storagePath($file) |
||
| 55 | |||
| 56 | /** |
||
| 57 | * @param string $msg |
||
| 58 | */ |
||
| 59 | protected function log($msg) |
||
| 66 | |||
| 67 | public function cleanUpTmpDirs() |
||
| 81 | |||
| 82 | public function getTmpDir() |
||
| 89 | |||
| 90 | public function copyTmplate() |
||
| 96 | |||
| 97 | public function readTeamplate() |
||
| 127 | |||
| 128 | protected function MustacheTagCleaner($content) |
||
| 140 | |||
| 141 | protected function MustacheRender($items, $mustache_template) |
||
| 151 | |||
| 152 | protected function AddContentType($imageCt="jpeg") |
||
| 189 | |||
| 190 | protected function FetchReplaceableImages(&$main_file, $ns) |
||
| 191 | { |
||
| 192 | //set up basic arrays to keep track of imgs |
||
| 193 | $imgs = array(); |
||
| 194 | $imgs_replaced = array(); // so they can later be removed from media and relation file. |
||
| 195 | $newIdCounter = 1; |
||
| 196 | |||
| 197 | //iterate through all drawing containers of the xml document |
||
| 198 | foreach ($main_file->xpath('//w:drawing') as $k=>$drawing) |
||
| 199 | { |
||
| 200 | $ueid = "wrklstId".$newIdCounter; |
||
| 201 | $wasId = (string) $main_file->xpath('//w:drawing')[$k]->children($ns['wp'])->children($ns['a'])->graphic->graphicData->children($ns['pic'])->pic->blipFill->children($ns['a'])->blip->attributes($ns['r'])["embed"]; |
||
| 202 | $imgs_replaced[$wasId] = $wasId; |
||
| 203 | $main_file->xpath('//w:drawing')[$k]->children($ns['wp'])->children($ns['a'])->graphic->graphicData->children($ns['pic'])->pic->blipFill->children($ns['a'])->blip->attributes($ns['r'])["embed"] = $ueid; |
||
| 204 | |||
| 205 | $cx = (int) $main_file->xpath('//w:drawing')[$k]->children($ns['wp'])->children($ns['a'])->graphic->graphicData->children($ns['pic'])->pic->spPr->children($ns['a'])->xfrm->ext->attributes()["cx"]; |
||
| 206 | $cy = (int) $main_file->xpath('//w:drawing')[$k]->children($ns['wp'])->children($ns['a'])->graphic->graphicData->children($ns['pic'])->pic->spPr->children($ns['a'])->xfrm->ext->attributes()["cy"]; |
||
| 207 | |||
| 208 | //figure out if there is a URL saved in the description field of the img |
||
| 209 | $img_url = $this->analyseImgUrlString((string) $drawing->children($ns['wp'])->xpath('wp:docPr')[0]->attributes()["descr"]); |
||
| 210 | $main_file->xpath('//w:drawing')[$k]->children($ns['wp'])->xpath('wp:docPr')[0]->attributes()["descr"] = $img_url["rest"]; |
||
| 211 | |||
| 212 | //check https://startbigthinksmall.wordpress.com/2010/01/04/points-inches-and-emus-measuring-units-in-office-open-xml/ |
||
| 213 | // for EMUs calculation |
||
| 214 | /* |
||
| 215 | 295px @72 dpi = 1530350 EMUs = Multiplier for 72dpi pixels 5187.627118644067797 |
||
| 216 | 413px @72 dpi = 2142490 EMUs = Multiplier for 72dpi pixels 5187.627118644067797 |
||
| 217 | |||
| 218 | */ |
||
| 219 | |||
| 220 | //if there is a url, save this img as a img to be replaced |
||
| 221 | if (trim($img_url["url"])) |
||
| 222 | { |
||
| 223 | $imgs[] = array( |
||
| 224 | "cx" => $cx, |
||
| 225 | "cy" => $cy, |
||
| 226 | "width" => (int) ($cx / 5187.627118644067797), |
||
| 227 | "height" => (int) ($cy / 5187.627118644067797), |
||
| 228 | "wasId" => $wasId, |
||
| 229 | "id" => $ueid, |
||
| 230 | "url" => $img_url["url"], |
||
| 231 | ); |
||
| 232 | |||
| 233 | $newIdCounter++; |
||
| 234 | } |
||
| 235 | } |
||
| 236 | return array( |
||
| 237 | 'imgs' => $imgs, |
||
| 238 | 'imgs_replaced' => $imgs_replaced |
||
| 239 | ); |
||
| 240 | } |
||
| 241 | |||
| 242 | protected function RemoveReplaceImages($imgs_replaced, &$rels_file) |
||
| 259 | |||
| 260 | protected function InsertImages($ns, &$imgs, &$rels_file, &$main_file) |
||
| 261 | { |
||
| 262 | //define what images are allowed |
||
| 263 | $allowed_imgs = array( |
||
| 264 | 'image/gif' => '.gif', |
||
| 265 | 'image/jpeg' => '.jpeg', |
||
| 266 | 'image/png' => '.png', |
||
| 267 | 'image/bmp' => '.bmp', |
||
| 268 | ); |
||
| 269 | |||
| 270 | //iterate through replacable images |
||
| 271 | foreach ($imgs as $k=>$img) |
||
| 272 | { |
||
| 273 | //get file type of img and test it against supported imgs |
||
| 274 | if ($img_file_handle = fopen($img['url'].$this->imageManipulation, "rb")) |
||
| 275 | { |
||
| 276 | $img_data = stream_get_contents($img_file_handle); |
||
| 277 | fclose($img_file_handle); |
||
| 278 | $fi = new \finfo(FILEINFO_MIME); |
||
| 279 | |||
| 280 | $image_mime = strstr($fi->buffer($img_data), ';', true); |
||
| 281 | //dd($image_mime); |
||
| 282 | if (isset($allowed_imgs[$image_mime])) |
||
| 283 | { |
||
| 284 | $imgs[$k]['img_file_src'] = str_replace("wrklstId", "wrklst_image", $img['id']).$allowed_imgs[$image_mime]; |
||
| 285 | $imgs[$k]['img_file_dest'] = str_replace("wrklstId", "wrklst_image", $img['id']).'.jpeg'; |
||
| 286 | |||
| 287 | \Storage::disk($this->storageDisk)->put($this->local_path.'word/media/'.$imgs[$k]['img_file_src'], $img_data); |
||
| 288 | |||
| 289 | //rework img to new size and jpg format |
||
| 290 | $img_rework = \Image::make($this->storagePath($this->local_path.'word/media/'.$imgs[$k]['img_file_src'])); |
||
| 291 | $w = $img['width']; |
||
| 292 | $h = $img['height']; |
||
| 293 | if ($w > $h) |
||
| 294 | $h = null; |
||
| 295 | else |
||
| 296 | $w = null; |
||
| 297 | $img_rework->resize($w, $h, function($constraint) { |
||
| 298 | $constraint->aspectRatio(); |
||
| 299 | $constraint->upsize(); |
||
| 300 | }); |
||
| 301 | $new_height = $img_rework->height(); |
||
| 302 | $new_width = $img_rework->width(); |
||
| 303 | $img_rework->save($this->storagePath($this->local_path.'word/media/'.$imgs[$k]['img_file_dest'])); |
||
| 304 | |||
| 305 | $this->zipper->folder('word/media')->add($this->storagePath($this->local_path.'word/media/'.$imgs[$k]['img_file_dest'])); |
||
| 306 | |||
| 307 | $sxe = $rels_file->addChild('Relationship'); |
||
| 308 | $sxe->addAttribute('Id', $img['id']); |
||
| 309 | $sxe->addAttribute('Type', "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"); |
||
| 310 | $sxe->addAttribute('Target', "media/".$imgs[$k]['img_file_dest']); |
||
| 311 | |||
| 312 | //update height and width of image in document.xml |
||
| 313 | $new_height_emus = (int) ($new_height * 5187.627118644067797); |
||
| 314 | $new_width_emus = (int) ($new_width * 5187.627118644067797); |
||
| 315 | foreach ($main_file->xpath('//w:drawing') as $k=>$drawing) |
||
| 316 | { |
||
| 317 | if ($img['id'] == $main_file->xpath('//w:drawing')[$k]->children($ns['wp'])->children($ns['a'])->graphic->graphicData->children($ns['pic'])->pic->blipFill->children($ns['a'])->blip->attributes($ns['r'])["embed"]) |
||
| 318 | { |
||
| 319 | $main_file->xpath('//w:drawing')[$k]->children($ns['wp'])->children($ns['a'])->graphic->graphicData->children($ns['pic'])->pic->spPr->children($ns['a'])->xfrm->ext->attributes()["cx"] = $new_width_emus; |
||
| 320 | $main_file->xpath('//w:drawing')[$k]->children($ns['wp'])->children($ns['a'])->graphic->graphicData->children($ns['pic'])->pic->spPr->children($ns['a'])->xfrm->ext->attributes()["cy"] = $new_height_emus; |
||
| 321 | |||
| 322 | //the following also changes the contraints of the container for the img. |
||
| 323 | // probably not wanted, as this will make images larger than the constraints of the placeholder |
||
| 324 | /* |
||
| 325 | $main_file->xpath('//w:drawing')[$k]->children($ns['wp'])->inline->extent->attributes()["cx"] = $new_width_emus; |
||
| 326 | $main_file->xpath('//w:drawing')[$k]->children($ns['wp'])->inline->extent->attributes()["cy"] = $new_height_emus; |
||
| 327 | */ |
||
| 328 | break; |
||
| 329 | } |
||
| 330 | } |
||
| 331 | } |
||
| 332 | } |
||
| 333 | } |
||
| 334 | } |
||
| 335 | |||
| 336 | protected function ImageReplacer() |
||
| 382 | |||
| 383 | /** |
||
| 384 | * @param string $string |
||
| 385 | */ |
||
| 386 | protected function analyseImgUrlString($string) |
||
| 411 | |||
| 412 | protected function convertHtmlToOpenXMLTag($value, $tag = "b") |
||
| 464 | |||
| 465 | /** |
||
| 466 | * @param string $value |
||
| 467 | */ |
||
| 468 | protected function convertHtmlToOpenXML($value) |
||
| 479 | |||
| 480 | public function saveAsPdf() |
||
| 499 | } |
||
| 500 |