Passed
Push — master ( a862c8...fef60d )
by Siad
05:54
created

Variable::resolveAllProperties()   B

Complexity

Conditions 10
Paths 10

Size

Total Lines 68
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 34
CRAP Score 10.0533

Importance

Changes 0
Metric Value
cc 10
eloc 37
c 0
b 0
f 0
nc 10
nop 1
dl 0
loc 68
ccs 34
cts 37
cp 0.9189
crap 10.0533
rs 7.6666

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
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19
20
/**
21
 * Variable Task.
22
 *
23
 * @author  Siad Ardroumli <[email protected]>
24
 * @package phing.tasks.ext.property
25
 */
26
class Variable extends PropertyTask
27
{
28
    private $remove = false;
29
30
    /**
31
     * Determines whether the property should be removed from the project.
32
     * Default is false. Once  removed, conditions that check for property
33
     * existence will find this property does not exist.
34
     *
35
     * @param boolean $b set to true to remove the property from the project.
36
     */
37
    public function setUnset($b)
38
    {
39
        $this->remove = $b;
40
    }
41
42
    /**
43
     * Execute this task.
44
     *
45
     * @throws BuildException  Description of the Exception
46
     */
47 1
    public function main()
48
    {
49 1
        if ($this->remove) {
50
            if ($this->name === null || $this->name === "") {
51
                throw new BuildException("The 'name' attribute is required with 'unset'.");
52
            }
53
            $this->removeProperty($this->name);
54
            return;
55
        }
56 1
        if ($this->file === null) {
57
            // check for the required name attribute
58 1
            if ($this->name === null || $this->name === '') {
59
                throw new BuildException("The 'name' attribute is required.");
60
            }
61
62
            // adjust the property value if necessary -- is this necessary?
63
            // Doesn't Ant do this automatically?
64 1
            $this->value = $this->getProject()->replaceProperties($this->value);
65
66
            // set the property
67 1
            $this->forceProperty($this->name, $this->value);
68
        } else {
69 1
            if (!$this->file->exists()) {
70
                throw new BuildException($this->file->getAbsolutePath() . " does not exists.");
71
            }
72 1
            $this->loadFile($this->file);
73
        }
74 1
    }
75
76
    /**
77
     * Remove a property from the project's property table and the userProperty table.
78
     * Note that Ant 1.6 uses a helper for this.
79
     */
80
    private function removeProperty($name)
81
    {
82
        $properties = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $properties is dead and can be removed.
Loading history...
83
        try {
84
            $properties = $this->getPropValue($this->getProject(), 'properties');
85
            if ($properties !== null) {
86
                unset($properties[$name]);
87
                $this->setPropValue($properties, $this->getProject(), 'properties');
88
            }
89
        } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
90
        }
91
        try {
92
            $properties = $this->getPropValue($this->getProject(), 'userProperties');
93
            if ($properties !== null) {
94
                unset($properties[$name]);
95
                $this->setPropValue($properties, $this->getProject(), 'userProperties');
96
            }
97
        } catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
98
        }
99
    }
100
101 1
    private function forceProperty($name, $value)
102
    {
103
        try {
104 1
            $properties = $this->getPropValue($this->getProject(), 'properties');
105
            if ($properties === null) {
106
                $this->getProject()->setUserProperty($name, $value);
107
            } else {
108
                $properties[$name] = $value;
109
                $this->setPropValue($properties, $this->getProject(), 'properties');
110
            }
111 1
        } catch (Exception $e) {
112 1
            $this->getProject()->setUserProperty($name, $value);
113
        }
114 1
    }
115
116
    /**
117
     * Get a private property of a class
118
     *
119
     * @param  mixed $thisClass The class
120
     * @param  string $fieldName The property to get
121
     * @return ReflectionProperty               The property value
122
     * @throws Exception
123
     */
124 1
    private function getField($thisClass, $fieldName)
125
    {
126 1
        $refClazz = new ReflectionObject($thisClass);
127 1
        if (!$refClazz->hasProperty($fieldName)) {
128 1
            throw new Exception("Invalid field : $fieldName");
129
        }
130
131
        return $refClazz->getProperty($fieldName);
132
    }
133
134
    /**
135
     * Get a private property of an object
136
     *
137
     * @param  mixed $instance the object instance
138
     * @param  string $fieldName the name of the field
139
     * @return mixed an object representing the value of the field
140
     * @throws Exception
141
     */
