Completed
Push — master ( c7efbc...78a379 )
by James Ekow Abaka
03:44
created

RecordWrapper   C

Complexity

Total Complexity 57

Size/Duplication

Total Lines 311
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 6

Test Coverage

Coverage 94.31%

Importance

Changes 54
Bugs 8 Features 10
Metric Value
wmc 57
c 54
b 8
f 10
lcom 2
cbo 6
dl 0
loc 311
ccs 116
cts 123
cp 0.9431
rs 6.433

39 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 2
A getDescription() 0 10 1
A count() 0 8 2
A retrieveItem() 0 9 3
A createNew() 0 5 1
A __call() 0 9 2
A __callStatic() 0 4 1
A __set() 0 5 1
A __get() 0 4 1
A getTable() 0 4 1
A expandArrayValue() 0 7 2
A toArray() 0 15 4
A save() 0 6 1
A isValid() 0 4 1
A hasMultipleData() 0 8 2
A getData() 0 14 4
A setData() 0 5 1
A mergeData() 0 7 2
A offsetExists() 0 4 1
A offsetGet() 0 8 2
A offsetSet() 0 5 1
A offsetUnset() 0 4 1
A wrap() 0 10 2
A getInvalidFields() 0 4 1
A getHasMany() 0 4 1
A getBelongsTo() 0 4 1
A current() 0 4 1
A key() 0 4 1
A next() 0 4 1
A rewind() 0 4 1
A valid() 0 4 1
A fetchRelatedFields() 0 14 3
A getRelationships() 0 8 1
A usetField() 0 4 1
A preSaveCallback() 0 4 1
A postSaveCallback() 0 4 1
A preUpdateCallback() 0 4 1
A postUpdateCallback() 0 4 1
A getBehaviours() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like RecordWrapper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use RecordWrapper, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * The MIT License
4
 *
5
 * Copyright 2015 ekow.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
 * THE SOFTWARE.
24
 */
