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:
1 | <?php |
||
11 | class Symlink extends DeploystrategyAbstract |
||
12 | { |
||
13 | /** |
||
14 | * Creates a symlink with lots of error-checking |
||
15 | * |
||
16 | * @param string $source |
||
17 | * @param string $dest |
||
18 | * @return bool |
||
19 | * @throws \ErrorException |
||
20 | */ |
||
21 | 18 | public function createDelegate($source, $dest) |
|
22 | { |
||
23 | 18 | $sourcePath = $this->getSourceDir() . '/' . $this->removeTrailingSlash($source); |
|
24 | 18 | $destPath = $this->getDestDir() . '/' . $this->removeTrailingSlash($dest); |
|
25 | |||
26 | 18 | if (!is_file($sourcePath) && !is_dir($sourcePath)) { |
|
27 | throw new \ErrorException("Could not find path '$sourcePath'"); |
||
28 | } |
||
29 | |||
30 | /* |
||
31 | |||
32 | Assume app/etc exists, app/etc/a does not exist unless specified differently |
||
33 | |||
34 | OK dir app/etc/a --> link app/etc/a to dir |
||
35 | OK dir app/etc/ --> link app/etc/dir to dir |
||
36 | OK dir app/etc --> link app/etc/dir to dir |
||
37 | |||
38 | OK dir/* app/etc --> for each dir/$file create a target link in app/etc |
||
39 | OK dir/* app/etc/ --> for each dir/$file create a target link in app/etc |
||
40 | OK dir/* app/etc/a --> for each dir/$file create a target link in app/etc/a |
||
41 | OK dir/* app/etc/a/ --> for each dir/$file create a target link in app/etc/a |
||
42 | |||
43 | OK file app/etc --> link app/etc/file to file |
||
44 | OK file app/etc/ --> link app/etc/file to file |
||
45 | OK file app/etc/a --> link app/etc/a to file |
||
46 | OK file app/etc/a --> if app/etc/a is a file throw exception unless force is set, in that case rm and see above |
||
47 | OK file app/etc/a/ --> link app/etc/a/file to file regardless if app/etc/a existst or not |
||
48 | |||
49 | */ |
||
50 | |||
51 | // Symlink already exists |
||
52 | 18 | if (is_link($destPath)) { |
|
53 | 1 | if (realpath(readlink($destPath)) == realpath($sourcePath)) { |
|
54 | // .. and is equal to current source-link |
||
55 | return true; |
||
56 | } |
||
57 | 1 | unlink($destPath); |
|
58 | } |
||
59 | |||
60 | // Create all directories up to one below the target if they don't exist |
||
61 | 18 | $destDir = dirname($destPath); |
|
62 | 18 | if (!file_exists($destDir)) { |
|
63 | 3 | mkdir($destDir, 0777, true); |
|
64 | } |
||
65 | |||
66 | // Handle source to dir linking, |
||
67 | // e.g. Namespace_Module.csv => app/locale/de_DE/ |
||
68 | // Namespace/ModuleDir => Namespace/ |
||
69 | // Namespace/ModuleDir => Namespace/, but Namespace/ModuleDir may exist |
||
70 | // Namespace/ModuleDir => Namespace/ModuleDir, but ModuleDir may exist |
||
71 | |||
72 | 18 | if (file_exists($destPath) && is_dir($destPath)) { |
|
73 | 7 | if (basename($sourcePath) === basename($destPath)) { |
|
74 | 2 | if ($this->isForced()) { |
|
75 | 1 | $this->filesystem->remove($destPath); |
|
76 | } else { |
||
77 | 2 | throw new \ErrorException("Target $dest already exists (set extra.magento-force to override)"); |
|
78 | } |
||
79 | } else { |
||
80 | 7 | $destPath .= '/' . basename($source); |
|
81 | } |
||
82 | 7 | return $this->create($source, substr($destPath, strlen($this->getDestDir()) + 1)); |
|
83 | } |
||
84 | |||
85 | // From now on $destPath can't be a directory, that case is already handled |
||
86 | |||
87 | // If file exists and force is not specified, throw exception unless FORCE is set |
||
88 | // existing symlinks are already handled |
||
89 | 17 | View Code Duplication | if (file_exists($destPath)) { |
|
|||
90 | if ($this->isForced()) { |
||
91 | unlink($destPath); |
||
92 | } else { |
||
93 | throw new \ErrorException( |
||
94 | "Target $dest already exists and is not a symlink (set extra.magento-force to override)" |
||
95 | ); |
||
96 | } |
||
97 | } |
||
98 | |||
99 | 17 | $relSourcePath = $this->getRelativePath($destPath, $sourcePath); |
|
100 | |||
101 | // Create symlink |
||
102 | 17 | $destPath = str_replace('\\', '/', $destPath); |
|
103 | 17 | if (false === $this->symlink($relSourcePath, $destPath, $sourcePath)) { |
|
104 | $msg = "An error occured while creating symlink\n" . $relSourcePath . " -> " . $destPath; |
||
105 | if ('\\' === DIRECTORY_SEPARATOR) { |
||
106 | $msg .= "\nDo you have admin privileges?"; |
||
107 | } |
||
108 | throw new \ErrorException($msg); |
||
109 | } |
||
110 | |||
111 | // Check we where able to create the symlink |
||
112 | // if (false === $destPath = @readlink($destPath)) { |
||
113 | // throw new \ErrorException("Symlink $destPath points to target $destPath"); |
||
114 | // } |
||
115 | 17 | $this->addDeployedFile($destPath); |
|
116 | |||
117 | 17 | return true; |
|
118 | } |
||
119 | |||
120 | /** |
||
121 | * @param $relSourcePath |
||
122 | * @param $destPath |
||
123 | * @param $absSourcePath |
||
124 | * |
||
125 | * @return bool |
||
126 | */ |
||
127 | 17 | protected function symlink($relSourcePath, $destPath, $absSourcePath) |
|
128 | { |
||
129 | 17 | $sourcePath = $relSourcePath; |
|
130 | // make symlinks always absolute on windows because of #142 |
||
131 | 17 | if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { |
|
132 | $sourcePath = str_replace('/', '\\', $absSourcePath); |
||
133 | } |
||
134 | 17 | return symlink($sourcePath, $destPath); |
|
135 | } |
||
136 | |||
137 | /** |
||
138 | * Returns the relative path from $from to $to |
||
139 | * |
||
140 | * This is utility method for symlink creation. |
||
141 | * Orig Source: http://stackoverflow.com/a/2638272/485589 |
||
142 | */ |
||
143 | 17 | public function getRelativePath($from, $to) |
|
176 | } |
||
177 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.