142 1
    private function getPropValue($instance, $fieldName)
143
    {
144 1
        $field = $this->getField($instance, $fieldName);
145
        $field->setAccessible(true);
146
        return $field->getValue($instance);
147
    }
148
149
    private function setPropValue($value, $instance, $fieldName)
150
    {
151
        $field = $this->getField($instance, $fieldName);
152
        $field->setAccessible(true);
153
        $field->setValue($instance, $value);
154
    }
155
156
    /**
157
     * load variables from a file
158
     *
159
     * @param  PhingFile $file file to load
160
     * @throws BuildException
161
     */
162 1
    protected function loadFile(PhingFile $file)
163
    {
164 1
        $props = new Properties();
165
        try {
166 1
            if ($file->exists()) {
167 1
                $props->load($file);
168
169 1
                $this->addProperties($props);
170
            } else {
171
                $this->log(
172
                    'Unable to find property file: ' . $file->getAbsolutePath(),
173 1
                    Project::MSG_VERBOSE
174
                );
175
            }
176
        } catch (IOException $ex) {
177
            throw new BuildException($ex, $this->getLocation());
178
        }
179 1
    }
180
181
    /**
182
     * iterate through a set of properties, resolve them, then assign them
183
     *
184
     * @param Properties $props The feature to be added to the Properties attribute
185
     */
186 1
    protected function addProperties($props)
187
    {
188 1
        $this->resolveAllProperties($props);
189 1
        foreach ($props->keys() as $name) {
190 1
            $this->forceProperty($name, $props->getProperty($name));
191
        }
192 1
    }
193
194
    /**
195
     * resolve properties inside a properties hashtable
196
     *
197
     * @param  Properties $props properties object to resolve
198
     * @throws BuildException  Description of the Exception
199
     */
200 1
    protected function resolveAllProperties(Properties $props)
201
    {
202 1
        foreach ($props->keys() as $name) {
203
            // There may be a nice regex/callback way to handle this
204
            // replacement, but at the moment it is pretty complex, and
205
            // would probably be a lot uglier to work into a preg_replace_callback()
206
            // system.  The biggest problem is the fact that a resolution may require
207
            // multiple passes.
208
209 1
            $value = $props->getProperty($name);
210 1
            $resolved = false;
211 1
            $resolveStack = array();
212
213 1
            $ih = PropertyHelper::getPropertyHelper($this->project);
214
215 1
            while (!$resolved) {
216 1
                $fragments = array();
217 1
                $propertyRefs = array();
218
219
                // [HL] this was ::parsePropertyString($this->value ...) ... this seems wrong
220 1
                $ih->parsePropertyString($value, $fragments, $propertyRefs);
221
222 1
                $resolved = true;
223 1
                if (count($propertyRefs) == 0) {
224 1
                    continue;
225
                }
226
227 1
                $sb = "";
228
229 1
                $j = $propertyRefs;
230
231 1
                foreach ($fragments as $fragment) {
232 1
                    if ($fragment !== null) {
233 1
                        $sb .= $fragment;
234 1
                        continue;
235
                    }
236
237 1
                    $propertyName = array_shift($j);
238 1
                    if (in_array($propertyName, $resolveStack)) {
239
                        // Should we maybe just log this as an error & move on?
240
                        // $this->log("Property ".$name." was circularly defined.", Project::MSG_ERR);
241
                        throw new BuildException("Property " . $propertyName . " was circularly defined.");
242
                    }
243
244 1
                    $fragment = $this->getProject()->getProperty($propertyName);
245 1
                    if ($fragment !== null) {
246 1
                        $sb .= $fragment;
247 1
                        continue;
248
                    }
249
250 1
                    if ($props->containsKey($propertyName)) {
251 1
                        $fragment = $props->getProperty($propertyName);
252 1
                        if (strpos($fragment, '${') !== false) {
253
                            $resolveStack[] = $propertyName;
254 1
                            $resolved = false; // parse again (could have been replaced w/ another var)
255
                        }
256
                    } else {
257
                        $fragment = "\${" . $propertyName . "}";
258
                    }
259
260 1
                    $sb .= $fragment;
261
                }
262
263 1
                $this->log("Resolved Property \"$value\" to \"$sb\"", Project::MSG_DEBUG);
264 1
                $value = $sb;
265 1
                $props->setProperty($name, $value);
266
267 1
                $this->getProject()->setProperty($name, $value);
268
            }
269
        }
270 1
    }
271
}
272