Completed
Push — master ( 2b9193...abd76f )
by James Ekow Abaka
03:07
created

RecordWrapper::__construct()   B

Complexity

Conditions 5
Paths 10

Size

Total Lines 19
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5.0488

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 8.8571
c 0
b 0
f 0
ccs 14
cts 16
cp 0.875
cc 5
eloc 16
nc 10
nop 1
crap 5.0488
1
<?php
2
3
/*
4
 * The MIT License
5
 *
6
 * Copyright 2015 ekow.
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated documentation files (the "Software"), to deal
10
 * in the Software without restriction, including without limitation the rights
11
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
 * copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
 * THE SOFTWARE.
25
 */
26
27
namespace ntentan\nibii;
28
29
use ntentan\utils\Utils;
30
use ntentan\kaikai\Cache;
31
use ntentan\panie\InjectionContainer;
32
use ntentan\utils\Text;
33
use ntentan\atiaa\Db;
34
35
/**
36
 * 
37
 */
38
class RecordWrapper implements \ArrayAccess, \Countable, \Iterator {
39
40
    use \ntentan\panie\ComponentContainerTrait;
41
42
    protected $hasMany = [];
43
    protected $belongsTo = [];
44
    protected $manyHaveMany = [];
45
    protected $behaviours = [];
46
    protected $table;
47
    protected $schema;
48
    private $quotedTable;
49
    private $unquotedTable;
50
    private $modelData = [];
51
    private $invalidFields;
52
    private $dynamicOperations;
53
    private $index = 0;
54
    private $dataSet = false;
55
    protected $adapter;
56
57 38
    public function __construct(DriverAdapter $adapter) {
58 38
        $table = Nibii::getModelTable($this);
59 38
        $driver = Db::getDriver();
60 38
        if(is_string($table)) {
61 36
            $this->quotedTable = $driver->quoteIdentifier($table);
62 36
            $this->table = $this->unquotedTable = $table;
63
        } else {
64 2
            $this->quotedTable = (isset($table['schema']) ? "{$driver->quoteIdentifier($table["schema"])}." : ""). $driver->quoteIdentifier($table["table"]);
65 2
            $this->unquotedTable = (isset($table['schema']) ? "{$table['schema']}." : "") . $table['table'];
66 2
            $this->table = $table['table'];
67 2
            $this->schema = $table['schema'];
68
        }
69 38
        $this->adapter = $adapter;
70 38
        $this->adapter->setModel($this, $this->quotedTable);
0 ignored issues
show
Unused Code introduced by
The call to DriverAdapter::setModel() has too many arguments starting with $this->quotedTable.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
71 38
        foreach ($this->behaviours as $behaviour) {
72
            $behaviourInstance = $this->getComponentInstance($behaviour);
73
            $behaviourInstance->setModel($this);
74
        }
75 38
    }
76
77
    /**
78
     * 
79
     * @return ModelDescription
80
     */
81 28
    public function getDescription() {
82 28
        return Cache::read(
83 28
            (new \ReflectionClass($this))->getName() . '::desc', function() {
84 28
                return new ModelDescription($this);
85 28
            }
86
        );
87
    }
88
89 10
    public function count() {
90 10
        if ($this->dataSet) {
91 10
            return count($this->getData());
92
        } else {
93
            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...
94
        }
95
    }
96
97
    /**
98
     * Retrieve an item stored in the record.
99
     * This method returns items that are directly stored in the model or lazy
100
     * loads related items. The key could be a field in the model's table or
101
     * the name of a related model.
102
     * @param string $key A key identifying the item to be retrieved.
103
     * @return mixed
104
     */
105 12
    private function retrieveItem($key) {
106 12
        $relationships = $this->getDescription()->getRelationships();
107 12
        $decamelizedKey = Text::deCamelize($key);
108 12
        if (isset($relationships[$key])) {
109 8
            return $this->fetchRelatedFields($relationships[$key]);
110
        }
111 4
        return isset($this->modelData[$decamelizedKey]) ? $this->modelData[$decamelizedKey] : null;
112
    }
113
114
    /**
115
     * Create a new instance of this Model
116
     * @return \ntentan\nibii\RecordWrapper
117
     */
118 36
    public static function createNew() {
119 36
        $class = get_called_class();
120 36
        return InjectionContainer::resolve($class);
121
    }
122
123
    /**
124
     * @method
125
     * @param type $name
126
     * @param type $arguments
127
     * @return type
128
     */
129 36
    public function __call($name, $arguments) {
130 36
        if ($this->dynamicOperations === null) {
131 36
            $this->dynamicOperations = new Operations(
132 36
                $this, $this->adapter, $this->quotedTable
133
            );
134
        }
135 36
        return $this->dynamicOperations->perform($name, $arguments);
136
    }
137
138 28
    public static function __callStatic($name, $arguments) {
139 28
        return call_user_func_array([self::createNew(), $name], $arguments);
140
    }
141
142 8
    public function __set($name, $value) {
143 8
        $this->dataSet = true;
144 8
        $this->modelData[Text::deCamelize($name)] = $value;
145 8
    }
146
147 12
    public function __get($name) {
148 12
        return $this->retrieveItem($name);
149
    }
150
151 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...
152 4
        foreach ($relationships as $name => $relationship) {
153 4
            $array[$name] = $this->fetchRelatedFields($relationship, $index)->toArray($depth);
154
        }
155 4
        return $array;
156
    }
