Completed
Push — master ( e8b22d...bec3f6 )
by Marko
11s
created

Entity   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 303
Duplicated Lines 10.56 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 30
c 0
b 0
f 0
lcom 1
cbo 4
dl 32
loc 303
ccs 84
cts 84
cp 1
rs 10

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A reset() 0 7 1
A attr() 0 4 1
A child() 0 4 1
A position() 0 7 1
A rotation() 0 7 1
A scale() 0 7 1
A animation() 0 4 1
A component() 14 14 3
A __call() 11 11 2
A domElement() 0 19 3
A appendAttributes() 0 6 2
A mixin() 0 5 1
A setAttribute() 7 7 4
A appendChildren() 0 10 3
A appendAnimations() 0 8 2
A addFormatComment() 0 7 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/** @formatter:off
3
 * ******************************************************************
4
 * Created by   Marko Kungla on Jun 20, 2016 - 9:11:10 PM
5
 * Contact      [email protected]
6
 * @copyright   2016 Marko Kungla - https://github.com/mkungla
7
 * @license     The MIT License (MIT)
8
 * 
9
 * @category       AframeVR
10
 * @package        aframe-php
11
 * 
12
 * Lang         PHP (php version >= 7)
13
 * Encoding     UTF-8
14
 * File         Entity.php
15
 * Code format  PSR-2 and 12
16
 * @link        https://github.com/mkungla/aframe-php
17
 * @issues      https://github.com/mkungla/aframe-php/issues
18
 * ********************************************************************
19
 * Contributors:
20
 * @author Marko Kungla <[email protected]>
21
 * ********************************************************************
22
 * Comments:
23
 * @formatter:on */