25
26
namespace ntentan\nibii;
27
28
use ntentan\utils\Utils;
29
use ntentan\kaikai\Cache;
30
use ntentan\panie\InjectionContainer;
31
32
class RecordWrapper implements \ArrayAccess, \Countable, \Iterator
33
{
34
    use \ntentan\panie\ComponentContainerTrait;
35
    
36
    protected $hasMany = [];
37
    protected $belongsTo = [];
38
    protected $manyHaveMany = [];
39
    protected $behaviours = [];
40
    protected $table;
41
    private $modelData = [];
42
    private $invalidFields;
43
    private $dynamicOperations;
44
    private $index = 0;
45
    private $dataSet = false;
46
    protected $adapter;
47
48 36
    public function __construct(DriverAdapter $adapter)
49
    {
50 36
        $this->table = Nibii::getModelTable($this);
51 36
        $this->adapter = $adapter;
52 36
        foreach($this->behaviours as $behaviour) {
53
            $behaviourInstance = $this->getComponentInstance($behaviour);
54
            $behaviourInstance->setModel($this);
55
        }
56 36
    }
57
58
    /**
59
     * 
60
     * @return ModelDescription
61
     */
62 28
    public function getDescription()
63
    {
64 28
        return Cache::read(
65 28
            (new \ReflectionClass($this))->getName() . '::desc',
66 28
            function() 
67
            {
68 28
                return new ModelDescription($this);
69 28
            }
70
        );
71
    }
72
    
73 10
    public function count()
74
    {
75 10
        if ($this->dataSet) {
76 10
            return count($this->getData());
77
        } else {
78
            return $this->__call('count', []);
0 ignored issues
show
Documentation introduced by
'count' is of type string, but the function expects a object<ntentan\nibii\type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
array() is of type array, but the function expects a object<ntentan\nibii\type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
79
        }
80
    }
81
82 12
    private function retrieveItem($key)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
83
    {
84 12
        $relationships = $this->getDescription()->getRelationships();
85 12
        if(isset($relationships[$key])) {
86 8
            return $this->fetchRelatedFields($relationships[$key]);
87
        } else {
88 4
            return isset($this->modelData[$key]) ? $this->modelData[$key] : null;
89
        }
90
    }
91
92
    /**
93
     * Create a new instance of this Model
94
     * @return \ntentan\nibii\RecordWrapper
95
     */
96 34
    public static function createNew()
97
    {
98 34
        $class = get_called_class();
99 34
        return InjectionContainer::resolve($class);
100
    }
101
102
    /**
103
     * @method
104
     * @param type $name
105
     * @param type $arguments
106
     * @return type
107
     */
108 34
    public function __call($name, $arguments)
109
    {
110 34
        if($this->dynamicOperations === null) {
111 34
            $this->dynamicOperations = new Operations(
112 34
                $this, InjectionContainer::singleton(DriverAdapter::class)
113
            );
114
        }
115 34
        return $this->dynamicOperations->perform($name, $arguments);
116
    }
117
118 26
    public static function __callStatic($name, $arguments)
119
    {
120 26
        return call_user_func_array([self::createNew(), $name], $arguments);
121
    }
122
123 8
    public function __set($name, $value)
124
    {
125 8
        $this->dataSet = true;
126 8
        $this->modelData[$name] = $value;
127 8
    }
128
129 12
    public function __get($name)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
130
    {
131 12
        return $this->retrieveItem($name);
132
    }
133
134 36
    public function getTable()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
135
    {
136 36
        return $this->table;
137
    }
138
    
139 4
    private function expandArrayValue($array, $relationships, $depth, $index = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
140
    {
141 4
        foreach($relationships as $name => $relationship) {
142 4
            $array[$name] = $this->fetchRelatedFields($relationship, $index)->toArray($depth);
143
        }
144 4
        return $array;
145
    }
146
147 16
    public function toArray($depth = 0)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
148
    {
149 16
        $relationships = $this->getDescription()->getRelationships();
150 16
        $array = $this->modelData;
151 16
        if($depth > 0) {
152 4
            if($this->hasMultipleData()) {
153
                foreach($array as $i => $value) {
154
                    $array[$i] = $this->expandArrayValue($value, $relationships, $depth - 1, $i);
155
                }
156
            } else {
157 4
                $array = $this->expandArrayValue($array, $relationships, $depth - 1);
158
            }
159
        }
160 16
        return $array;
161
    }
162
    
163 10
    public function save()
164
    {
165 10
        $return = $this->__call('save', [$this->hasMultipleData()]);
0 ignored issues
show
Documentation introduced by
'save' is of type string, but the function expects a object<ntentan\nibii\type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
array($this->hasMultipleData()) is of type array<integer,boolean,{"0":"boolean"}>, but the function expects a object<ntentan\nibii\type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
166 10
        $this->invalidFields = $this->dynamicOperations->getInvalidFields();
167 10
        return $return;
168
    }
169
    
170
    public function isValid()
171
    {
172
        return $this->__call('isValid', []);
0 ignored issues
show
Documentation introduced by
'isValid' is of type string, but the function expects a object<ntentan\nibii\type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
array() is of type array, but the function expects a object<ntentan\nibii\type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
173
    }
174
175 18
    private function hasMultipleData()
176
    {
177 18
        if(count($this->modelData) > 0) {
178 16
            return is_numeric(array_keys($this->modelData)[0]);
179
        } else {
180 2
            return false;
181
        }
182
    }
183
184 14
    public function getData()
185
    {
186 14
        $data = [];
187
                
188 14
        if(count($this->modelData) == 0) {
189 6
            $data = $this->modelData;
190 12
        } else if($this->hasMultipleData()) {
191 2
            $data = $this->modelData;
192 12
        } else if(count($this->modelData) > 0) {
193 12
            $data[] = $this->modelData;
194
        }
195
        
196 14
        return $data;
197
    }
198
199 26
    public function setData($data)
200
    {
201 26
        $this->dataSet = true;
202 26
        $this->modelData = $data;
203 26
    }
204
    
205
    public function mergeData($data)
206
    {
207
        foreach($data as $key => $value) {
208
            $this->modelData[$key] = $value;
209
        }
210
        $this->dataSet = true;
211
    }
212
213 2
    public function offsetExists($offset)
214
    {
215 2
        return isset($this->modelData[$offset]);
216
    }
217
218 2
    public function offsetGet($offset)
219
    {
220 2
        if (is_numeric($offset)) {
221 2
            return $this->wrap($offset);
222
        } else {
223 2
            return $this->retrieveItem($offset);
224
        }
225
    }
226
227 2
    public function offsetSet($offset, $value)
228
    {
229 2
        $this->dataSet = true;
230 2
        $this->modelData[$offset] = $value;
231 2
    }
232
233
    public function offsetUnset($offset)
234
    {
235
        unset($this->modelData[$offset]);
236
    }
237
238 6
    private function wrap($offset)
239
    {
240 6
        if(isset($this->modelData[$offset])) {
241 6
            $newInstance = $this->createNew();
242 6
            $newInstance->setData($this->modelData[$offset]);
243 6
            return $newInstance;
244
        } else {
245
            return null;
246
        }
247
    }
248
249 4
    public function getInvalidFields()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
250
    {
251 4
        return $this->invalidFields;
252
    }
253
254
    public function getHasMany()
255
    {
256
        return $this->hasMany;
257
    }
258
259
    public function getBelongsTo()
260
    {
261
        return $this->belongsTo;
262
    }
263
264 4
    public function current()
265
    {
266 4
        return $this->wrap($this->index);
267
    }
268
269
    public function key()
270
    {
271
        return $this->index;
272
    }
273
274 4
    public function next()
275
    {
276 4
        $this->index++;
277 4
    }
278
279 4
    public function rewind()
280
    {
281 4
        $this->index = 0;
282 4
    }
283
284 4
    public function valid()
285
    {
286 4
        return isset($this->modelData[$this->index]);
287
    }
288
289 12
    private function fetchRelatedFields($relationship, $index = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
290
    {
291 12
        if($index === null) {
292 12
            $data = $this->modelData;
293
        } else {
294
            $data = $this->modelData[$index];
295
        }
296 12
        $model = $relationship->getModelInstance();
297 12
        if(empty($data)) {
298
            return $model;
299
        } else {
300 12
            return $model->fetch($relationship->getQuery($data));
301
        }
302
    }
303
304 28
    public function getRelationships()
305
    {
306
        return [
307 28
            'HasMany' => $this->hasMany,
308 28
            'BelongsTo' => $this->belongsTo,
309 28
            'ManyHaveMany' => $this->manyHaveMany
310
        ];
311
    }
312
    
313
    public function usetField($field)
314
    {
315
        unset($this->modelData[$field]);
316
    }
317
    
318 8
    public function preSaveCallback()
319
    {
320
        
321 8
    }
322
    
323 4
    public function postSaveCallback($id)
0 ignored issues
show
Unused Code introduced by
The parameter $id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
324
    {
325
        
326 4
    }
327
    
328 2
    public function preUpdateCallback()
329
    {
330
        
331 2
    }
332
    
333 2
    public function postUpdateCallback()
334
    {
335
        
336 2
    }
337
    
338 10
    public function getBehaviours()
339
    {
340 10
        return $this->loadedComponents;
341
    }
342
}
343