Passed
Push — master ( fd43ba...a7f15e )
by Siad
11:00
created

PhingTask::createProperty()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 8
ccs 6
cts 6
cp 1
crap 1
rs 10
c 1
b 0
f 0
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
 * Task that invokes phing on another build file.
22
 *
23
 * Use this task, for example, if you have nested buildfiles in your project. Unlike
24
 * AntTask, PhingTask can even support filesets:
25
 *
26
 * <pre>
27
 *   <phing>
28
 *    <fileset dir="${srcdir}">
29
 *      <include name="** /build.xml" /> <!-- space added after ** is there because of PHP comment syntax -->
30
 *      <exclude name="build.xml" />
31
 *    </fileset>
32
 *   </phing>
33
 * </pre>
34
 *
35
 * @author  Hans Lellelid <[email protected]>
36
 * @package phing.tasks.system
37
 */
38
class PhingTask extends Task
39
{
40
    use FileSetAware;
41
42
    /**
43
     * the basedir where is executed the build file
44
     * @var PhingFile
45
     */
46
    private $dir;
47
48
    /**
49
     * build.xml (can be absolute) in this case dir will be ignored
50
     */
51
    private $phingFile;
52
53
    /**
54
     * the target to call if any
55
     * @var Target
56
     */
57
    protected $newTarget;
58
59
    /**
60
     * should we inherit properties from the parent ?
61
     */
62
    private $inheritAll = true;
63
64
    /**
65
     * should we inherit references from the parent ?
66
     */
67
    private $inheritRefs = false;
68
69
    /**
70
     * the properties to pass to the new project
71
     */
72
    private $properties = [];
73
74
    /**
75
     * the references to pass to the new project
76
     */
77
    private $references = [];
78
79
    /**
80
     * The temporary project created to run the build file
81
     *
82
     * @var Project
83
     */
84
    private $newProject;
85
86
    /**
87
     * Fail the build process when the called build fails?
88
     */
89
    private $haltOnFailure = false;
90
91
    /**
92
     * Whether the basedir of the new project should be the same one
93
     * as it would be when running the build file directly -
94
     * independent of dir and/or inheritAll settings.
95
     */
96
    private $useNativeBasedir = false;
97
98
    /**
99
     * @var OutputStream
100
     */
101
    private $out;
102
103
    /** @var string */
104
    private $output;
105
106 27
    public function __construct(Task $owner = null)
107
    {
108 27
        if ($owner !== null) {
109
            $this->bindToOwner($owner);
110
        }
111 27
        parent::__construct();
112 27
    }
113
114
    /**
115
     *  If true, abort the build process if there is a problem with or in the target build file.
116
     *  Defaults to false.
117
     *
118
     * @param bool $hof new value
119
     */
120 14
    public function setHaltOnFailure($hof)
121
    {
122 14
        $this->haltOnFailure = (bool) $hof;
123 14
    }
124
125
    /**
126
     * Whether the basedir of the new project should be the same one
127
     * as it would be when running the build file directly -
128
     * independent of dir and/or inheritAll settings.
129
     *
130
     * @param bool $b
131
     */
132
    public function setUseNativeBasedir(bool $b)
133
    {
134
        $this->useNativeBasedir = $b;
135
    }
136
137
    /**
138
     * Creates a Project instance for the project to call.
139
     *
140
     * @return void
141
     */
142 27
    public function init()
143
    {
144 27
        $this->newProject = new Project();
145 27
        $tdf = $this->project->getTaskDefinitions();
146 27
        $this->newProject->addTaskDefinition("property", $tdf["property"]);
147 27
    }
148
149
    /**
150
     * Called in execute or createProperty if newProject is null.
151
     *
152
     * <p>This can happen if the same instance of this task is run
153
     * twice as newProject is set to null at the end of execute (to
154
     * save memory and help the GC).</p>
155
     *
156
     * <p>Sets all properties that have been defined as nested
157
     * property elements.</p>
158
     */
159 6
    private function reinit()
160
    {
161 6
        $this->init();
162
163 6
        $count = count($this->properties);
164 6
        for ($i = 0; $i < $count; $i++) {
165
            /**
166
             * @var PropertyTask $p
167
             */
168 6
            $p = $this->properties[$i];
169
            /**
170
             * @var PropertyTask $newP
171
             */
172 6
            $newP = $this->newProject->createTask("property");
173 6
            $newP->setName($p->getName());
174 6
            if ($p->getValue() !== null) {
175 6
                $newP->setValue($p->getValue());
176
            }
177 6
            if ($p->getFile() !== null) {
178
                $newP->setFile($p->getFile());
179
            }
180 6
            if ($p->getPrefix() !== null) {
181
                $newP->setPrefix($p->getPrefix());
182
            }
183 6
            if ($p->getRefid() !== null) {
184
                $newP->setRefid($p->getRefid());
185
            }
186 6
            if ($p->getEnvironment() !== null) {
187
                $newP->setEnvironment($p->getEnvironment());
188
            }
189 6
            if ($p->getUserProperty() !== null) {
190 6
                $newP->setUserProperty($p->getUserProperty());
191
            }
192 6
            $newP->setOverride($p->getOverride());
193 6
            $newP->setLogoutput($p->getLogoutput());
194 6
            $newP->setQuiet($p->getQuiet());
195
196 6
            $this->properties[$i] = $newP;
197
        }
198 6
    }
199
200
    /**
201
     * Main entry point for the task.
202
     *
203
     * @return void
204
     */
205 24
    public function main()
206
    {
207
        // Call Phing on the file set with the attribute "phingfile"
208 24
        if ($this->phingFile !== null || $this->dir !== null) {
209 24
            $this->processFile();
210
        }
211
212
        // if no filesets are given stop here; else process filesets
213 21
        if (!empty($this->filesets)) {
214
            // preserve old settings
215
            $savedDir = $this->dir;
216
            $savedPhingFile = $this->phingFile;
217
            $savedTarget = $this->newTarget;
218
219
            // set no specific target for files in filesets
220
            // [HL] I'm commenting this out; I don't know why this should not be supported!
221
            // $this->newTarget = null;
222
223
            foreach ($this->filesets as $fs) {
224
                $ds = $fs->getDirectoryScanner($this->project);
225
226
                $fromDir = $fs->getDir($this->project);
0 ignored issues
show
Unused Code introduced by
The assignment to $fromDir is dead and can be removed.
Loading history...
227
                $srcFiles = $ds->getIncludedFiles();
228
229
                foreach ($srcFiles as $fname) {
230
                    $f = new PhingFile($ds->getbasedir(), $fname);
231
                    $f = $f->getAbsoluteFile();
232
                    $this->phingFile = $f->getAbsolutePath();
233
                    $this->dir = $f->getParentFile();
234
                    $this->processFile(); // run Phing!
235
                }
236
            }
237
238
            // side effect free programming ;-)
239
            $this->dir = $savedDir;
240
            $this->phingFile = $savedPhingFile;
241
            $this->newTarget = $savedTarget;
242
243
            // [HL] change back to correct dir
244
            if ($this->dir !== null) {
245
                chdir($this->dir->getAbsolutePath());
246
            }
247
        }
248
249
        // Remove any dangling references to help the GC
250 21
        foreach ($this->properties as $property) {
251 11
            $property->setFallback(null);
252
        }
253 21
    }
254
255
    /**
256
     * Execute phing file.
257
     *
258
     * @throws BuildException
259
     */
260 24
    private function processFile(): void
261
    {
262 24
        $buildFailed = false;
263 24
        $savedDir = $this->dir;
264 24
        $savedPhingFile = $this->phingFile;
265 24
        $savedTarget = $this->newTarget;
266
267 24
        $savedBasedirAbsPath = null; // this is used to save the basedir *if* we change it
268
269
        try {
270 24
            $this->getNewProject();
271
272 24
            $this->initializeProject();
273
274 24
            if ($this->dir !== null) {
275 4
                if (!$this->useNativeBasedir) {
276 4
                    $this->newProject->setBasedir($this->dir);
277 4
                    if ($savedDir !== null) { // has been set explicitly
278 4
                        $this->newProject->setInheritedProperty('project.basedir', $this->dir->getAbsolutePath());
279
                    }
280
                }
281
            } else {
282
                // Since we're not changing the basedir here (for file resolution),
283
                // we don't need to worry about any side-effects in this scanrio.
284 21
                $this->dir = $this->getProject()->getBasedir();
285
            }
286
287 24
            $this->overrideProperties();
288 24
            $this->phingFile = $this->phingFile ?? 'build.xml';
289
290 24
            $fu = new FileUtils();
291 24
            $file = $fu->resolveFile($this->dir, $this->phingFile);
292 24
            $this->phingFile = $file->getAbsolutePath();
293
294 24
            $this->log(
295 24
                "Calling Buildfile '" . $this->phingFile . "' with target '" . $this->newTarget . "'",
296 24
                Project::MSG_VERBOSE
297
            );
298
299 24
            $this->newProject->setUserProperty("phing.file", $this->phingFile);
300
301 24
            ProjectConfigurator::configureProject($this->newProject, new PhingFile($this->phingFile));
302
303 23
            if ($this->newTarget === null) {
304
                $this->newTarget = $this->newProject->getDefaultTarget();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->newProject->getDefaultTarget() of type string is incompatible with the declared type Target of property $newTarget.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
305
            }
306
307
            // Are we trying to call the target in which we are defined?
308
            if (
309 23
                $this->newProject->getBaseDir() == $this->project->getBaseDir()
310 19
                && $this->newProject->getProperty("phing.file") == $this->project->getProperty("phing.file")
311 16
                && $this->getOwningTarget() !== null
312 16
                && $this->newTarget == $this->getOwningTarget()->getName()
313
            ) {
314 2
                throw new BuildException("phing task calling its own parent target");
315
            }
316
317 21
            $this->addReferences();
318 21
            $this->newProject->executeTarget($this->newTarget);
319 4
        } catch (Exception $e) {
320 4
            $buildFailed = true;
321 4
            $this->log($e->getMessage(), Project::MSG_ERR);
322 4
            if (Phing::getMsgOutputLevel() <= Project::MSG_DEBUG) {
323 4
                $lines = explode("\n", $e->getTraceAsString());
324 4
                foreach ($lines as $line) {
325 4
                    $this->log($line, Project::MSG_DEBUG);
326
                }
327
            }
328 21
        } finally {
329
            // reset environment values to prevent side-effects.
330
331 24
            $this->newProject = null;
332 24
            $pkeys = array_keys($this->properties);
333 24
            foreach ($pkeys as $k) {
334 11
                $this->properties[$k]->setProject(null);
335
            }
336
337 24
            if ($this->output !== null && $this->out !== null) {
338 1
                $this->out->close();
339
            }
340
341 24
            $this->dir = $savedDir;
342 24
            $this->phingFile = $savedPhingFile;
343 24
            $this->newTarget = $savedTarget;
344
345
            // If the basedir for any project was changed, we need to set that back here.
346 24
            if ($savedBasedirAbsPath !== null) {
0 ignored issues
show
introduced by
The condition $savedBasedirAbsPath !== null is always false.
Loading history...
347
                chdir($savedBasedirAbsPath);
348
            }
349
350 24
            if ($this->haltOnFailure && $buildFailed) {
351 24
                throw new BuildException('Execution of the target buildfile failed. Aborting.');
352
            }
353
        }
354 21
    }
355
356
    /**
357
     * Get the (sub)-Project instance currently in use.
358
     *
359
     * @return Project
360
     */
361 24
    protected function getNewProject(): \Project
362
    {
363 24
        if ($this->newProject === null) {
364 6
            $this->reinit();
365
        }
366 24
        return $this->newProject;
367
    }
368
369
    /**
370
     * Configure the Project, i.e. make intance, attach build listeners
371
     * (copy from father project), add Task and Datatype definitions,
372
     * copy properties and references from old project if these options
373
     * are set via the attributes of the XML tag.
374
     *
375
     * Developer note:
376
     * This function replaces the old methods "init", "_reinit" and
377
     * "_initializeProject".
378
     */
379 24
    private function initializeProject()
380
    {
381 24
        $this->newProject->setInputHandler($this->project->getInputHandler());
382
383 24
        foreach ($this->project->getBuildListeners() as $listener) {
384 24
            $this->newProject->addBuildListener($listener);
385
        }
386
387
        /* Copy things from old project. Datatypes and Tasks are always
388
         * copied, properties and references only if specified so/not
389
         * specified otherwise in the XML definition.
390
         */
391
        // Add Datatype definitions
392 24
        foreach ($this->project->getDataTypeDefinitions() as $typeName => $typeClass) {
393 24
            $this->newProject->addDataTypeDefinition($typeName, $typeClass);
394
        }
395
396
        // Add Task definitions
397 24
        foreach ($this->project->getTaskDefinitions() as $taskName => $taskClass) {
398 24
            if ($taskClass == "propertytask") {
399
                // we have already added this taskdef in init()
400
                continue;
401
            }
402 24
            $this->newProject->addTaskDefinition($taskName, $taskClass);
403
        }
404
405 24
        if ($this->output !== null) {
406
            try {
407 1
                if ($this->dir !== null) {
408 1
                    $outfile = (new FileUtils())->resolveFile($this->dir, $this->output);
409
                } else {
410 1
                    $outfile = $this->getProject()->resolveFile($this->output);
411
                }
412 1
                $this->out = new FileOutputStream($outfile);
413 1
                $logger = new DefaultLogger();
414 1
                $logger->setMessageOutputLevel(Project::MSG_INFO);
415 1
                $logger->setOutputStream($this->out);
416 1
                $logger->setErrorStream($this->out);
417 1
                $this->newProject->addBuildListener($logger);
418
            } catch (Exception $ex) {
419
                $this->log("Phing: Can't set output to " . $this->output);
420
            }
421
        }
422
423 24
        if ($this->useNativeBasedir) {
424
            $this->addAlmostAll($this->getProject()->getUserProperties(), 'user');
425
        } else {
426 24
            $this->project->copyUserProperties($this->newProject);
427
        }
428
429 24
        if (!$this->inheritAll) {
430
            // set System built-in properties separately,
431
            // b/c we won't inherit them.
432 13
            $this->newProject->setSystemProperties();
433
        } else {
434 12
            $this->addAlmostAll($this->getProject()->getProperties(), 'plain');
435
        }
436 24
    }
437
438
    /**
439
     * Copies all properties from the given table to the new project -
440
     * omitting those that have already been set in the new project as
441
     * well as properties named basedir or phing.file.
442
     * @param array $props properties <code>Hashtable</code> to copy to the
443
     * new project.
444
     * @param string $type the type of property to set (a plain Phing property, a
445
     * user property or an inherited property).
446
     */
447 12
    private function addAlmostAll(array $props, string $type): void
448
    {
449 12
        foreach ($props as $name => $value) {
450 12
            if ($name === 'basedir' || $name === 'phing.file' || $name === 'phing.version') {
451
                // basedir and phing.file get special treatment in main()
452 12
                continue;
453
            }
454 12
            if ($type === 'plain') {
455
                // don't re-set user properties, avoid the warning message
456 12
                if ($this->newProject->getProperty($name) === null) {
457
                    // no user property
458 12
                    $this->newProject->setNewProperty($name, $value);
459
                }
460
            } elseif ($type === 'user') {
461
                $this->newProject->setUserProperty($name, $value);
462
            } elseif ($type === 'inherited') {
463
                $this->newProject->setInheritedProperty($name, $value);
464
            }
465
        }
466 12
    }
467
468
    /**
469
     * Override the properties in the new project with the one
470
     * explicitly defined as nested elements here.
471
     *
472
     * @return void
473
     * @throws BuildException
474
     */
475 24
    private function overrideProperties()
476
    {
477 24
        foreach (array_keys($this->properties) as $i) {
478 11
            $p = $this->properties[$i];
479 11
            $p->setProject($this->newProject);
480 11
            $p->main();
481
        }
482 24
        if ($this->useNativeBasedir) {
483
            $this->addAlmostAll($this->getProject()->getInheritedProperties(), 'inherited');
484
        } else {
485 24
            $this->project->copyInheritedProperties($this->newProject);
486
        }
487 24
    }
488
489
    /**
490
     * Add the references explicitly defined as nested elements to the
491
     * new project.  Also copy over all references that don't override
492
     * existing references in the new project if inheritrefs has been
493
     * requested.
494
     *
495
     * @return void
496
     * @throws BuildException
497
     */
498 21
    private function addReferences()
499
    {
500
501
        // parent project references
502 21
        $projReferences = $this->project->getReferences();
503
504 21
        $newReferences = $this->newProject->getReferences();
505
506 21
        $subprojRefKeys = [];
507
508 21
        if (count($this->references) > 0) {
509
            for ($i = 0, $count = count($this->references); $i < $count; $i++) {
510
                /** @var Reference $ref */
511
                $ref = $this->references[$i];
512
                $refid = $ref->getRefId();
513
514
                if ($refid === null) {
515
                    throw new BuildException('the refid attribute is required for reference elements');
516
                }
517
                if (!isset($projReferences[$refid])) {
518
                    $this->log("Parent project doesn't contain any reference '" . $refid . "'", Project::MSG_WARN);
519
                    continue;
520
                }
521
522
                $subprojRefKeys[] = $refid;
523
                //thisReferences.remove(refid);
524
                $toRefid = $ref->getToRefid();
0 ignored issues
show
Bug introduced by
The method getToRefid() does not exist on Reference. Did you maybe mean getRefId()? ( Ignorable by Annotation )

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

524
                /** @scrutinizer ignore-call */ 
525
                $toRefid = $ref->getToRefid();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
525
                if ($toRefid === null) {
526
                    $toRefid = $refid;
527
                }
528
                $this->copyReference($refid, $toRefid);
529
            }
530
        }
531
532
        // Now add all references that are not defined in the
533
        // subproject, if inheritRefs is true
534 21
        if ($this->inheritRefs) {
535
            // get the keys that are were not used by the subproject
536 2
            $unusedRefKeys = array_diff(array_keys($projReferences), $subprojRefKeys);
537
538 2
            foreach ($unusedRefKeys as $key) {
539 2
                if (isset($newReferences[$key])) {
540 2
                    continue;
541
                }
542 2
                $this->copyReference($key, $key);
543
            }
544
        }
545 21
    }
546
547
    /**
548
     * Try to clone and reconfigure the object referenced by oldkey in
549
     * the parent project and add it to the new project with the key
550
     * newkey.
551
     *
552
     * <p>If we cannot clone it, copy the referenced object itself and
553
     * keep our fingers crossed.</p>
554
     *
555
     * @param  string $oldKey
556
     * @param  string $newKey
557
     * @throws BuildException
558
     * @return void
559
     */
560 2
    private function copyReference($oldKey, $newKey)
561
    {
562 2
        $orig = $this->project->getReference($oldKey);
563 2
        if ($orig === null) {
564
            $this->log(
565
                "No object referenced by " . $oldKey . ". Can't copy to "
566
                . $newKey,
567
                Project::MSG_WARN
568
            );
569
570
            return;
571
        }
572
573 2
        $copy = clone $orig;
574
575 2
        if ($copy instanceof ProjectComponent) {
576 2
            $copy->setProject($this->newProject);
577 2
        } elseif (in_array('setProject', get_class_methods(get_class($copy)))) {
578
            $copy->setProject($this->newProject);
579 2
        } elseif (!($copy instanceof Project)) {
580
            // don't copy the old "Project" itself
581
            $msg = "Error setting new project instance for "
582
                . "reference with id " . $oldKey;
583
            throw new BuildException($msg);
584
        }
585
586 2
        $this->newProject->addReference($newKey, $copy);
587 2
    }
588
589
    /**
590
     * If true, pass all properties to the new phing project.
591
     * Defaults to true.
592
     *
593
     * @param $value
594
     */
595 20
    public function setInheritAll($value)
596
    {
597 20
        $this->inheritAll = (bool) $value;
598 20
    }
599
600
    /**
601
     * If true, pass all references to the new phing project.
602
     * Defaults to false.
603
     *
604
     * @param $value
605
     */
606 12
    public function setInheritRefs($value)
607
    {
608 12
        $this->inheritRefs = (bool) $value;
609 12
    }
610
611
    /**
612
     * The directory to use as a base directory for the new phing project.
613
     * Defaults to the current project's basedir, unless inheritall
614
     * has been set to false, in which case it doesn't have a default
615
     * value. This will override the basedir setting of the called project.
616
     *
617
     * @param PhingFile $d
618
     */
619 4
    public function setDir(PhingFile $d): void
620
    {
621 4
        $this->dir = $d;
622 4
    }
623
624
    /**
625
     * The build file to use.
626
     * Defaults to "build.xml". This file is expected to be a filename relative
627
     * to the dir attribute given.
628
     *
629
     * @param $s
630
     */
631 24
    public function setPhingFile($s)
632
    {
633
        // it is a string and not a file to handle relative/absolute
634
        // otherwise a relative file will be resolved based on the current
635
        // basedir.
636 24
        $this->phingFile = $s;
637 24
    }
638
639
    /**
640
     * Alias function for setPhingfile
641
     *
642
     * @param $s
643
     */
644
    public function setBuildfile($s)
645
    {
646
        $this->setPhingFile($s);
647
    }
648
649
    /**
650
     * The target of the new Phing project to execute.
651
     * Defaults to the new project's default target.
652
     *
653
     * @param string $s
654
     */
655 25
    public function setTarget(string $s)
656
    {
657 25
        if ('' === $s) {
658 1
            throw new BuildException("target attribute must not be empty");
659
        }
660
661 24
        $this->newTarget = $s;
0 ignored issues
show
Documentation Bug introduced by
It seems like $s of type string is incompatible with the declared type Target of property $newTarget.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
662 24
    }
663
664
    /**
665
     * Set the filename to write the output to. This is relative to the value
666
     * of the dir attribute if it has been set or to the base directory of the
667
     * current project otherwise.
668
     * @param string $outputFile the name of the file to which the output should go.
669
     */
670 1
    public function setOutput(string $outputFile): void
671
    {
672 1
        $this->output = $outputFile;
673 1
    }
674
675
    /**
676
     * Property to pass to the new project.
677
     * The property is passed as a 'user property'
678
     */
679 11
    public function createProperty()
680
    {
681 11
        $p = new PropertyTask();
682 11
        $p->setFallback($this->getNewProject());
683 11
        $p->setUserProperty(true);
684 11
        $this->properties[] = $p;
685
686 11
        return $p;
687
    }
688
689
    /**
690
     * Reference element identifying a data type to carry
691
     * over to the new project.
692
     *
693
     * @param PhingReference $ref
694
     */
695 1
    public function addReference(PhingReference $ref)
696
    {
697 1
        $this->references[] = $ref;
698 1
    }
699
}
700