ForeachTask::main()   F
last analyzed

Complexity

Conditions 22
Paths 131

Size

Total Lines 101
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 59
CRAP Score 23.4724

Importance

Changes 0
Metric Value
eloc 67
c 0
b 0
f 0
dl 0
loc 101
ccs 59
cts 69
cp 0.8551
rs 3.9083
cc 22
nc 131
nop 0
crap 23.4724

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
/**
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * This software consists of voluntary contributions made by many individuals
17
 * and is licensed under the LGPL. For more information please see
18
 * <http://phing.info>.
19
 */
20
21
namespace Phing\Task\System;
22
23
use Phing\Exception\BuildException;
24
use Phing\Io\DirectoryScanner;
25
use Phing\Io\File;
26
use Phing\Io\FileSystem;
27
use Phing\Io\IOException;
28
use Phing\Mapper\FileNameMapper;
29
use Phing\Project;
30
use Phing\Task;
31
use Phing\Type\Element\ResourceAware;
32
use Phing\Type\Mapper;
33
use Phing\Type\Path;
34
35
/**
36
 * <foreach> task.
37
 *
38
 * Task definition for the foreach task.  This task takes a list with
39
 * delimited values, and executes a target with set param.
40
 *
41
 * Usage:
42
 * <foreach list="values" target="targ" param="name" delimiter="|" />
43
 *
44
 * Attributes:
45
 * list      --> The list of values to process, with the delimiter character,
46
 *               indicated by the "delimiter" attribute, separating each value.
47
 * target    --> The target to call for each token, passing the token as the
48
 *               parameter with the name indicated by the "param" attribute.
49
 * param     --> The name of the parameter to pass the tokens in as to the
50
 *               target.
51
 * delimiter --> The delimiter string that separates the values in the "list"
52
 *               parameter.  The default is ",".
53
 *
54
 * @author  Jason Hines <[email protected]>
55
 * @author  Hans Lellelid <[email protected]>
56
 */