157
158 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...
159 16
        $relationships = $this->getDescription()->getRelationships();
160 16
        $array = $this->modelData;
161 16
        if ($depth > 0) {
162 4
            if ($this->hasMultipleData()) {
163
                foreach ($array as $i => $value) {
164
                    $array[$i] = $this->expandArrayValue($value, $relationships, $depth - 1, $i);
165
                }
166
            } else {
167 4
                $array = $this->expandArrayValue($array, $relationships, $depth - 1);
168
            }
169
        }
170 16
        return $array;
171
    }
172
173 10
    public function save() {
174 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...
175 10
        $this->invalidFields = $this->dynamicOperations->getInvalidFields();
176 10
        return $return;
177
    }
178
179 18
    private function hasMultipleData() {
180 18
        if (count($this->modelData) > 0) {
181 16
            return is_numeric(array_keys($this->modelData)[0]);
182
        } else {
183 2
            return false;
184
        }
185
    }
186
187 14
    public function getData() {
188 14
        $data = [];
189
190 14
        if (count($this->modelData) == 0) {
191 6
            $data = $this->modelData;
192 12
        } else if ($this->hasMultipleData()) {
193 2
            $data = $this->modelData;
194 12
        } else if (count($this->modelData) > 0) {
195 12
            $data[] = $this->modelData;
196
        }
197
198 14
        return $data;
199
    }
200
201 26
    public function setData($data) {
202 26
        $this->dataSet = true;
203 26
        $this->modelData = $data;
204 26
    }
205
206
    public function mergeData($data) {
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 2
        return isset($this->modelData[$offset]);
215
    }
216
217 2
    public function offsetGet($offset) {
218 2
        if (is_numeric($offset)) {
219 2
            return $this->wrap($offset);
220
        } else {
221 2
            return $this->retrieveItem($offset);
222
        }
223
    }
224
225 2
    public function offsetSet($offset, $value) {
226 2
        $this->dataSet = true;
227 2
        $this->modelData[$offset] = $value;
228 2
    }
229
230
    public function offsetUnset($offset) {
231
        unset($this->modelData[$offset]);
232
    }
233
234 6
    private function wrap($offset) {
235 6
        if (isset($this->modelData[$offset])) {
236 6
            $newInstance = $this->createNew();
237 6
            $newInstance->setData($this->modelData[$offset]);
238 6
            return $newInstance;
239
        } else {
240
            return null;
241
        }
242
    }
243
244 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...
245 4
        return $this->invalidFields;
246
    }
247
248
    public function getHasMany() {
249
        return $this->hasMany;
250
    }
251
252
    public function getBelongsTo() {
253
        return $this->belongsTo;
254
    }
255
256 4
    public function current() {
257 4
        return $this->wrap($this->index);
258
    }
259
260
    public function key() {
261
        return $this->index;
262
    }
263
264 4
    public function next() {
265 4
        $this->index++;
266 4
    }
267
268 4
    public function rewind() {
269 4
        $this->index = 0;
270 4
    }
271
272 4
    public function valid() {
273 4
        return isset($this->modelData[$this->index]);
274
    }
275
276 6
    public function onValidate() {
277 6
        return true;
278
    }
279
280 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...
281 12
        if ($index === null) {
282 12
            $data = $this->modelData;
283
        } else {
284
            $data = $this->modelData[$index];
285
        }
286 12
        $model = $relationship->getModelInstance();
287 12
        if (empty($data)) {
288
            return $model;
289
        } else {
290 12
            return $model->fetch($relationship->getQuery($data));
291
        }
292
    }
293
294 28
    public function getRelationships() {
295
        return [
296 28
            'HasMany' => $this->hasMany,
297 28
            'BelongsTo' => $this->belongsTo,
298 28
            'ManyHaveMany' => $this->manyHaveMany
299
        ];
300
    }
301
302
    public function usetField($field) {
303
        unset($this->modelData[$field]);
304
    }
305
306 8
    public function preSaveCallback() {
307
        
308 8
    }
309
310 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...
311
        
312 4
    }
313
314 2
    public function preUpdateCallback() {
315
        
316 2
    }
317
318 2
    public function postUpdateCallback() {
319
        
320 2
    }
321
322 10
    public function getBehaviours() {
323 10
        return $this->loadedComponents;
324
    }
325
    
326 38
    public function getDBStoreInformation() {
327
        return [
328 38
            'schema' => $this->schema,
329 38
            'table' => $this->table,
330 38
            'quoted_table' => $this->quotedTable,
331 38
            'unquoted_table' => $this->unquotedTable
332
        ];
333
    }
334
335
}
336