Completed
Push — master ( c6396d...9f5552 )
by Michiel
16:38
created

ComponentHelper::createCondition()   A

Complexity

Conditions 6
Paths 18

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6.6829

Importance

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