Passed
Push — master ( e5c614...6595be )
by Siad
13:10
created

Target   C

Complexity

Total Complexity 54

Size/Duplication

Total Lines 473
Duplicated Lines 0 %

Test Coverage

Coverage 85.71%

Importance

Changes 0
Metric Value
eloc 108
dl 0
loc 473
ccs 120
cts 140
cp 0.8571
rs 6.4799
c 0
b 0
f 0
wmc 54

30 Methods

Rating   Name   Duplication   Size   Complexity  
A setHidden() 0 5 1
A getProject() 0 3 1
A getDescription() 0 3 1
A replaceChild() 0 5 2
A setLocation() 0 3 1
A getTasks() 0 12 3
A isHidden() 0 3 1
A setDepends() 0 12 3
A getDependencies() 0 3 1
A testUnlessCondition() 0 15 4
A getHidden() 0 3 1
A setIf() 0 3 1
A performTasks() 0 10 2
A getLogSkipped() 0 7 2
A testIfCondition() 0 15 4
A setDescription() 0 3 1
A setProject() 0 3 1
A dependsOn() 0 3 1
A getLocation() 0 3 1
A __toString() 0 3 1
A addTask() 0 3 1
A parseDepends() 0 15 3
A addDataType() 0 3 1
A getName() 0 3 1
A setUnless() 0 3 1
A setName() 0 3 1
A __construct() 0 12 2
B main() 0 21 9
A setLogSkipped() 0 3 1
A addDependency() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Target 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.

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 Target, and based on these observations, apply Extract Interface, too.

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
 * The Target component. Carries all required target data. Implements the
22
 * abstract class {@link TaskContainer}
23
 *
24
 * @author    Andreas Aderhold <[email protected]>
25
 * @copyright 2001,2002 THYRELL. All rights reserved
26
 * @see       TaskContainer
27
 * @package   phing
28
 */
