Passed
Push — master ( b9bc63...f1e2bc )
by Michiel
06:23
created

ForeachTask::process()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2.004

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 17
ccs 9
cts 10
cp 0.9
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 4
crap 2.004
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
namespace Phing\Task\System;
21
22
use Phing\Exception\BuildException;
23
use Phing\Io\DirectoryScanner;
24
use Phing\Io\File;
25
use Phing\Io\FileSystem;
26
use Phing\Io\IOException;
27
use Phing\Project;
28
use Phing\Task;
29
use Phing\Type\Element\ResourceAware;
30
use Phing\Type\Mapper;
31
use Phing\Type\Path;
32
33
/**
34
 * <foreach> task
35
 *
36
 * Task definition for the foreach task.  This task takes a list with
37
 * delimited values, and executes a target with set param.
38
 *
39
 * Usage:
40
 * <foreach list="values" target="targ" param="name" delimiter="|" />
41
 *
42
 * Attributes:
43
 * list      --> The list of values to process, with the delimiter character,
44
 *               indicated by the "delimiter" attribute, separating each value.
45
 * target    --> The target to call for each token, passing the token as the
46
 *               parameter with the name indicated by the "param" attribute.
47
 * param     --> The name of the parameter to pass the tokens in as to the
48
 *               target.
49
 * delimiter --> The delimiter string that separates the values in the "list"
50
 *               parameter.  The default is ",".
51
 *
52
 * @author  Jason Hines <[email protected]>
53
 * @author  Hans Lellelid <[email protected]>
54
 * @package phing.tasks.system
55
 */
