Passed
Push — master ( 1117df...fac7df )
by Siad
11:02
created

AbstractFileSet::__construct()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 11
nc 2
nop 1
dl 0
loc 16
rs 9.9
c 1
b 0
f 0
ccs 12
cts 12
cp 1
crap 3
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 FileSet class provides methods and properties for accessing
22
 * and managing filesets. It extends ProjectComponent and thus inherits
23
 * all methods and properties (not explicitly declared). See ProjectComponent
24
 * for further detail.
25
 *
26
 * TODO:
27
 *   - merge this with patternsets: FileSet extends PatternSet !!!
28
 *     requires additional mods to the parsing algo
29
 *         [HL] .... not sure if that really makes so much sense.  I think
30
 *            that perhaps they should use common utility class if there really
31
 *            is that much shared functionality
32
 *
33
 * @author  Andreas Aderhold <[email protected]>
34
 * @author  Hans Lellelid <[email protected]>
35
 * @see     ProjectComponent
36
 * @package phing.types
37
 */
38
abstract class AbstractFileSet extends DataType implements SelectorContainer, IteratorAggregate
39
{
40
    use SelectorAware;
41
42
    // These vars are public for cloning purposes
43
44
    /**
45
     * @var boolean
46
     */
47
    public $useDefaultExcludes = true;
48
49
    /**
50
     * Whether to expand/dereference symbolic links, default is false
51
     *
52
     * @var boolean
53
     */
54
    protected $expandSymbolicLinks = false;
55
56
    /**
57
     * @var PatternSet
58
     */
59
    public $defaultPatterns;
60
61
    public $additionalPatterns = [];
62
    public $dir;
63
    public $isCaseSensitive = true;
64
    private $errorOnMissingDir = false;
65
    private $directoryScanner;
66
67
    /**
68
     * @param null $fileset
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $fileset is correct as it would always require null to be passed?
Loading history...
69
     */
70 128
    public function __construct($fileset = null)
71
    {
72 128
        parent::__construct();
73
74 128
        if ($fileset !== null && ($fileset instanceof FileSet)) {
0 ignored issues
show
introduced by
The condition $fileset !== null is always false.
Loading history...
75 1
            $this->dir = $fileset->dir;
76 1
            $this->additionalPatterns = $fileset->additionalPatterns;
77 1
            $this->useDefaultExcludes = $fileset->useDefaultExcludes;
78 1
            $this->isCaseSensitive = $fileset->isCaseSensitive;
79 1
            $this->selectorsList = $fileset->selectorsList;
80 1
            $this->expandSymbolicLinks = $fileset->expandSymbolicLinks;
81 1
            $this->errorOnMissingDir = $fileset->errorOnMissingDir;
82 1
            $this->setProject($fileset->getProject());
83
        }
84
85 128
        $this->defaultPatterns = new PatternSet();
86 128
    }
87
88
    /**
89
     * Sets whether to expand/dereference symbolic links, default is false
90
     *
91
     * @var boolean
92
     */
93 1
    public function setExpandSymbolicLinks(bool $expandSymbolicLinks)
94
    {
95 1
        if ($this->isReference()) {
96 1
            throw $this->tooManyAttributes();
97
        }
98
        $this->expandSymbolicLinks = $expandSymbolicLinks;
99
    }
100
101
    /**
102
     * Makes this instance in effect a reference to another PatternSet
103
     * instance.
104
     * You must not set another attribute or nest elements inside
105
     * this element if you make it a reference.
106
     *
107
     * @param  Reference $r
108
     * @throws BuildException
109
     */
110 3
    public function setRefid(Reference $r)
111
    {
112 3
        if ((isset($this->dir) && null !== $this->dir) || $this->defaultPatterns->hasPatterns()) {
113 1
            throw $this->tooManyAttributes();
114
        }
115 3
        if (!empty($this->additionalPatterns)) {
116 1
            throw $this->noChildrenAllowed();
117
        }
118 3
        if (!empty($this->selectorsList)) {
119
            throw $this->noChildrenAllowed();
120
        }
121 3
        parent::setRefid($r);
122 3
    }
123
124
    /**
125
     * @param $dir
126
     * @throws IOException
127
     * @throws NullPointerException
128
     */
129 125
    public function setDir($dir)
130
    {
131 125
        if ($this->isReference()) {
132 1
            throw $this->tooManyAttributes();
133
        }
134 124
        if ($dir instanceof PhingFile) {
135 2
            $dir = $dir->getPath();
136
        }
137 124
        $this->dir = new PhingFile((string) $dir);
138 124
        $this->directoryScanner = null;
139 124
    }
140
141
    /**
142
     * @param Project $p
143
     * @return mixed
144
     * @throws BuildException
145
     */
146 90
    public function getDir(Project $p = null)
147
    {
148 90
        if ($p === null) {
149
            $p = $this->getProject();
150
        }
151
152 90
        if ($this->isReference()) {
153 1
            return $this->getRef($p)->getDir($p);
154
        }
155
156 90
        return $this->dir;
157
    }
158
159
    /**
160
     * @return mixed
161
     * @throws BuildException
162
     */
163 2
    public function createPatternSet()
164
    {
165 2
        if ($this->isReference()) {
166 1
            throw $this->noChildrenAllowed();
167
        }
168 2
        $num = array_push($this->additionalPatterns, new PatternSet());
169
170 2
        return $this->additionalPatterns[$num - 1];
171
    }
172
173
    /**
174
     * add a name entry on the include list
175
     */
176 77
    public function createInclude()
177
    {
178 77
        if ($this->isReference()) {
179 1
            throw $this->noChildrenAllowed();
180
        }
181
182 77
        return $this->defaultPatterns->createInclude();
183
    }
184
185
    /**
186
     * add a name entry on the include files list
187
     */
188 1
    public function createIncludesFile()
189
    {
190 1
        if ($this->isReference()) {
191 1
            throw $this->noChildrenAllowed();
192
        }
193
194
        return $this->defaultPatterns->createIncludesFile();
195
    }
196
197
    /**
198
     * add a name entry on the exclude list
199
     */
200 2
    public function createExclude()
201
    {
202 2
        if ($this->isReference()) {
203 1
            throw $this->noChildrenAllowed();
204
        }
205
206 1
        return $this->defaultPatterns->createExclude();
207
    }
208
209
    /**
210
     * add a name entry on the include files list
211
     */
212 1
    public function createExcludesFile()
213
    {
214 1
        if ($this->isReference()) {
215 1
            throw $this->noChildrenAllowed();
216
        }
217
218
        return $this->defaultPatterns->createExcludesFile();
219
    }
220
221 2
    public function setFile(PhingFile $file)
222
    {
223 2
        if ($this->isReference()) {
224 1
            throw $this->tooManyAttributes();
225
        }
226 1
        $this->setDir($file->getParentFile());
227 1
        $this->createInclude()->setName($file->getName());
228 1
    }
229
230
    /**
231
     * Sets the set of include patterns. Patterns may be separated by a comma
232
     * or a space.
233
     *
234
     * @param  $includes
235
     * @throws BuildException
236
     */
237 8
    public function setIncludes($includes)
238
    {
239 8
        if ($this->isReference()) {
240 1
            throw $this->tooManyAttributes();
241
        }
242 8
        $this->defaultPatterns->setIncludes($includes);
243 8
    }
244
245
    /**
246
     * Sets the set of exclude patterns. Patterns may be separated by a comma
247
     * or a space.
248
     *
249
     * @param  $excludes
250
     * @throws BuildException
251
     */
252 2
    public function setExcludes($excludes)
253
    {
254 2
        if ($this->isReference()) {
255 1
            throw $this->tooManyAttributes();
256
        }
257 1
        $this->defaultPatterns->setExcludes($excludes);
258 1
    }
259
260
    /**
261
     * Sets the name of the file containing the includes patterns.
262
     *
263
     * @param  PhingFile $incl The file to fetch the include patterns from.
264
     * @throws BuildException
265
     */
266 1
    public function setIncludesfile(PhingFile $incl)
267
    {
268 1
        if ($this->isReference()) {
269 1
            throw $this->tooManyAttributes();
270
        }
271
        $this->defaultPatterns->setIncludesFile($incl);
272
    }
273
274
    /**
275
     * Sets the name of the file containing the includes patterns.
276
     *
277
     * @param  PhingFile $excl The file to fetch the exclude patterns from.
278
     * @throws BuildException
279
     */
280 1
    public function setExcludesfile($excl)
281
    {
282 1
        if ($this->isReference()) {
283 1
            throw $this->tooManyAttributes();
284
        }
285
        $this->defaultPatterns->setExcludesFile($excl);
286
    }
287
288
    /**
289
     * Sets whether default exclusions should be used or not.
290
     *
291
     * @param  $useDefaultExcludes "true"|"on"|"yes" when default exclusions
0 ignored issues
show
Documentation Bug introduced by
The doc comment "true"|"on"|"yes" at position 0 could not be parsed: Unknown type name '"true"' at position 0 in "true"|"on"|"yes".
Loading history...
292
     *                           should be used, "false"|"off"|"no" when they
293
     *                           shouldn't be used.
294
     * @throws BuildException
295
     * @return void
296
     */
297 3
    public function setDefaultexcludes($useDefaultExcludes)
298
    {
299 3
        if ($this->isReference()) {
300
            throw $this->tooManyAttributes();
301
        }
302 3
        $this->useDefaultExcludes = $useDefaultExcludes;
303 3
    }
304
305
    /**
306
     * Sets case sensitivity of the file system
307
     *
308
     * @param $isCaseSensitive
309
     */
310 1
    public function setCaseSensitive($isCaseSensitive)
311
    {
312 1
        if ($this->isReference()) {
313 1
            throw $this->tooManyAttributes();
314
        }
315
        $this->isCaseSensitive = $isCaseSensitive;
316
    }
317
318
    /**
319
     * returns a reference to the dirscanner object belonging to this fileset
320
     *
321
     * @param  Project $p
322
     * @throws BuildException
323
     * @return \DirectoryScanner
324
     */
325 108
    public function getDirectoryScanner(Project $p = null)
326
    {
327 108
        if ($p === null) {
328
            $p = $this->getProject();
329
        }
330
331 108
        if ($this->isReference()) {
332 1
            $o = $this->getRef($p);
333
334 1
            return $o->getDirectoryScanner($p);
335
        }
336
337 108
        if ($this->dir === null) {
338
            throw new BuildException(sprintf("No directory specified for <%s>.", $this->getDataTypeName()));
339
        }
340 108
        if (!$this->dir->exists() && $this->errorOnMissingDir) {
341
            throw new BuildException("Directory " . $this->dir->getAbsolutePath() . " not found.");
342
        }
343 108
        if (!$this->dir->isLink() || !$this->expandSymbolicLinks) {
344 108
            if (!$this->dir->isDirectory()) {
345 1
                throw new BuildException($this->dir->getAbsolutePath() . " is not a directory.");
346
            }
347
        }
348 107
        $ds = new DirectoryScanner();
349 107
        $ds->setExpandSymbolicLinks($this->expandSymbolicLinks);
350 107
        $ds->setErrorOnMissingDir($this->errorOnMissingDir);
351 107
        $this->setupDirectoryScanner($ds, $p);
352 107
        $ds->scan();
353
354 107
        return $ds;
355
    }
356
357
    /**
358
     * feed dirscanner with infos defined by this fileset
359
     *
360
     * @param  DirectoryScanner $ds
361
     * @param  Project $p
362
     * @throws BuildException
363
     */
364 107
    protected function setupDirectoryScanner(DirectoryScanner $ds, Project $p = null)
365
    {
366 107
        if ($p === null) {
367
            $p = $this->getProject();
368
        }
369
370 107
        if ($this->isReference()) {
371
            $this->getRef($p)->setupDirectoryScanner($ds, $p);
372
            return;
373
        }
374
375 107
        $stk[] = $this;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$stk was never initialized. Although not strictly required by PHP, it is generally a good practice to add $stk = array(); before regardless.
Loading history...
376 107
        $this->dieOnCircularReference($stk, $p);
377 107
        array_pop($stk);
378
379
        // FIXME - pass dir directly when dirscanner supports File
380 107
        $ds->setBasedir($this->dir->getPath());
381
382 107
        foreach ($this->additionalPatterns as $addPattern) {
383 1
            $this->defaultPatterns->append($addPattern, $p);
384
        }
385
386 107
        $ds->setIncludes($this->defaultPatterns->getIncludePatterns($p));
387 107
        $ds->setExcludes($this->defaultPatterns->getExcludePatterns($p));
388
389 107
        $p->log(
390 107
            $this->getDataTypeName() . ": Setup file scanner in dir " . (string) $this->dir . " with " . (string) $this->defaultPatterns,
391 107
            Project::MSG_DEBUG
392
        );
393
394 107
        if ($ds instanceof SelectorScanner) {
0 ignored issues
show
introduced by
$ds is always a sub-type of SelectorScanner.
Loading history...
395 107
            $selectors = $this->getSelectors($p);
396 107
            foreach ($selectors as $selector) {
397 5
                $p->log((string) $selector . PHP_EOL, Project::MSG_DEBUG);
398
            }
399 107
            $ds->setSelectors($selectors);
400
        }
401
402 107
        if ($this->useDefaultExcludes) {
403 105
            $ds->addDefaultExcludes();
404
        }
405 107
        $ds->setCaseSensitive($this->isCaseSensitive);
406 107
    }
407
408 107
    public function dieOnCircularReference(&$stk, Project $p = null)
409
    {
410 107
        if ($this->checked) {
411 104
            return;
412
        }
413 6
        if ($this->isReference()) {
414 2
            parent::dieOnCircularReference($stk, $p);
415
        } else {
416 5
            foreach ($this->selectorsList as $fileSelector) {
417 5
                if ($fileSelector instanceof DataType) {
418 5
                    static::pushAndInvokeCircularReferenceCheck($fileSelector, $stk, $p);
0 ignored issues
show
Bug introduced by
It seems like $p can also be of type null; however, parameter $p of DataType::pushAndInvokeCircularReferenceCheck() does only seem to accept Project, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

418
                    static::pushAndInvokeCircularReferenceCheck($fileSelector, $stk, /** @scrutinizer ignore-type */ $p);
Loading history...
419
                }
420
            }
421 5
            foreach ($this->additionalPatterns as $ps) {
422
                static::pushAndInvokeCircularReferenceCheck($ps, $stk, $p);
423
            }
424 5
            $this->setChecked(true);
425
        }
426 6
    }
427
428
    /**
429
     * Performs the check for circular references and returns the
430
     * referenced FileSet.
431
     *
432
     * @param Project $p
433
     *
434
     * @throws BuildException
435
     *
436
     * @return FileSet
437
     */
438 2
    public function getRef(Project $p)
0 ignored issues
show
Unused Code introduced by
The parameter $p is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

438
    public function getRef(/** @scrutinizer ignore-unused */ Project $p)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
439
    {
440 2
        return $this->getCheckedRef(__CLASS__, $this->getDataTypeName());
441
    }
442
443
    // SelectorContainer methods
444
445
    /**
446
     * Indicates whether there are any selectors here.
447
     *
448
     * @return boolean Whether any selectors are in this container
449
     */
450
    public function hasSelectors()
451
    {
452
        if ($this->isReference() && $this->getProject() !== null) {
453
            return $this->getRef($this->getProject())->hasSelectors();
454
        }
455
        $stk[] = $this;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$stk was never initialized. Although not strictly required by PHP, it is generally a good practice to add $stk = array(); before regardless.
Loading history...
456
        $this->dieOnCircularReference($stk, $this->getProject());
457
458
        return !empty($this->selectorsList);
459
    }
460
461
    /**
462
     * Indicates whether there are any patterns here.
463
     *
464
     * @return boolean Whether any patterns are in this container.
465
     */
466
    public function hasPatterns()
467
    {
468
        if ($this->isReference() && $this->getProject() !== null) {
469
            return $this->getRef($this->getProject())->hasPatterns();
470
        }
471
        $stk[] = $this;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$stk was never initialized. Although not strictly required by PHP, it is generally a good practice to add $stk = array(); before regardless.
Loading history...
472
        $this->dieOnCircularReference($stk, $this->getProject());
473
474
        if ($this->defaultPatterns->hasPatterns()) {
475
            return true;
476
        }
477
478
        for ($i = 0, $size = count($this->additionalPatterns); $i < $size; $i++) {
479
            $ps = $this->additionalPatterns[$i];
480
            if ($ps->hasPatterns()) {
481
                return true;
482
            }
483
        }
484
485
        return false;
486
    }
487
488
    /**
489
     * Gives the count of the number of selectors in this container
490
     *
491
     * @throws Exception
492
     * @return int The number of selectors in this container
493
     */
494
    public function count()
495
    {
496
        if ($this->isReference() && $this->getProject() !== null) {
497
            try {
498
                return $this->getRef($this->getProject())->count();
499
            } catch (Exception $e) {
500
                throw $e;
501
            }
502
        }
503
504
        return count($this->selectorsList);
505
    }
506
507
    /**
508
     * Returns the set of selectors as an array.
509
     *
510
     * @param  Project $p
511
     * @throws BuildException
512
     * @return array of selectors in this container
513
     */
514 107
    public function getSelectors(Project $p)
515
    {
516 107
        if ($this->isReference()) {
517
            return $this->getRef($p)->getSelectors($p);
518
        }
519
520
// *copy* selectors
521 107
        $result = [];
522 107
        for ($i = 0, $size = count($this->selectorsList); $i < $size; $i++) {
523 5
            $result[] = clone $this->selectorsList[$i];
524
        }
525
526 107
        return $result;
527
    }
528
529
    /**
530
     * Returns an array for accessing the set of selectors.
531
     *
532
     * @return array The array of selectors
533
     */
534
    public function selectorElements()
535
    {
536
        if ($this->isReference() && $this->getProject() !== null) {
537
            return $this->getRef($this->getProject())->selectorElements();
538
        }
539
540
        return $this->selectorsList;
541
    }
542
543
    /**
544
     * Add a new selector into this container.
545
     *
546
     * @param FileSelector $selector new selector to add
547
     *
548
     * @throws BuildException
549
     *
550
     * @return void
551
     */
552 8
    public function appendSelector(FileSelector $selector)
553
    {
554 8
        if ($this->isReference()) {
555
            throw $this->noChildrenAllowed();
556
        }
557 8
        $this->selectorsList[] = $selector;
558 8
        $this->directoryScanner = null;
559 8
        $this->setChecked(false);
560 8
    }
561
562
    /**
563
     * @param array ...$options
564
     * @return ArrayIterator
565
     */
566 22
    public function getIterator(...$options): \ArrayIterator
567
    {
568 22
        if ($this->isReference()) {
569 1
            return $this->getRef($this->getProject())->getIterator($options);
570
        }
571 22
        return new ArrayIterator($this->getFiles($options));
572
    }
573
574
    abstract protected function getFiles(...$options);
575
576 1
    public function __toString()
577
    {
578
        try {
579 1
            if ($this->isReference()) {
580
                return (string) $this->getRef($this->getProject());
581
            }
582 1
            $stk[] = $this;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$stk was never initialized. Although not strictly required by PHP, it is generally a good practice to add $stk = array(); before regardless.
Loading history...
583 1
            $this->dieOnCircularReference($stk, $this->getProject());
584 1
            $ds = $this->getDirectoryScanner($this->getProject());
585 1
            $files = $ds->getIncludedFiles();
586 1
            $result = implode(';', $files);
587
        } catch (BuildException $e) {
588
            $result = '';
589
        }
590
591 1
        return $result;
592
    }
593
}
594