Passed
Push — master ( f1e2bc...c4cbbf )
by Michiel
05:24
created

ComponentHelper::getUnmappedElementName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 2
dl 0
loc 10
ccs 5
cts 6
cp 0.8333
crap 2.0185
rs 10
c 0
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
namespace Phing;
21
22
use Exception;
23
use Phing\Exception\BuildException;
24
use Phing\Io\File;
25
use Phing\Io\IOException;
26
use Phing\Task\System\Condition\Condition;
27
use Phing\Type\DataType;
28
use Phing\Util\Properties;
29
use Phing\Util\StringHelper;
30
use ReflectionClass;
31
32
/**
33
 * Component creation and configuration
34
 *
35
 * @author Michiel Rook <[email protected]>
36
 *
37
 */
38
class ComponentHelper
39
{
40
    public const COMPONENT_HELPER_REFERENCE = "phing.ComponentHelper";
41
42
    /**
43
     * @var Project
44
     */
45
    private $project;
46
47
    /**
48
     * task definitions for this project
49
     *
50
     * @var string[]
51
     */
52
    private $taskdefs = [];
53
54
    /**
55
     * type definitions for this project
56
     *
57
     * @var string[]
58
     */
59
    private $typedefs = [];
60
61
    /**
62
     * ComponentHelper constructor.
63
     *
64
     * @param Project $project
65
     */
66 839
    public function __construct(Project $project)
67
    {
68 839
        $this->project = $project;
69 839
    }
70
71
    /**
72
     * @param Project $project
73
     * @return ComponentHelper
74
     */
75 839
    public static function getComponentHelper(Project $project)
76
    {
77 839
        if ($project === null) {
78
            return null;
79
        }
80
81
        /**
82
         * @var ComponentHelper $componentHelper
83
         */
84 839
        $componentHelper = $project->getReference(self::COMPONENT_HELPER_REFERENCE);
85
86 839
        if ($componentHelper !== null) {
87 838
            return $componentHelper;
88
        }
89
90 839
        $componentHelper = new ComponentHelper($project);
91 839
        $project->addReference(self::COMPONENT_HELPER_REFERENCE, $componentHelper);
92
93 839
        return $componentHelper;
94
    }
95
96
    /**
97
     * Initializes the default tasks and data types
98
     */
99 837
    public function initDefaultDefinitions()
100
    {
101 837
        $this->initDefaultTasks();
102 837
        $this->initDefaultDataTypes();
103 837
        $this->initCustomTasks();
104 837
        $this->initCustomDataTypes();
105 837
    }
106
107
    /**
108
     * Adds a task definition.
109
     *
110
     * @param string $name Name of tag.
111
     * @param string $class The class path to use.
112
     * @param string $classpath The classpat to use.
113
     */
114 837
    public function addTaskDefinition($name, $class, $classpath = null)
115
    {
116 837
        if ($class === "") {
117
            $this->project->log("Task $name has no class defined.", Project::MSG_ERR);
118 837
        } elseif (!isset($this->taskdefs[$name])) {
119 837
            Phing::import($class, $classpath);
120 837
            $this->taskdefs[$name] = $class;
121 837
            $this->project->log("  +Task definition: $name ($class)", Project::MSG_DEBUG);
122
        } else {
123 47
            $this->project->log("Task $name ($class) already registered, skipping", Project::MSG_VERBOSE);
124
        }
125 837
    }
126
127
    /**
128
     * Returns the task definitions
129
     *
130
     * @return array
131
     */
132 46
    public function getTaskDefinitions()
133
    {
134 46
        return $this->taskdefs;
135
    }
136
137
    /**
138
     * Adds a data type definition.
139
     *
140
     * @param string $typeName Name of the type.
141
     * @param string $typeClass The class to use.
142
     * @param string $classpath The classpath to use.
143
     */
144 837
    public function addDataTypeDefinition($typeName, $typeClass, $classpath = null)
145
    {
146 837
        if (!isset($this->typedefs[$typeName])) {
147 837
            Phing::import($typeClass, $classpath);
148 837
            $this->typedefs[$typeName] = $typeClass;
149 837
            $this->project->log("  +User datatype: $typeName ($typeClass)", Project::MSG_DEBUG);
150
        } else {
151 33
            $this->project->log("Type $typeName ($typeClass) already registered, skipping", Project::MSG_VERBOSE);
152
        }
153 837
    }
154
155 130
    public static function getElementName(Project $p = null, $o = null, $brief = false)
156
    {
157
        //if ($p === null) {
158
        //    TODO Project::getProject($o)
159
        //}
160
161 130
        return $p === null
162 130
            ? self::getUnmappedElementName($o, $brief)
163 130
            : self::getComponentHelper($p)->getElementName(null, $o, $brief);
164
    }
165
166 130
    private static function getUnmappedElementName($c, $brief)
167
    {
168 130
        $clazz = new ReflectionClass($c);
169 130
        $name = $clazz->getName();
170
171 130
        if ($brief) {
172 130
            return $clazz->getShortName();
173
        }
174
175
        return $name;
176
    }
177
178
    /**
179
     * Returns the data type definitions
180
     *
181
     * @return array
182
     */
183 838
    public function getDataTypeDefinitions()
184
    {
185 838
        return $this->typedefs;
186
    }
187
188
    /**
189
     * Create a new task instance and return reference to it.
190
     *
191
     * @param string $taskType Task name
192
     * @return Task           A task object
193
     * @throws BuildException
194
     */
195 698
    public function createTask($taskType)
196
    {
197
        try {
198 698
            $classname = "";
199 698
            $tasklwr = strtolower($taskType);
200 698
            foreach ($this->taskdefs as $name => $class) {
201 698
                if (strtolower($name) === $tasklwr) {
202 693
                    $classname = $class;
203 693
                    break;
204
                }
205
            }
206
207 698
            if ($classname === "") {
208 83
                return null;
209
            }
210
211 693
            $o = $this->createObject($classname);
212
213 693
            if ($o instanceof Task) {
214 671
                $task = $o;
215
            } else {
216 227
                $this->project->log("  (Using TaskAdapter for: $taskType)", Project::MSG_DEBUG);
217
                // not a real task, try adapter
218 227
                $taskA = new TaskAdapter();
219 227
                $taskA->setProxy($o);
220 227
                $task = $taskA;
221
            }
222 693
            $task->setProject($this->project);
223 693
            $task->setTaskType($taskType);
224
            // set default value, can be changed by the user
225 693
            $task->setTaskName($taskType);
226 693
            $this->project->log("  +Task: " . $taskType, Project::MSG_DEBUG);
227
        } catch (Exception $t) {
228
            throw new BuildException("Could not create task of type: " . $taskType, $t);
229
        }
230
        // everything fine return reference
231 693
        return $task;
232
    }
233
234
    /**
235
     * Creates a new condition and returns the reference to it
236
     *
237
     * @param string $conditionType
238
     * @return Condition
239
     * @throws BuildException
240
     */
241 1
    public function createCondition($conditionType)
242
    {
243
        try {
244 1
            $classname = "";
245 1
            $tasklwr = strtolower($conditionType);
246 1
            foreach ($this->typedefs as $name => $class) {
247 1
                if (strtolower($name) === $tasklwr) {
248 1
                    $classname = $class;
249 1
                    break;
250
                }
251
            }
252
253 1
            if ($classname === "") {
254
                return null;
255
            }
256
257 1
            $o = $this->createObject($classname);
258
259 1
            if ($o instanceof Condition) {
260 1
                return $o;
261
            }
262
263
            throw new BuildException("Not actually a condition");
264
        } catch (Exception $e) {
265
            throw new BuildException("Could not create condition of type: " . $conditionType, $e);
266
        }
267
    }
268
269 693
    private function createObject(string $classname)
270
    {
271 693
        if ($classname === "") {
272
            return null;
273
        }
274
275 693
        $cls = Phing::import($classname);
276
277 693
        if (!class_exists($cls)) {
278
            throw new BuildException(
279
                "Could not instantiate class $cls, even though a class was specified. (Make sure that the specified class file contains a class with the correct name.)"
280
            );
281
        }
282
283 693
        return new $cls();
284
    }
285
286
    /**
287
     * Create a datatype instance and return reference to it
288
     * See createTask() for explanation how this works
289
     *
290
     * @param string $typeName Type name
291
     * @return object         A datatype object
292
     * @throws BuildException
293
     *                                 Exception
294
     */
295 83
    public function createDataType($typeName)
296
    {
297
        try {
298 83
            $cls = "";
299 83
            $typelwr = strtolower($typeName);
300 83
            foreach ($this->typedefs as $name => $class) {
301 83
                if (strtolower($name) === $typelwr) {
302 83
                    $cls = StringHelper::unqualify($class);
303 83
                    break;
304
                }
305
            }
306
307 83
            if ($cls === "") {
308
                return null;
309
            }
310
311 83
            if (!class_exists($cls)) {
312
                throw new BuildException(
313
                    "Could not instantiate class $cls, even though a class was specified. (Make sure that the specified class file contains a class with the correct name.)"
314
                );
315
            }
316
317 83
            $type = new $cls();
318 83
            $this->project->log("  +Type: $typeName", Project::MSG_DEBUG);
319 83
            if ($type instanceof ProjectComponent) {
320 83
                $type->setProject($this->project);
321
            }
322 83
            if (!($type instanceof DataType)) {
323 83
                throw new Exception("$class is not an instance of phing.types.DataType");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $class seems to be defined by a foreach iteration on line 300. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
324
            }
325
        } catch (Exception $t) {
326
            throw new BuildException("Could not create type: $typeName", $t);
327
        }
328
        // everything fine return reference
329 83
        return $type;
330
    }
331
332 837
    private function initDefaultTasks()
333
    {
334 837
        $taskdefs = Phing::getResourcePath("etc/default.tasks.properties");
335
336
        try { // try to load taskdefs
337 837
            $props = new Properties();
338 837
            $in = new File((string) $taskdefs);
339
340 837
            if ($in === null) {
341
                throw new BuildException("Can't load default task list");
342
            }
343 837
            $props->load($in);
344
345 837
            $enum = $props->propertyNames();
346 837
            foreach ($enum as $key) {
347 837
                $value = $props->getProperty($key);
348 837
                $this->addTaskDefinition($key, $value);
349
            }
350
        } catch (IOException $ioe) {
351
            throw new BuildException("Can't load default task list");
352
        }
353 837
    }
354
355 837
    private function initDefaultDataTypes()
356
    {
357 837
        $typedefs = Phing::getResourcePath("etc/default.types.properties");
358
359
        try { // try to load typedefs
360 837
            $props = new Properties();
361 837
            $in = new File((string) $typedefs);
362 837
            if ($in === null) {
363
                throw new BuildException("Can't load default datatype list");
364
            }
365 837
            $props->load($in);
366
367 837
            $enum = $props->propertyNames();
368 837
            foreach ($enum as $key) {
369 837
                $value = $props->getProperty($key);
370 837
                $this->addDataTypeDefinition($key, $value);
371
            }
372
        } catch (IOException $ioe) {
373
            throw new BuildException("Can't load default datatype list");
374
        }
375 837
    }
376
377 837
    private function initCustomTasks()
378
    {
379 837
        $taskdefs = Phing::getResourcePath("custom.task.properties");
380
        try { // try to load typedefs
381 837
            $props = new Properties();
382 837
            $in = new File((string) $taskdefs);
383 837
            if (!$in->exists()) {
384
                return;
385
            }
386 837
            $props->load($in);
387 837
            $enum = $props->propertyNames();
388 837
            foreach ($enum as $key) {
389 837
                $value = $props->getProperty($key);
390 837
                $this->addTaskDefinition($key, $value);
391
            }
392
        } catch (IOException $ioe) {
393
            throw new BuildException("Can't load custom task list");
394
        }
395 837
    }
396
397 837
    private function initCustomDataTypes()
398
    {
399 837
        $typedefs = Phing::getResourcePath("custom.type.properties");
400
        try { // try to load typedefs
401 837
            $props = new Properties();
402 837
            $in = new File((string) $typedefs);
403 837
            if (!$in->exists()) {
404
                return;
405
            }
406 837
            $props->load($in);
407 837
            $enum = $props->propertyNames();
408 837
            foreach ($enum as $key) {
409 837
                $value = $props->getProperty($key);
410 837
                $this->addDataTypeDefinition($key, $value);
411
            }
412
        } catch (IOException $ioe) {
413
            throw new BuildException("Can't load custom type list");
414
        }
415 837
    }
416
417 36
    public function initSubProject(ComponentHelper $helper): void
418
    {
419 36
        $dataTypes = $helper->getDataTypeDefinitions();
420 36
        foreach ($dataTypes as $name => $class) {
421 36
            $this->addDataTypeDefinition($name, $class);
422
        }
423 36
    }
424
}
425