57
class ForeachTask extends Task
58
{
59
    use ResourceAware;
60
61
    /**
62
     * Delimter-separated list of values to process.
63
     */
64
    private $list;
65
66
    /**
67
     * Name of parameter to pass to callee.
68
     */
69
    private $param;
70
71
    /**
72
     * @var PropertyTask[]
73
     */
74
    private $params = [];
75
76
    /**
77
     * Name of absolute path parameter to pass to callee.
78
     */
79
    private $absparam;
80
81
    /**
82
     * Delimiter that separates items in $list.
83
     */
84
    private $delimiter = ',';
85
86
    /**
87
     * PhingCallTask that will be invoked w/ calleeTarget.
88
     *
89
     * @var PhingCallTask
90
     */
91
    private $callee;
92
93
    /**
94
     * @var Mapper
95
     */
96
    private $mapperElement;
97
98
    /**
99
     * Target to execute.
100
     *
101
     * @var string
102
     */
103
    private $calleeTarget;
104
105
    /**
106
     * Total number of files processed.
107
     *
108
     * @var int
109
     */
110
    private $total_files = 0;
111
112
    /**
113
     * Total number of directories processed.
114
     *
115
     * @var int
116
     */
117
    private $total_dirs = 0;
118
119
    /**
120
     * @var bool
121
     */
122
    private $trim = false;
123
124
    /**
125
     * @var bool
126
     */
127
    private $inheritAll = false;
128
129
    /**
130
     * @var bool
131
     */
132
    private $inheritRefs = false;
133
134
    /**
135
     * @var Path
136
     */
137
    private $currPath;
138
139
    /**
140
     * @var PhingReference[]
141
     */
142
    private $references = [];
143
144
    /**
145
     * @var string
146
     */
147
    private $index = 'index';
148
149
    /**
150
     * This method does the work.
151
     *
152
     * @throws BuildException
153
     */
154 11
    public function main()
155
    {
156
        if (
157 11
            null === $this->list
158 11
            && null === $this->currPath
159 11
            && 0 === count($this->dirsets)
160 11
            && 0 === count($this->filesets)
161 11
            && 0 === count($this->filelists)
162
        ) {
163 1
            throw new BuildException(
164 1
                'Need either list, path, nested dirset, nested fileset or nested filelist to iterate through'
165 1
            );
166
        }
167 10
        if (null === $this->param) {
168 2
            throw new BuildException('You must supply a property name to set on each iteration in param');
169
        }
170 8
        if (null === $this->calleeTarget) {
171
            throw new BuildException('You must supply a target to perform');
172
        }
173
174 8
        $callee = $this->createCallTarget();
175 8
        $mapper = null;
176 8
        $total_entries = 0;
177
178 8
        if (null !== $this->mapperElement) {
179
            $mapper = $this->mapperElement->getImplementation();
180
        }
181
182 8
        if (null !== $this->list) {
183 3
            $arr = explode($this->delimiter, $this->list);
184
185 3
            foreach ($arr as $index => $value) {
186 3
                if ($this->trim) {
187
                    $value = trim($value);
188
                }
189 3
                $premapped = '';
190 3
                if (null !== $mapper) {
191
                    $premapped = $value;
192
                    $value = $mapper->main($value);
193
                    if (null === $value) {
194
                        continue;
195
                    }
196
                    $value = array_shift($value);
197
                }
198 3
                $this->log(
199 3
                    "Setting param '{$this->param}' to value '{$value}'" . ($premapped ? " (mapped from '{$premapped}')" : ''),
200 3
                    Project::MSG_VERBOSE
201 3
                );
202 3
                $prop = $callee->createProperty();
203 3
                $prop->setName($this->param);
204 3
                $prop->setValue($value);
205 3
                $prop = $callee->createProperty();
206 3
                $prop->setName($this->index);
207 3
                $prop->setValue($index);
208 3
                $callee->main();
209 3
                ++$total_entries;
210
            }
211
        }
212
213 8
        if (null !== $this->currPath) {
214 1
            $pathElements = $this->currPath->listPaths();
215 1
            foreach ($pathElements as $pathElement) {
216 1
                $ds = new DirectoryScanner();
217 1
                $ds->setBasedir($pathElement);
218 1
                $ds->scan();
219 1
                $this->process($callee, new File($pathElement), $ds->getIncludedFiles(), []);
220
            }
221
        }
222
223
        // filelists
224 8
        foreach ($this->filelists as $fl) {
225
            $srcFiles = $fl->getFiles($this->project);
226
227
            $this->process($callee, $fl->getDir($this->project), $srcFiles, []);
228
        }
229
230
        // filesets
231 8
        foreach ($this->filesets as $fs) {
232 3
            $ds = $fs->getDirectoryScanner($this->project);
233 3
            $srcFiles = $ds->getIncludedFiles();
234 3
            $srcDirs = $ds->getIncludedDirectories();
235
236 3
            $this->process($callee, $fs->getDir($this->project), $srcFiles, $srcDirs);
237
        }
238
239 8
        foreach ($this->dirsets as $dirset) {
240 1
            $ds = $dirset->getDirectoryScanner($this->project);
241 1
            $srcDirs = $ds->getIncludedDirectories();
242
243 1
            $this->process($callee, $dirset->getDir($this->project), [], $srcDirs);
244
        }
245
246 8
        if (null === $this->list) {
247 5
            $this->log(
248 5
                "Processed {$this->total_dirs} directories and {$this->total_files} files",
249 5
                Project::MSG_VERBOSE
250 5
            );
251
        } else {
252 3
            $this->log(
253 3
                "Processed {$total_entries} entr" . ($total_entries > 1 ? 'ies' : 'y') . ' in list',
254 3
                Project::MSG_VERBOSE
255 3
            );
256
        }
257
    }
258
259
    public function setTrim(string $trim)
260
    {
261
        $this->trim = $trim;
0 ignored issues
show
Documentation Bug introduced by
The property $trim was declared of type boolean, but $trim is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
262
    }
263
264 5
    public function setList(string $list)
265
    {
266 5
        $this->list = $list;
267
    }
268
269 9
    public function setTarget(string $target)
270
    {
271 9
        $this->calleeTarget = $target;
272
    }
273
274
    public function addParam(PropertyTask $param)
275
    {
276
        $this->params[] = $param;
277
    }
278
279
    /**
280
     * Corresponds to <code>&lt;phingcall&gt;</code>'s nested
281
     * <code>&lt;reference&gt;</code> element.
282
     */
283 1
    public function addReference(PhingReference $r)
284
    {
285 1
        $this->references[] = $r;
286
    }
287
288 4
    public function setAbsparam(string $absparam)
289
    {
290 4
        $this->absparam = $absparam;
291
    }
292
293
    public function setDelimiter(string $delimiter)
294
    {
295
        $this->delimiter = $delimiter;
296
    }
297
298
    public function setIndex($index)
299
    {
300
        $this->index = $index;
301
    }
302
303 1
    public function createPath()
304
    {
305 1
        if (null === $this->currPath) {
306 1
            $this->currPath = new Path($this->getProject());
307
        }
308
309 1
        return $this->currPath;
310
    }
311
312
    /**
313
     * Nested creator, creates one Mapper for this task.
314
     *
315
     * @throws BuildException
316
     *
317
     * @return object The created Mapper type object
318
     */
319
    public function createMapper()
320
    {
321
        if (null !== $this->mapperElement) {
322
            throw new BuildException('Cannot define more than one mapper', $this->getLocation());
323
        }
324
        $this->mapperElement = new Mapper($this->project);
325
326
        return $this->mapperElement;
327
    }
328
329
    /**
330
     * @return PropertyTask
331
     */
332
    public function createProperty()
333
    {
334
        return $this->callee->createProperty();
335
    }
336
337
    /**
338
     * @return PropertyTask
339
     */
340
    public function createParam()
341
    {
342
        return $this->callee->createProperty();
343
    }
344
345
    /**
346
     * @param string $param
347
     */
348 8
    public function setParam($param)
349
    {
350 8
        $this->param = $param;
351
    }
352
353
    /**
354
     * Corresponds to <code>&lt;antcall&gt;</code>'s <code>inheritall</code>
355
     * attribute.
356
     *
357
     * @param mixed $b
358
     */
359
    public function setInheritall($b)
360
    {
361
        $this->inheritAll = $b;
362
    }
363
364
    /**
365
     * Corresponds to <code>&lt;antcall&gt;</code>'s <code>inheritrefs</code>
366
     * attribute.
367
     *
368
     * @param mixed $b
369
     */
370
    public function setInheritrefs($b)
371
    {
372
        $this->inheritRefs = $b;
373
    }
374
375
    /**
376
     * Processes a list of files & directories.
377
     *
378
     * @param array $srcFiles
379
     * @param array $srcDirs
380
     */
381 5
    protected function process(PhingCallTask $callee, File $fromDir, $srcFiles, $srcDirs)
382
    {
383 5
        $mapper = null;
384
385 5
        if (null !== $this->mapperElement) {
386
            $mapper = $this->mapperElement->getImplementation();
387
        }
388
389 5
        $filecount = count($srcFiles);
390 5
        $this->total_files += $filecount;
391
392 5
        $this->processResources($filecount, $srcFiles, $callee, $fromDir, $mapper);
393
394 5
        $dircount = count($srcDirs);
395 5
        $this->total_dirs += $dircount;
396
397 5
        $this->processResources($dircount, $srcDirs, $callee, $fromDir, $mapper);
398
    }
399
400
    /**
401
     * @param string         $fromDir
402
     * @param FileNameMapper $mapper
403
     *
404
     * @throws IOException
405
     */
406 5
    private function processResources(int $rescount, array $srcRes, PhingCallTask $callee, $fromDir, $mapper)
407
    {
408 5
        for ($j = 0; $j < $rescount; ++$j) {
409 4
            $value = $srcRes[$j];
410 4
            $premapped = '';
411
412 4
            if ($this->absparam) {
413 3
                $prop = $callee->createProperty();
414 3
                $prop->setName($this->absparam);
415 3
                $prop->setValue($fromDir . FileSystem::getFileSystem()->getSeparator() . $value);
416
            }
417
418 4
            if (null !== $mapper) {
419
                $premapped = $value;
420
                $value = $mapper->main($value);
421
                if (null === $value) {
422
                    continue;
423
                }
424
                $value = array_shift($value);
425
            }
426
427 4
            if ($this->param) {
428 4
                $this->log(
429 4
                    "Setting param '{$this->param}' to value '{$value}'" . ($premapped ? " (mapped from '{$premapped}')" : ''),
430 4
                    Project::MSG_VERBOSE
431 4
                );
432 4
                $prop = $callee->createProperty();
433 4
                $prop->setName($this->param);
434 4
                $prop->setValue($value);
435
            }
436
437 4
            $callee->main();
438
        }
439
    }
440
441 8
    private function createCallTarget()
442
    {
443
        /**
444
         * @var PhingCallTask $ct
445
         */
446 8
        $ct = $this->getProject()->createTask('phingcall');
447 8
        $ct->setOwningTarget($this->getOwningTarget());
448 8
        $ct->setTaskName($this->getTaskName());
449 8
        $ct->setLocation($this->getLocation());
450 8
        $ct->init();
451 8
        $ct->setTarget($this->calleeTarget);
452 8
        $ct->setInheritAll($this->inheritAll);
453 8
        $ct->setInheritRefs($this->inheritRefs);
454 8
        foreach ($this->params as $param) {
455
            $toSet = $ct->createParam();
456
            $toSet->setName($param->getName());
457
            if (null !== $param->getValue()) {
458
                $toSet->setValue($param->getValue());
459
            }
460
461
            if (null != $param->getFile()) {
462
                $toSet->setFile($param->getFile());
463
            }
464
            if (null != $param->getPrefix()) {
465
                $toSet->setPrefix($param->getPrefix());
466
            }
467
            if (null != $param->getRefid()) {
468
                $toSet->setRefid($param->getRefid());
469
            }
470
            if (null != $param->getEnvironment()) {
471
                $toSet->setEnvironment($param->getEnvironment());
472
            }
473
        }
474
475 8
        foreach ($this->references as $ref) {
476 1
            $ct->addReference($ref);
477
        }
478
479 8
        return $ct;
480
    }
481
}
482