24
namespace AframeVR\Core;
25
26
use \AframeVR\Core\Exceptions\BadComponentCallException;
27
use \AframeVR\Interfaces\{
28
    ComponentInterface,
29
    EntityInterface,
30
    AnimationInterface
31
};
32
use \AframeVR\Core\Helpers\{
33
    EntityChildrenFactory,
34
    MeshAttributes,
35
    Helper
36
};
37
use \AframeVR\Core\Animation;
38
use \DOMElement;
39
use \Closure;
40
41
class Entity implements EntityInterface
42
{
43
    use MeshAttributes;
44
    
45
    /**
46
     * Array of used components
47
     *
48
     * @var array
49
     */
50
    protected $components = array();
51
    
52
    /**
53
     * Array of used animations
54
     *
55
     * @var array
56
     */
57
    protected $animations = array();
58
    
59
    /**
60
     * Dom element attributes
61
     *
62
     * @var unknown
63
     */
64
    protected $attrs = array();
65
    
66
    /**
67
     * Children Factory
68
     *
69
     * @var EntityChildrenFactory
70
     */
71
    protected $childrenFactory;
72
    
73
    /**
74
     * Indent used when rendering formated outout
75
     *
76
     * @var unknown
77
     */
78
    private $indentation = 0;
79
80
    /**
81
     * Constructor
82
     *
83
     * @param string $id            
84
     */
85 80
    public function __construct(string $id = 'untitled')
86
    {
87 80
        $this->attr('id', $id);
88
        
89
        /* Extending entity reset | initial setup */
90 80
        $this->reset();
91 80
    }
92
93
    /**
94
     * Reset primitive default attributtes
95
     *
96
     * {@inheritdoc}
97
     *
98
     * @return void
99
     */
100 75
    public function reset()
101
    {
102
        /* Components which All entities inherently have */
103 75
        $this->component('Position');
104 75
        $this->component('Rotation');
105 75
        $this->component('Scale');
106 75
    }
107
108
    /**
109
     * Set DOM attributes
110
     *
111
     * @param string $attr            
112
     * @param string $val            
113
     * @return void
114
     */
115 80
    public function attr(string $attr, string $val)
116
    {
117 80
        $this->attrs[$attr] = $val;
118 80
    }
119
120
    /**
121
     * Child entity / primitive
122
     *
123
     * @return EntityChildrenFactory
0 ignored issues
show
Documentation introduced by
Should the return type not be Helpers\EntityChildrenFactory?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
124
     */
125 5
    public function child(): EntityChildrenFactory
126
    {
127 5
        return $this->childrenFactory ?? $this->childrenFactory = new EntityChildrenFactory();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \AframeVR\Core\Helpers\EntityChildrenFactory() of type object<AframeVR\Core\Hel...\EntityChildrenFactory> is incompatible with the declared type object<EntityChildrenFactory> of property $childrenFactory.

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...
128
    }
129
130
    /**
131
     * Position component
132
     *
133
     * All entities inherently have the position component.
134
     *
135
     * @param int|float $x_axis            
136
     * @param int|float $y_axis            
137
     * @param int|float $z_axis            
138
     * @return EntityInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be \AframeVR\Interfaces\EntityInterface?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
139
     */
140 4
    public function position(float $x_axis = 0, float $y_axis = 0, float $z_axis = 0): EntityInterface
141
    {
142 4
        $this->component('Position')->positionX($x_axis);
143 4
        $this->component('Position')->positionY($y_axis);
144 4
        $this->component('Position')->positionZ($z_axis);
145 4
        return $this;
146
    }
147
148
    /**
149
     * Rotation component
150
     *
151
     * All entities inherently have the rotation component.
152
     *
153
     * @param int|float $roll            
154
     * @param int|float $pitch            
155
     * @param int|float $yaw            
156
     * @return EntityInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be \AframeVR\Interfaces\EntityInterface?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
157
     */
158 4
    public function rotation(float $roll = 0, float $pitch = 0, float $yaw = 0): EntityInterface
159
    {
160 4
        $this->component('Rotation')->roll($roll);
161 4
        $this->component('Rotation')->pitch($pitch);
162 4
        $this->component('Rotation')->yaw($yaw);
163 4
        return $this;
164
    }
165
166
    /**
167
     * Scale component
168
     *
169
     * All entities inherently have the scale component.
170
     *
171
     * @param int|float $scale_x            
172
     * @param int|float $scale_y            
173
     * @param int|float $scale_z            
174
     * @return EntityInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be \AframeVR\Interfaces\EntityInterface?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
175
     */
176 6
    public function scale(float $scale_x = 1, float $scale_y = 1, float $scale_z = 1): EntityInterface
177
    {
178 6
        $this->component('Scale')->scaleX($scale_x);
179 6
        $this->component('Scale')->scaleY($scale_y);
180 6
        $this->component('Scale')->scaleZ($scale_z);
181 6
        return $this;
182
    }
183
184
    /**
185
     * Animations
186
     *
187
     * @param mixed $name            
188
     * @return \AframeVR\Interfaces\AnimationInterface
189
     */
190 2
    public function animation($name = 'untitled'): AnimationInterface
191
    {
192 2
        return $this->animations[$name] ?? $this->animations[$name] = new Animation();
193
    }
194
195
    /**
196
     * Set mixin attribute
197
     *
198
     * @param string $id            
199
     * @return \AframeVR\Core\Entity
200
     */
201 1
    public function mixin(string $id)
202
    {
203 1
        $this->attr('mixin', $id);
204 1
        return $this;
205
    }
206
207
    /**
208
     * Load component for this entity
209
     *
210
     * @param string $component_name            
211
     * @throws \AframeVR\Core\Exceptions\BadComponentCallException
212
     * @return object|null
213
     */
214 80 View Code Duplication
    public function component(string $component_name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
215
    {
216 80
        if (! array_key_exists($component_name, $this->components)) {
217 80
            $component = sprintf('\AframeVR\Core\Components\%s\%sComponent', ucfirst($component_name), 
218
                ucfirst($component_name));
219 80
            if (class_exists($component)) {
220 80
                $this->components[$component_name] = new $component();
221
            } else {
222 1
                throw new BadComponentCallException($component_name);
223
            }
224
        }
225
        
226 80
        return $this->components[$component_name] ?? null;
227
    }
228
229
    /**
230
     * Handle entity components
231
     *
232
     * Since we might need to customize these to have
233
     * custom components loaded as $this->methosd aswell therefore
234
     * we have these placeholder magic methods here
235
     *
236
     * @param string $component_name            
237
     * @param array $args            
238
     */
239 30 View Code Duplication
    public function __call(string $component_name, array $args)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
240
    {
241 30
        if (! method_exists($this, $component_name)) {
242 30
            $this->{$component_name} = Closure::bind(
243 30
                function () use ($component_name) {
244 30
                    return $this->component($component_name);
245 30
                }, $this, get_class());
246
        }
247
        
248 30
        return call_user_func($this->{$component_name}, $args);
249
    }
250
251
    /**
252
     * Create and add DOM element of the entity
253
     *
254
     * @param \DOMDocument $aframe_dom            
255
     * @return \DOMElement
256
     */
257 13
    public function domElement(\DOMDocument &$aframe_dom): DOMElement
258
    {
259 13
        $a_entity = $aframe_dom->createElement('a-entity');
260
        
261 13
        $this->appendAttributes($a_entity);
262
 
263 13
        foreach ($this->components as $component) {
264
            /*
265
             * Check does component has any attributes to add to DOM element.
266
             * default attributes most of cases are ommited so we might not have any attributes to add
267
             */
268 13
            if ($component->hasDOMAttributes())
269 13
                $a_entity->setAttributeNode($component->getDOMAttr());
270
        }
271
        
272 13
        $this->appendChildren($aframe_dom, $a_entity);
273 13
        $this->appendAnimations($aframe_dom, $a_entity);
274 13
        return $a_entity;
275
    }
276
277
    /**
278
     * Append DOM attributes no set by components
279
     *
280
     * @param \DOMElement $a_entity            
281
     */
282 13
    private function appendAttributes(\DOMElement &$a_entity)
283
    {
284 13
        foreach ($this->attrs as $attr => $val) {
285 13
            $this->setAttribute($a_entity, $attr, $val);
286
        }
287 13
    }
288
289 13 View Code Duplication
    private function setAttribute(&$a_entity, $attr, $val)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
290
    {
291 13
        if ($attr === 'id' && ($val === 'untitled' || is_numeric($val)))
292 4
            return;
293
        
294 11
        $a_entity->setAttribute($attr, $val);
295 11
    }
296
297
    /**
298
     * Append childern to entities DOM element
299
     *
300
     * @param \DOMDocument $aframe_dom            
301
     * @param \DOMElement $a_entity            
302
     */
303 13
    private function appendChildren(\DOMDocument &$aframe_dom, \DOMElement &$a_entity)
304
    {
305 13
        if ($this->childrenFactory instanceof EntityChildrenFactory) {
306 2
            foreach ($this->childrenFactory->getChildern() as $child) {
307 2
                $this->addFormatComment($aframe_dom, $a_entity, "\n\t");
308 2
                $a_entity->appendChild($child->domElement($aframe_dom));
309 2
                $this->addFormatComment($aframe_dom, $a_entity, '');
310
            }
311
        }
312 13
    }
313
314
    /**
315
     * Append childern to entities DOM element
316
     *
317
     * @param \DOMDocument $aframe_dom            
318
     * @param \DOMElement $a_entity            
319
     */
320 13
    private function appendAnimations(\DOMDocument &$aframe_dom, \DOMElement &$a_entity)
321
    {
322 13
        foreach ($this->animations as $animations) {
323 1
            $this->addFormatComment($aframe_dom, $a_entity, "\n\t");
324 1
            $a_entity->appendChild($animations->domElement($aframe_dom));
325 1
            $this->addFormatComment($aframe_dom, $a_entity, '');
326
        }
327 13
    }
328
329
    /**
330
     * Add format comment
331
     * 
332
     * @param \DOMDocument $aframe_dom            
333
     * @param \DOMElement $a_entity            
334
     * @param string $content            
335
     */
336 3
    private function addFormatComment(\DOMDocument &$aframe_dom, \DOMElement &$a_entity, string $content)
337
    {
338 3
        if ($aframe_dom->formatOutput) {
339 1
            $com = $aframe_dom->createComment($content);
340 1
            $a_entity->appendChild($com);
341
        }
342 3
    }
343
}
344