Completed
Push — 3.0 ( 46111f...d5ff83 )
by Daniel
02:06
created

Symlink::createDelegate()   D

Complexity

Conditions 14
Paths 42

Size

Total Lines 98
Code Lines 36

Duplication

Lines 9
Ratio 9.18 %

Code Coverage

Tests 27
CRAP Score 21.8059

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 9
loc 98
ccs 27
cts 41
cp 0.6585
rs 4.9516
cc 14
eloc 36
nc 42
nop 2
crap 21.8059

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Composer Magento Installer
4
 */
5
6
namespace MagentoHackathon\Composer\Magento\Deploystrategy;
7
8
/**
9
 * Symlink deploy strategy
10
 */
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 1
        }
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 3
        }
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 1
                } else {
77 1
                    throw new \ErrorException("Target $dest already exists (set extra.magento-force to override)");
78
                }
79 1
            } 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)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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)
144
    {
145 17
        $from = str_replace('\\', '/', $from);
146 17
        $to = str_replace('\\', '/', $to);
147
148 17
        $from = str_replace(array('/./', '//'), '/', $from);
149 17
        $to = str_replace(array('/./', '//'), '/', $to);
150
151 17
        $from = explode('/', $from);
152 17
        $to = explode('/', $to);
153
154 17
        $relPath = $to;
155
156 17
        foreach ($from as $depth => $dir) {
157
            // find first non-matching dir
158 17
            if ($dir === $to[$depth]) {
159
                // ignore this directory
160 17
                array_shift($relPath);
161 17
            } else {
162
                // get number of remaining dirs to $from
163 17
                $remaining = count($from) - $depth;
164 17
                if ($remaining > 1) {
165
                    // add traversals up to first matching dir
166 17
                    $padLength = (count($relPath) + $remaining - 1) * -1;
167 17
                    $relPath = array_pad($relPath, $padLength, '..');
168 17
                    break;
169
                } else {
170
                    $relPath[0] = './' . $relPath[0];
171
                }
172
            }
173 17
        }
174 17
        return implode('/', $relPath);
175
    }
176
}
177