Passed
Branch master (8a7ad0)
by Henri
01:23 queued 10s
created

DataTrait::first()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 1
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace HnrAzevedo\Datamanager;
4
5
use Exception;
6
7
trait DataTrait{
8
    use CrudTrait, CheckTrait;
9
10
    protected ?string $table = null;
11
    protected ?string $primary = null;
12
    protected array $data = [];
13
    protected bool $full = false;
14
15
    protected array $result = [];
16
    
17
    
18
    protected ?string $clause = null;
19
20
    protected ?string $order = null;
21
    protected ?string $limit = null;
22
    protected ?int $offset = null;
23
    protected array $excepts = [];
24
    protected int $count = 0;
25
    protected array $select = [];
26
    protected ?string $query = null;
27
28
    
29
30
    public function __set(string $prop,$value)
31
    {
32
33
        if(is_array($value)){
34
            $attr = array_keys($value)[0];
35
            $this->data[$prop][$attr] = $value[$attr];
36
            return $this;
37
        }
38
39
        $this->isSettable($prop);
40
41
        $this->data[$prop]['changed'] = true;
42
        $this->data[$prop]['value'] = $value;
43
        
44
        return $this;
45
    }
46
47
    public function getData(): ?array
48
    {
49
        return $this->data;
50
    }
51
52
    public function __get(string $field)
53
    {
54
        $this->isSettable($field);
55
        return $this->data[$field]['value'];
56
    }
57
58
    public function getCount(): int
59
    {
60
        return $this->count;
61
    }
62
63
    public function except($deniable)
64
    {
65
        $deniable = (is_array($deniable)) ? $deniable : [$deniable];
66
67
        foreach ($deniable as $field) {
68
            if(!array_key_exists($field,$this->data)){
69
                throw new Exception("{$field} field does not exist in the table {$this->table}.");
70
            }
71
72
            $this->excepts[$field] = true;
73
        }
74
75
        return $this;
76
    }
77
78
    public function deny()
79
    {
80
        foreach ($this->excepts as $field => $value) {
81
            unset($this->select[$field]);
82
        }
83
        return $this;
84
    }
85
86
    public function orderBy(string $field, string $ord = 'ASC')
87
    {
88
        $this->isSettable( str_replace(['asc','ASC','desc','DESC',' '],'',$field) );
89
90
        $ord = (strpos(strtolower($field),'asc') || strpos(strtolower($field),'desc')) ? '' : $ord;
91
92
        $this->order = " ORDER BY {$field} {$ord} ";
93
        return $this;
94
    }
95
96
    public function only($params)
97
    {
98
        $params = (is_array($params)) ? $params : [$params];
99
        $this->select = [];
100
101
        foreach ($params as $field) {
102
103
            $this->isSettable($field);
104
105
            $this->select[$field] = true;
106
        }
107
        $this->select[$this->primary] = true;
108
109
        return $this;
110
    }
111
112
    public function where(array $where)
113
    {
114
        $this->where['AND'] = (array_key_exists('AND',$this->where)) ?? '';
0 ignored issues
show
Bug Best Practice introduced by
The property where does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
115
        $w = [];
116
        foreach ($where as $condition => $values) {
117
118
            if(!is_array($values)){
119
                $w['AND'][] = $values;
120
                continue;
121
            }
122
123
            $this->check_where_array($values);
124
125
            $w[(is_int($condition) ? 'AND' : $condition)][] = $values;
126
                       
127
        }
128
129
        $this->where = array_merge($this->where,$w);
130
131
        return $this;
132
    }
133
134
    public function limit(string $limit)
135
    {
136
        $this->limit = $limit;
137
        return $this;
138
    }
139
140
    public function offset(int $offset)
141
    {
142
        $this->checkLimit();
143
144
        $this->offset = $offset;
145
        return $this;
146
    }
147
148
    public function result(): array
149
    {
150
        return $this->result;
151
    }
152
153
    public function first()
154
    {
155
        return  (count($this->result) > 0) ? $this->setByDatabase($this->result[0]) : $this;
156
    }
157
158
    public function setByDatabase(array $arrayValues)
159
    {
160
        $clone = clone $this;
161
        
162
        $clone->result = [
163
            0 => $this->result[0]
164
        ];
165
166
        $clone->count = 1;
167
168
        foreach ($arrayValues as $key => $value) {
169
170
            $this->isSettable($key);
171
172
            $clone->data[$key]['value'] = $value;
173
174
        }
175
        return $clone;
176
    }
177
178
    public function toJson(): string
179
    {
180
        $string = '';
181
        foreach ($this->data as $key => $value) {
182
183
            if(gettype($value)==='object'){
184
                $value = $value->getData()[$this->primary]['value'];
185
            }
186
187
            $string .= '"'.$key.'"'.':"'.$value.'",';
188
        }
189
        return str_replace(',}', '}', '{'.$string.'}');
190
    }
191
192
    public function remove(?bool $exec = false)
193
    {
194
        if(!$exec){
0 ignored issues
show
Bug Best Practice introduced by
The expression $exec of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
195
            $this->clause = 'remove';    
196
            return $this;
197
        }
198
199
        $this->clause = null;
200
201
        if(count($this->where) == 1){
202
            $this->removeById();
203
            return $this;
204
        }
205
206
        $this->delete($this->mountRemove()['where'], substr( $this->mountRemove()['data'] ,0,-1) );
0 ignored issues
show
Bug introduced by
It seems like mountRemove() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

206
        $this->delete($this->/** @scrutinizer ignore-call */ mountRemove()['where'], substr( $this->mountRemove()['data'] ,0,-1) );
Loading history...
207
208
        $this->check_fail();
209
            
210
        return $this;
211
    }
212
213
    private function removeById(): bool
214
    {
215
        $delete = $this->delete("{$this->primary}=:{$this->primary}","{$this->primary}={$this->getData()[$this->primary]['value']}");
216
217
        $this->check_fail();
218
219
        return $delete;
220
    }
221
222
    public function persist()
223
    {
224
        $columns = '';
225
        $values = '';
226
        $data = [];
227
228
        foreach ($this->data as $key => $value) {
229
            if(strstr($this->data[$key]['extra'],'auto_increment')){
230
                continue;
231
            }
232
233
            $this->checkMaxlength($key, $value['value'], $value['maxlength']);
234
235
            $columns .= $key.',';
236
            $values .= ':'.$key.',';
237
            $data[$key] = $value['value'];
238
        }
239
240
        $this->transaction('begin');
241
        try{
242
           
243
            $id = $this->insert($data);
244
245
            $this->check_fail();
246
247
            $this->getData()[$this->primary]['value'] = $id;
248
            
249
            $this->transaction('commit');
250
251
        }catch(Exception $er){
252
            $this->transaction('rollback');
253
            throw $er;
254
        }
255
256
        return $this;
257
    }
258
259
    public function toEntity()
260
    {
261
        if($this->getCount() === 0){
262
            return null;
263
        }
264
265
        $entity = $this->setByDatabase($this->result[0]);
266
267
        if(count($this->result) > 1){
268
            $entity = [];
269
            foreach ($this->result as $key => $value) {
270
                $entity[] = $this->setByDatabase($value);
271
            }
272
        }
273
274
        return $entity;
275
    }
276
277
    public function findById($id)
278
    {
279
        return $this->where([$this->primary,'=',$id]);
280
    }
281
282
    public function execute()
283
    {
284
        if(!is_null($this->clause) && $this->clause == 'remove'){
285
            return $this->remove(true);
286
        }
287
288
        $this->deny();
289
        
290
        $this->mountSelect();
0 ignored issues
show
Bug introduced by
It seems like mountSelect() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

290
        $this->/** @scrutinizer ignore-call */ 
291
               mountSelect();
Loading history...
291
        
292
        $where = substr($this->mountWhereExec()['where'],0,-1);
0 ignored issues
show
Bug introduced by
It seems like mountWhereExec() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

292
        $where = substr($this->/** @scrutinizer ignore-call */ mountWhereExec()['where'],0,-1);
Loading history...
293
        $this->query .= " WHERE {$where} ";
294
295
        $this->query .= $this->order;
296
       
297
        $this->mountLimit();
0 ignored issues
show
Bug introduced by
It seems like mountLimit() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

297
        $this->/** @scrutinizer ignore-call */ 
298
               mountLimit();
Loading history...
298
        $this->mountOffset();
0 ignored issues
show
Bug introduced by
It seems like mountOffset() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

298
        $this->/** @scrutinizer ignore-call */ 
299
               mountOffset();
Loading history...
299
300
        $this->result = $this->select($this->query, $this->mountWhereExec()['data']);
301
302
        $this->check_fail();
303
304
        $this->count = count($this->result);
305
        $this->query = null;
306
307
        return $this;
308
    }
309
310
    public function find(?int $key = null)
311
    {
312
        $this->query = " SELECT * FROM {$this->table} ";
313
        return (is_int($key)) ? $this->findById($key) : $this;
314
    }
315
316
    public function save()
317
    {
318
        $this->transaction('begin');
319
320
        try{
321
            $this->update(
322
                $this->mountSave()['data'],
0 ignored issues
show
Bug introduced by
It seems like mountSave() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

322
                $this->/** @scrutinizer ignore-call */ 
323
                       mountSave()['data'],
Loading history...
323
                "{$this->primary}=:{$this->primary}", 
324
                $this->primary.'='.$this->getData()[$this->primary]['value']
325
            );
326
327
            $this->check_fail();
328
329
            $this->transaction('commit');
330
        }catch(Exception $er){
331
            $this->transaction('rollback');
332
            throw $er;
333
        }
334
335
        return $this;
336
    }
337
338
}