Passed
Push — master ( 3372b2...cdab9c )
by Siad
12:15
created

ComponentHelper::initSubProject()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

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