29
class Target implements TaskContainer
30
{
31
32
    /**
33
     * Name of target
34
     *
35
     * @var string
36
     */
37
    private $name;
38
39
    /**
40
     * Dependencies
41
     *
42
     * @var array
43
     */
44
    private $dependencies = [];
45
46
    /**
47
     * Holds objects of children of this target
48
     *
49
     * @var array
50
     */
51
    private $children = [];
52
53
    /**
54
     * The if condition from xml
55
     *
56
     * @var string
57
     */
58
    private $ifCondition = "";
59
60
    /**
61
     * The unless condition from xml
62
     *
63
     * @var string
64
     */
65
    private $unlessCondition = "";
66
67
    /**
68
     * Description of this target
69
     *
70
     * @var string
71
     */
72
    private $description;
73
74
    /**
75
     * Whether to hide target in targets list (-list -p switches)
76
     *
77
     * @var boolean
78
     */
79
    private $hidden = false;
80
81
    /**
82
     * Whether to log message as INFO or VERBOSE if target skipped
83
     *
84
     * @var boolean
85
     */
86
    private $logSkipped = false;
87
88
    /**
89
     * Rreference to project
90
     *
91
     * @var Project
92
     */
93
    private $project;
94
    private $location;
95
96 793
    public function __construct(Target $other = null)
97
    {
98 793
        if ($other !== null) {
99
            $this->name = $other->name;
100
            $this->ifCondition = $other->ifCondition;
101
            $this->unlessCondition = $other->unlessCondition;
102
            $this->dependencies = $other->dependencies;
103
            $this->location = $other->location;
104
            $this->project = $other->project;
105
            $this->description = $other->description;
106
            // The children are added to after this cloning
107
            $this->children = $other->children;
108
        }
109 793
    }
110
111
    /**
112
     * References the project to the current component.
113
     *
114
     * @param Project $project The reference to the current project
115
     */
116 792
    public function setProject(Project $project)
117
    {
118 792
        $this->project = $project;
119 792
    }
120
121
    /**
122
     * Returns reference to current project
123
     *
124
     * @return Project Reference to current porject object
125
     */
126 604
    public function getProject()
127
    {
128 604
        return $this->project;
129
    }
130
131
    /**
132
     * Sets the location of this target's definition.
133
     *
134
     * @param location location
135
     */
136 792
    public function setLocation(Location $location): void
137
    {
138 792
        $this->location = $location;
139 792
    }
140
141
    /**
142
     * Get the location of this target's definition.
143
     *
144
     * @return Location
145
     */
146 1
    public function getLocation(): Location
147
    {
148 1
        return $this->location;
149
    }
150
151
    /**
152
     * Sets the target dependencies from xml
153
     *
154
     * @param  string $depends Comma separated list of targetnames that depend on
155
     *                         this target
156
     * @throws BuildException
157
     */
158 249
    public function setDepends($depends)
159
    {
160
        // explode should be faster than strtok
161 249
        $deps = explode(',', $depends);
162 249
        for ($i = 0, $size = count($deps); $i < $size; $i++) {
163 249
            $trimmed = trim($deps[$i]);
164 249
            if ($trimmed === "") {
165 2
                throw new BuildException(
166 2
                    "Syntax Error: Depend attribute for target " . $this->getName() . " is malformed."
167
                );
168
            }
169 248
            $this->addDependency($trimmed);
170
        }
171 247
    }
172
173
    /**
174
     * Adds a singular dependent target name to the list
175
     *
176
     * @param string $dependency The dependency target to add
177
     */
178 248
    public function addDependency($dependency)
179
    {
180 248
        $this->dependencies[] = (string) $dependency;
181 248
    }
182
183
    /**
184
     * Returns reference to indexed array of the dependencies this target has.
185
     *
186
     * @return array Reference to target dependencoes
187
     */
188 792
    public function getDependencies()
189
    {
190 792
        return $this->dependencies;
191
    }
192
193
    /**
194
     * @param string $targetName Name of the target to search for
195
     * @return false|int|string
196
     */
197 7
    public function dependsOn($targetName)
198
    {
199 7
        return \array_search($targetName, $this->dependencies);
200
    }
201
202
    /**
203
     * Sets the name of the target
204
     *
205
     * @param string $name Name of this target
206
     */
207 792
    public function setName($name)
208
    {
209 792
        $this->name = (string) $name;
210 792
    }
211
212
    /**
213
     * Returns name of this target.
214
     *
215
     * @return string The name of the target
216
     */
217 564
    public function getName()
218
    {
219 564
        return (string) $this->name;
220
    }
221
222
    /**
223
     * Set target status. If true, target does not come in phing -list
224
     *
225
     * @param  boolean $flag
226
     * @return Target
227
     */
228 792
    public function setHidden($flag)
229
    {
230 792
        $this->hidden = (bool) $flag;
231
232 792
        return $this;
233
    }
234
235
    /**
236
     * Get target status. If true, target does not come in phing -list
237
     *
238
     * @return boolean
239
     */
240
    public function getHidden()
241
    {
242
        return $this->hidden;
243
    }
244
245
    /**
246
     * Alias for getHidden()
247
     *
248
     * @return boolean
249
     */
250
    public function isHidden()
251
    {
252
        return $this->getHidden();
253
    }
254
255
    /**
256
     * Adds a task element to the list of this targets child elements
257
     *
258
     * @param Task $task The task object to add
259
     */
260 790
    public function addTask(Task $task)
261
    {
262 790
        $this->children[] = $task;
263 790
    }
264
265
    /**
266
     * Adds a runtime configurable element to the list of this targets child
267
     * elements.
268
     *
269
     * @param RuntimeConfigurable $rtc The RuntimeConfigurable object
270
     */
271 4
    public function addDataType($rtc)
272
    {
273 4
        $this->children[] = $rtc;
274 4
    }
275
276
    /**
277
     * Returns an array of all tasks this target has as childrens.
278
     *
279
     * The task objects are copied here. Don't use this method to modify
280
     * task objects.
281
     *
282
     * @return array Task[]
283
     */
284 792
    public function getTasks()
285
    {
286 792
        $tasks = [];
287 792
        for ($i = 0, $size = count($this->children); $i < $size; $i++) {
288 785
            $tsk = $this->children[$i];
289 785
            if ($tsk instanceof Task) {
290
                // note: we're copying objects here!
291 785
                $tasks[] = clone $tsk;
292
            }
293
        }
294
295 792
        return $tasks;
296
    }
297
298
    /**
299
     * Set the if-condition from the XML tag, if any. The property name given
300
     * as parameter must be present so the if condition evaluates to true
301
     *
302
     * @param string $property The property name that has to be present
303
     */
304 792
    public function setIf($property)
305
    {
306 792
        $this->ifCondition = $property ?? "";
307 792
    }
308
309
    /**
310
     * Set the unless-condition from the XML tag, if any. The property name
311
     * given as parameter must be present so the unless condition evaluates
312
     * to true
313
     *
314
     * @param string $property The property name that has to be present
315
     */
316 792
    public function setUnless($property)
317
    {
318 792
        $this->unlessCondition = $property ?? "";
319 792
    }
320
321
    /**
322
     * Sets a textual description of this target.
323
     *
324
     * @param string $description The description text
325
     */
326 792
    public function setDescription($description)
327
    {
328 792
        $this->description = $description;
329 792
    }
330
331
    /**
332
     * Returns the description of this target.
333
     *
334
     * @return string The description text of this target
335
     */
336
    public function getDescription()
337
    {
338
        return $this->description;
339
    }
340
341 792
    public function setLogSkipped(bool $log)
342
    {
343 792
        $this->logSkipped = $log;
344 792
    }
345
346
    /**
347
     * @return bool|null
348
     */
349 10
    public function getLogSkipped()
350
    {
351 10
        if ($this->logSkipped === null) {
352
            $this->setLogSkipped(false);
353
        }
354
355 10
        return $this->logSkipped;
356
    }
357
358
    /**
359
     * Returns a string representation of this target. In our case it
360
     * simply returns the target name field
361
     *
362
     * @return string The string representation of this target
363
     */
364 600
    public function __toString()
365
    {
366 600
        return (string) $this->name;
367
    }
368
369
    /**
370
     * The entry point for this class. Does some checking, then processes and
371
     * performs the tasks for this target.
372
     */
373 792
    public function main()
374
    {
375 792
        if ($this->testIfCondition() && $this->testUnlessCondition()) {
376 792
            foreach ($this->children as $o) {
377 653
                if ($o instanceof Task) {
378
                    // child is a task
379 653
                    $o->perform();
380 1
                } elseif ($o instanceof RuntimeConfigurable) {
381
                    // child is a RuntimeConfigurable
382 1
                    $o->maybeConfigure($this->project);
383
                }
384
            }
385 10
        } elseif (!$this->testIfCondition()) {
386 2
            $this->project->log(
387 2
                "Skipped target '" . $this->name . "' because property '" . $this->ifCondition . "' not set.",
388 2
                $this->getLogSkipped() ? Project::MSG_INFO : Project::MSG_VERBOSE
389
            );
390
        } else {
391 8
            $this->project->log(
392 8
                "Skipped target '" . $this->name . "' because property '" . $this->unlessCondition . "' set.",
393 8
                $this->getLogSkipped() ? Project::MSG_INFO : Project::MSG_VERBOSE
394
            );
395
        }
396 792
    }
397
398
    /**
399
     * Performs the tasks by calling the main method of this target that
400
     * actually executes the tasks.
401
     *
402
     * This method is for ZE2 and used for proper exception handling of
403
     * task exceptions.
404
     */
405 600
    public function performTasks()
406
    {
407
        try { // try to execute this target
408 600
            $this->project->fireTargetStarted($this);
409 600
            $this->main();
410 474
            $this->project->fireTargetFinished($this, $null = null);
411 160
        } catch (BuildException $exc) {
412
            // log here and rethrow
413 160
            $this->project->fireTargetFinished($this, $exc);
414 160
            throw $exc;
415
        }
416 474
    }
417
418
    /**
419
     * Tests if the property set in ifConfiditon exists.
420
     *
421
     * @return boolean <code>true</code> if the property specified
422
     *                 in <code>$this->ifCondition</code> exists;
423
     *                 <code>false</code> otherwise
424
     */
425 792
    private function testIfCondition()
426
    {
427 792
        if ($this->ifCondition === "") {
428 792
            return true;
429
        }
430
431 3
        $properties = explode(",", $this->ifCondition);
432
433 3
        $result = true;
434 3
        foreach ($properties as $property) {
435 3
            $test = $this->getProject()->replaceProperties($property);
436 3
            $result = $result && ($this->project->getProperty($test) !== null);
0 ignored issues
show
introduced by
The condition $this->project->getProperty($test) !== null is always true.
Loading history...
437
        }
438
439 3
        return $result;
440
    }
441
442
    /**
443
     * Tests if the property set in unlessCondition exists.
444
     *
445
     * @return boolean <code>true</code> if the property specified
446
     *                 in <code>$this->unlessCondition</code> exists;
447
     *                 <code>false</code> otherwise
448
     */
449 792
    private function testUnlessCondition()
450
    {
451 792
        if ($this->unlessCondition === "") {
452 792
            return true;
453
        }
454
455 8
        $properties = explode(",", $this->unlessCondition);
456
457 8
        $result = true;
458 8
        foreach ($properties as $property) {
459 8
            $test = $this->getProject()->replaceProperties($property);
460 8
            $result = $result && ($this->project->getProperty($test) === null);
0 ignored issues
show
introduced by
The condition $this->project->getProperty($test) === null is always false.
Loading history...
461
        }
462
463 8
        return $result;
464
    }
465
466
    /**
467
     * Replaces all occurrences of the given task in the list
468
     * of children with the replacement data type wrapper.
469
     * @param Task $task
470
     * @param RuntimeConfigurable|Task $o
471
     */
472 11
    public function replaceChild(Task $task, $o)
473
    {
474 11
        $keys = array_keys($this->children, $task);
475 11
        foreach ($keys as $index) {
476 11
            $this->children[$index] = $o;
477
        }
478 11
    }
479
480
    /**
481
     * @param string $depends
482
     * @param string $targetName
483
     * @param string $attributeName
484
     * @return string[]
485
     * @throws \BuildException
486
     */
487 7
    public static function parseDepends($depends, $targetName, $attributeName)
488
    {
489 7
        $list = [];
490 7
        if ($depends !== '') {
491 7
            $list = explode(',', $depends);
492 7
            array_walk($list, 'trim');
493 7
            if (count($list) === 0) {
494
                throw new BuildException("Syntax Error: "
495
                    . $attributeName
496
                    . " attribute of target \""
497
                    . $targetName
498
                    . "\" contains an empty string.");
499
            }
500
        }
501 7
        return $list;
502
    }
503
}
504