56
class ForeachTask extends Task
57
{
58
    use ResourceAware;
59
60
    /**
61
     * Delimter-separated list of values to process.
62
     */
63
    private $list;
64
65
    /**
66
     * Name of parameter to pass to callee
67
     */
68
    private $param;
69
70
    /**
71
     * @var PropertyTask[] $params
72
     */
73
    private $params = [];
74
75
    /**
76
     * Name of absolute path parameter to pass to callee
77
     */
78
    private $absparam;
79
80
    /**
81
     * Delimiter that separates items in $list
82
     */
83
    private $delimiter = ',';
84
85
    /**
86
     * PhingCallTask that will be invoked w/ calleeTarget.
87
     *
88
     * @var PhingCallTask
89
     */
90
    private $callee;
91
92
    /**
93
     * Instance of mapper
94
     */
95
    private $mapperElement;
96
97
    /**
98
     * Target to execute.
99
     *
100
     * @var string
101
     */
102
    private $calleeTarget;
103
104
    /**
105
     * Total number of files processed
106
     *
107
     * @var integer
108
     */
109
    private $total_files = 0;
110
111
    /**
112
     * Total number of directories processed
113
     *
114
     * @var integer
115
     */
116
    private $total_dirs = 0;
117
118
    /**
119
     * @var bool $trim
120
     */
121
    private $trim = false;
122
123
    /**
124
     * @var  $inheritAll
0 ignored issues
show
Documentation Bug introduced by
The doc comment $inheritAll at position 0 could not be parsed: Unknown type name '$inheritAll' at position 0 in $inheritAll.
Loading history...
125
     */
126
    private $inheritAll = false;
127
128
    /**
129
     * @var bool $inheritRefs
130
     */
131
    private $inheritRefs = false;
132
133
    /**
134
     * @var Path $currPath
135
     */
136
    private $currPath;
137
138
    /**
139
     * @var PhingReference[] $references
140
     */
141
    private $references = [];
142
143
    /**
144
     * @var string $index
145
     */
146
    private $index = 'index';
147
148
    /**
149
     * This method does the work.
150
     *
151
     * @throws BuildException
152
     * @return void
153
     */
154 11
    public function main()
155
    {
156
        if (
157 11
            $this->list === null
158 11
            && $this->currPath === null
159 11
            && count($this->dirsets) === 0
160 11
            && count($this->filesets) === 0
161 11
            && count($this->filelists) === 0
162
        ) {
163 1
            throw new BuildException(
164 1
                'Need either list, path, nested dirset, nested fileset or nested filelist to iterate through'
165
            );
166
        }
167 10
        if ($this->param === null) {
168 2
            throw new BuildException("You must supply a property name to set on each iteration in param");
169
        }
170 8
        if ($this->calleeTarget === null) {
171
            throw new BuildException("You must supply a target to perform");
172
        }
173
174 8
        $callee = $this->createCallTarget();
175 8
        $mapper = null;
176
177 8
        if ($this->mapperElement !== null) {
178
            $mapper = $this->mapperElement->getImplementation();
179
        }
180
181 8
        if ($this->list !== null) {
182 3
            $arr = explode($this->delimiter, $this->list);
183 3
            $total_entries = 0;
184
185 3
            foreach ($arr as $index => $value) {
186 3
                if ($this->trim) {
187
                    $value = trim($value);
188
                }
189 3
                $premapped = '';
190 3
                if ($mapper !== null) {
191
                    $premapped = $value;
192
                    $value = $mapper->main($value);
193
                    if ($value === null) {
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
                );
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 ($this->currPath !== null) {
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(), array());
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 ($this->list === null) {
247 5
            $this->log(
248 5
                "Processed {$this->total_dirs} directories and {$this->total_files} files",
249 5
                Project::MSG_VERBOSE
250
            );
251
        } else {
252 3
            $this->log(
253 3
                "Processed $total_entries entr" . ($total_entries > 1 ? 'ies' : 'y') . " in list",
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $total_entries does not seem to be defined for all execution paths leading up to this point.
Loading history...
254 3
                Project::MSG_VERBOSE
255
            );
256
        }
257 8
    }
258
259
    /**
260
     * Processes a list of files & directories
261
     *
262
     * @param PhingCallTask $callee
263
     * @param File $fromDir
264
     * @param array $srcFiles
265
     * @param array $srcDirs
266
     */
267 5
    protected function process(Task $callee, File $fromDir, $srcFiles, $srcDirs)
268
    {
269 5
        $mapper = null;
270
271 5
        if ($this->mapperElement !== null) {
272
            $mapper = $this->mapperElement->getImplementation();
273
        }
274
275 5
        $filecount = count($srcFiles);
276 5
        $this->total_files += $filecount;
277
278 5
        $this->processResources($filecount, $srcFiles, $callee, $fromDir, $mapper);
279
280 5
        $dircount = count($srcDirs);
281 5
        $this->total_dirs += $dircount;
282
283 5
        $this->processResources($dircount, $srcDirs, $callee, $fromDir, $mapper);
284 5
    }
285
286
    /**
287
     * @param int $rescount
288
     * @param array $srcRes
289
     * @param $callee
290
     * @param $fromDir
291
     * @param $mapper
292
     * @throws IOException
293
     */
294 5
    private function processResources(int $rescount, array $srcRes, $callee, $fromDir, $mapper)
295
    {
296 5
        for ($j = 0; $j < $rescount; $j++) {
297 4
            $value = $srcRes[$j];
298 4
            $premapped = "";
299
300 4
            if ($this->absparam) {
301 3
                $prop = $callee->createProperty();
302 3
                $prop->setName($this->absparam);
303 3
                $prop->setValue($fromDir . FileSystem::getFileSystem()->getSeparator() . $value);
304
            }
305
306 4
            if ($mapper !== null) {
307
                $premapped = $value;
308
                $value = $mapper->main($value);
309
                if ($value === null) {
310
                    continue;
311
                }
312
                $value = array_shift($value);
313
            }
314
315 4
            if ($this->param) {
316 4
                $this->log(
317 4
                    "Setting param '$this->param' to value '$value'" . ($premapped ? " (mapped from '$premapped')" : ''),
318 4
                    Project::MSG_VERBOSE
319
                );
320 4
                $prop = $callee->createProperty();
321 4
                $prop->setName($this->param);
322 4
                $prop->setValue($value);
323
            }
324
325 4
            $callee->main();
326
        }
327 5
    }
328
329
    public function setTrim($trim)
330
    {
331
        $this->trim = $trim;
332
    }
333
334
    /**
335
     * @param $list
336
     */
337 5
    public function setList($list)
338
    {
339 5
        $this->list = (string) $list;
340 5
    }
341
342
    /**
343
     * @param $target
344
     */
345 9
    public function setTarget($target)
346
    {
347 9
        $this->calleeTarget = (string) $target;
348 9
    }
349
350
    /**
351
     * @param PropertyTask $param
352
     */
353
    public function addParam(PropertyTask $param)
354
    {
355
        $this->params[] = $param;
356
    }
357
358
    /**
359
     * Corresponds to <code>&lt;phingcall&gt;</code>'s nested
360
     * <code>&lt;reference&gt;</code> element.
361
     */
362 1
    public function addReference(PhingReference $r)
363
    {
364 1
        $this->references[] = $r;
365 1
    }
366
367
    /**
368
     * @param $absparam
369
     */
370 4
    public function setAbsparam($absparam)
371
    {
372 4
        $this->absparam = (string) $absparam;
373 4
    }
374
375
    /**
376
     * @param $delimiter
377
     */
378
    public function setDelimiter($delimiter)
379
    {
380
        $this->delimiter = (string) $delimiter;
381
    }
382
383
    public function setIndex($index)
384
    {
385
        $this->index = $index;
386
    }
387
388 1
    public function createPath()
389
    {
390 1
        if ($this->currPath === null) {
391 1
            $this->currPath = new Path($this->getProject());
392
        }
393
394 1
        return $this->currPath;
395
    }
396
397
    /**
398
     * Nested creator, creates one Mapper for this task
399
     *
400
     * @return object         The created Mapper type object
401
     * @throws BuildException
402
     */
403
    public function createMapper()
404
    {
405
        if ($this->mapperElement !== null) {
406
            throw new BuildException("Cannot define more than one mapper", $this->getLocation());
407
        }
408
        $this->mapperElement = new Mapper($this->project);
409
410
        return $this->mapperElement;
411
    }
412
413
    /**
414
     * @return PropertyTask
415
     */
416
    public function createProperty()
417
    {
418
        return $this->callee->createProperty();
419
    }
420
421
    /**
422
     * @return PropertyTask
423
     */
424
    public function createParam()
425
    {
426
        return $this->callee->createProperty();
427
    }
428
429
    /**
430
     * @param string $param
431
     */
432 8
    public function setParam($param)
433
    {
434 8
        $this->param = $param;
435 8
    }
436
437
    /**
438
     * Corresponds to <code>&lt;antcall&gt;</code>'s <code>inheritall</code>
439
     * attribute.
440
     */
441
    public function setInheritall($b)
442
    {
443
        $this->inheritAll = $b;
444
    }
445
446
    /**
447
     * Corresponds to <code>&lt;antcall&gt;</code>'s <code>inheritrefs</code>
448
     * attribute.
449
     */
450
    public function setInheritrefs($b)
451
    {
452
        $this->inheritRefs = $b;
453
    }
454
455 8
    private function createCallTarget()
456
    {
457
        /**
458
         * @var PhingCallTask $ct
459
         */
460 8
        $ct = $this->getProject()->createTask("phingcall");
461 8
        $ct->setOwningTarget($this->getOwningTarget());
462 8
        $ct->setTaskName($this->getTaskName());
463 8
        $ct->setLocation($this->getLocation());
464 8
        $ct->init();
465 8
        $ct->setTarget($this->calleeTarget);
466 8
        $ct->setInheritAll($this->inheritAll);
467 8
        $ct->setInheritRefs($this->inheritRefs);
468 8
        foreach ($this->params as $param) {
469
            $toSet = $ct->createParam();
470
            $toSet->setName($param->getName());
471
            if ($param->getValue() !== null) {
472
                $toSet->setValue($param->getValue());
473
            }
474
475
            if ($param->getFile() != null) {
476
                $toSet->setFile($param->getFile());
477
            }
478
            if ($param->getPrefix() != null) {
479
                $toSet->setPrefix($param->getPrefix());
480
            }
481
            if ($param->getRefid() != null) {
482
                $toSet->setRefid($param->getRefid());
483
            }
484
            if ($param->getEnvironment() != null) {
485
                $toSet->setEnvironment($param->getEnvironment());
486
            }
487
        }
488
489 8
        foreach ($this->references as $ref) {
490 1
            $ct->addReference($ref);
491
        }
492
493 8
        return $ct;
494
    }
495
}
496