Passed
Push — main ( 221f6d...f8c128 )
by Siad
05:28
created

src/Phing/Parser/TargetHandler.php (1 issue)

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\Parser;
22
23
use Phing\Exception\BuildException;
24
use Phing\ExtensionPoint;
25
use Phing\Project;
26
use Phing\Target;
27
use Phing\Util\StringHelper;
28
29
/**
30
 * The target handler class.
31
 *
32
 * This class handles the occurrence of a <target> tag and it's possible
33
 * nested tags (datatypes and tasks).
34
 *
35
 * @author    Andreas Aderhold <[email protected]>
36
 * @copyright 2001,2002 THYRELL. All rights reserved
37
 */
38
class TargetHandler extends AbstractHandler
39
{
40
    /**
41
     * Reference to the target object that represents the currently parsed
42
     * target.
43
     *
44
     * @var Target the target instance
45
     */
46
    private $target;
47
48
    /**
49
     * The phing project configurator object.
50
     *
51
     * @var ProjectConfigurator
52
     */
53
    private $configurator;
54
55
    /**
56
     * @var XmlContext
57
     */
58
    private $context;
59
60
    /**
61
     * Constructs a new TargetHandler.
62
     *
63
     * @internal param the $object ExpatParser object
64
     * @internal param the $object parent handler that invoked this handler
65
     * @internal param the $object ProjectConfigurator object
66
     */
67 859
    public function __construct(
68
        AbstractSAXParser $parser,
69
        AbstractHandler $parentHandler,
70
        ProjectConfigurator $configurator,
71
        XmlContext $context
72
    ) {
73 859
        parent::__construct($parser, $parentHandler);
74 859
        $this->configurator = $configurator;
75 859
        $this->context = $context;
76 859
    }
77
78
    /**
79
     * Executes initialization actions required to setup the data structures
80
     * related to the tag.
81
     * <p>
82
     * This includes:
83
     * <ul>
84
     * <li>creation of the target object</li>
85
     * <li>calling the setters for attributes</li>
86
     * <li>adding the target to the project</li>
87
     * <li>adding a reference to the target (if id attribute is given)</li>
88
     * </ul>.
89
     *
90
     * @param $tag
91
     * @param $attrs
92
     *
93
     * @throws BuildException
94
     * @throws ExpatParseException
95
     *
96
     * @internal param the $string tag that comes in
97
     * @internal param attributes $array the tag carries
98
     */
99 859
    public function init($tag, $attrs)
100
    {
101 859
        $name = null;
102 859
        $depends = '';
103 859
        $extensionPoint = null; //'fail';
104 859
        $extensionPointMissing = null;
105 859
        $ifCond = null;
106 859
        $unlessCond = null;
107 859
        $id = null;
108 859
        $description = null;
109 859
        $isHidden = false;
110 859
        $logskipped = false;
111
112 859
        foreach ($attrs as $key => $value) {
113 859
            switch ($key) {
114 859
                case 'name':
115 859
                    $name = (string) $value;
116
117 859
                    break;
118
119 421
                case 'depends':
120 257
                    $depends = (string) $value;
121
122 257
                    break;
123
124 198
                case 'if':
125 2
                    $ifCond = (string) $value;
126
127 2
                    break;
128
129 198
                case 'unless':
130 7
                    $unlessCond = (string) $value;
131
132 7
                    break;
133
134 191
                case 'id':
135
                    $id = (string) $value;
136
137
                    break;
138
139 191
                case 'hidden':
140
                    $isHidden = ('true' === $value || '1' === $value);
141
142
                    break;
143
144 191
                case 'description':
145 183
                    $description = (string) $value;
146
147 183
                    break;
148
149 8
                case 'logskipped':
150
                    $logskipped = $value;
151
152
                    break;
153
154 8
                case 'extensionof':
155 7
                    $extensionPoint = $value;
156
157 7
                    break;
158
159 3
                case 'onmissingextensionpoint':
160 3
                    if (!in_array($value, ['fail', 'warn', 'ignore'], true)) {
161
                        throw new BuildException('Invalid onMissingExtensionPoint ' . $value);
162
                    }
163 3
                    $extensionPointMissing = $value;
164
165 3
                    break;
166
167
                default:
168
                    throw new ExpatParseException("Unexpected attribute '{$key}'", $this->parser->getLocation());
0 ignored issues
show
The method getLocation() does not exist on Phing\Parser\AbstractSAXParser. Since it exists in all sub-types, consider adding an abstract or default implementation to Phing\Parser\AbstractSAXParser. ( Ignorable by Annotation )

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

168
                    throw new ExpatParseException("Unexpected attribute '{$key}'", $this->parser->/** @scrutinizer ignore-call */ getLocation());
Loading history...
169
            }
170
        }
171
172 859
        if (null === $name) {
173
            throw new ExpatParseException(
174
                'target element appears without a name attribute',
175
                $this->parser->getLocation()
176
            );
177
        }
178
179
        // shorthand
180 859
        $project = $this->configurator->project;
181
182
        // check to see if this target is a dup within the same file
183 859
        if (isset($this->context->getCurrentTargets()[$name])) {
184
            throw new BuildException(
185
                "Duplicate target: {$name}",
186
                $this->parser->getLocation()
187
            );
188
        }
189
190 859
        $this->target = 'target' === $tag ? new Target() : new ExtensionPoint();
191 859
        $this->target->setProject($project);
192 859
        $this->target->setLocation($this->parser->getLocation());
193 859
        $this->target->setHidden($isHidden);
194 859
        $this->target->setIf($ifCond);
195 859
        $this->target->setUnless($unlessCond);
196 859
        $this->target->setDescription($description);
197 859
        $this->target->setLogSkipped(StringHelper::booleanValue($logskipped));
198
        // take care of dependencies
199 859
        if ('' !== $depends) {
200 257
            $this->target->setDepends($depends);
201
        }
202
203
        // check to see if target with same name is already defined
204 859
        $projectTargets = $project->getTargets();
205 859
        if (isset($projectTargets[$name])) {
206
            if (
207 92
                $this->configurator->isIgnoringProjectTag()
208 92
                && null != $this->configurator->getCurrentProjectName()
209 92
                && 0 != strlen($this->configurator->getCurrentProjectName())
210
            ) {
211
                // In an impored file (and not completely
212
                // ignoring the project tag)
213 92
                $newName = $this->configurator->getCurrentProjectName() . '.' . $name;
214 92
                $project->log(
215
                    'Already defined in main or a previous import, ' .
216 92
                    "define {$name} as {$newName}",
217 92
                    Project::MSG_VERBOSE
218
                );
219 92
                $name = $newName;
220
            } else {
221
                $project->log(
222
                    'Already defined in main or a previous import, ' .
223
                    "ignore {$name}",
224
                    Project::MSG_VERBOSE
225
                );
226
                $name = null;
227
            }
228
        }
229
230 859
        if (null !== $name) {
231 859
            $this->target->setName($name);
232 859
            $project->addOrReplaceTarget($name, $this->target);
233 859
            if (null !== $id && '' !== $id) {
234
                $project->addReference($id, $this->target);
235
            }
236
        }
237
238 859
        if (null !== $extensionPointMissing && null === $extensionPoint) {
239 1
            throw new BuildException(
240
                'onMissingExtensionPoint attribute cannot ' .
241 1
                'be specified unless extensionOf is specified',
242 1
                $this->target->getLocation()
243
            );
244
        }
245 859
        if (null !== $extensionPoint) {
246 7
            foreach (Target::parseDepends($extensionPoint, $name, 'extensionof') as $extPointName) {
247 7
                if (null === $extensionPointMissing) {
248 5
                    $extensionPointMissing = 'fail';
249
                }
250 7
                $this->context->addExtensionPoint([
251 7
                    $extPointName,
252 7
                    $this->target->getName(),
253 7
                    $extensionPointMissing,
254
                    null,
255
                ]);
256
            }
257
        }
258 859
    }
259
260
    /**
261
     * Checks for nested tags within the current one. Creates and calls
262
     * handlers respectively.
263
     *
264
     * @param string $name  the tag that comes in
265
     * @param array  $attrs attributes the tag carries
266
     */
267 849
    public function startElement($name, $attrs)
268
    {
269 849
        $tmp = new ElementHandler($this->parser, $this, $this->configurator, null, null, $this->target);
270 849
        $tmp->init($name, $attrs);
271 849
    }
272
273
    /**
274
     * Checks if this target has dependencies and/or nested tasks.
275
     * If the target has neither, show a warning.
276
     */
277 859
    protected function finished()
278
    {
279 859
        if (!$this->target instanceof ExtensionPoint && !count($this->target->getDependencies()) && !count($this->target->getTasks())) {
280 165
            $this->configurator->project->log(
281 165
                "Warning: target '" . $this->target->getName() .
282 165
                "' has no tasks or dependencies",
283 165
                Project::MSG_WARN
284
            );
285
        }
286 859
    }
287
}
288