DataLayer   A
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 393
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 112
c 3
b 0
f 0
dl 0
loc 393
rs 9.28
wmc 39

22 Methods

Rating   Name   Duplication   Size   Complexity  
A fail() 0 3 1
A __isset() 0 3 1
A count() 0 11 2
A findById() 0 3 1
A functionSql() 0 4 1
A __get() 0 13 3
A findByPrimaryKey() 0 3 1
A find() 0 10 2
A __construct() 0 13 1
A order() 0 4 1
A data() 0 3 1
A limit() 0 4 1
A destroy() 0 10 2
A change() 0 4 1
A toCamelCase() 0 5 1
A save() 0 31 5
A __set() 0 7 2
A group() 0 4 1
A offset() 0 4 1
A make() 0 4 1
A fetch() 0 19 4
A required() 0 15 5
1
<?php
2
3
namespace Stonks\DataLayer;
4
5
use Exception;
6
use PDO;
7
use PDOException;
8
use stdClass;
9
10
/**
11
 * Class DataLayer
12
 *
13
 * @package Stonks\DataLayer
14
 */
15
class DataLayer
16
{
17
18
    use CrudTrait;
19
20
    /**
21
     * @var string
22
     */
23
    private $entity;
24
25
    /**
26
     * @var array|null
27
     */
28
    private $required;
29
30
    /**
31
     * @var string
32
     */
33
    private $primary;
34
35
    /**
36
     * @var bool|string
37
     */
38
    private $timestamps;
39
40
    /**
41
     * @var string|null
42
     */
43
    private $database;
44
45
    /**
46
     * @var string|null
47
     */
48
    private $statement;
49
50
    /**
51
     * @var array|null
52
     */
53
    private $params;
54
55
    /**
56
     * @var string|null
57
     */
58
    private $group;
59
60
    /**
61
     * @var string|null
62
     */
63
    private $order;
64
65
    /**
66
     * @var string|null
67
     */
68
    private $limit;
69
70
    /**
71
     * @var string|null
72
     */
73
    private $offset;
74
75
    /**
76
     * @var string|null
77
     */
78
    private $saveMethod;
79
80
    /**
81
     * @var array|null
82
     */
83
    private $functionSql;
84
85
    /**
86
     * @var Exception|PDOException|null
87
     */
88
    private $fail;
89
90
    /**
91
     * @var object|null
92
     */
93
    private $data;
94
95
    /**
96
     * DataLayer constructor.
97
     *
98
     * @param string $entity
99
     * @param array|null $required
100
     * @param string $primary
101
     * @param bool|string $timestamps
102
     * @param string|null $database
103
     */
104
    public function __construct(
105
        string $entity,
106
        ?array $required = [],
107
        string $primary = 'id',
108
        $timestamps = false,
109
        ?string $database = null
110
    ) {
111
        $this->entity = $entity;
112
        $this->required = $required;
113
        $this->primary = $primary;
114
        $this->timestamps = $timestamps;
115
        $this->database = $database;
116
        $this->functionSql = [];
117
    }
118
119
    /**
120
     * @param $name
121
     * @param $value
122
     * @return void
123
     */
124
    public function __set($name, $value): void
125
    {
126
        if (empty($this->data)) {
127
            $this->data = new stdClass();
128
        }
129
130
        $this->data->$name = $value;
131
    }
132
133
    /**
134
     * @param $name
135
     * @return bool
136
     */
137
    public function __isset($name): bool
138
    {
139
        return isset($this->data->$name);
140
    }
141
142
    /**
143
     * @param $name
144
     * @return string|null
145
     */
146
    public function __get($name): ?string
147
    {
148
        $method = $this->toCamelCase($name);
149
150
        if (method_exists($this, $method)) {
151
            return $this->$method();
152
        }
153
154
        if (method_exists($this, $name)) {
155
            return $this->$name();
156
        }
157
158
        return ($this->data->$name ?? null);
159
    }
160
161
    /**
162
     * @return Exception|PDOException|null
163
     */
164
    public function fail()
165
    {
166
        return $this->fail;
167
    }
168
169
    /**
170
     * @return object|null
171
     */
172
    public function data(): ?object
173
    {
174
        return $this->data;
175
    }
176
177
    /**
178
     * @param string|null $terms
179
     * @param string|null $params
180
     * @param string $columns
181
     * @return DataLayer
182
     */
183
    public function find(?string $terms = '', ?string $params = '', string $columns = '*'): DataLayer
184
    {
185
        if ($terms) {
186
            $this->statement = "SELECT {$columns} FROM {$this->entity} WHERE {$terms}";
187
            parse_str($params, $this->params);
0 ignored issues
show
Bug introduced by
It seems like $params can also be of type null; however, parameter $string of parse_str() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

187
            parse_str(/** @scrutinizer ignore-type */ $params, $this->params);
Loading history...
188
            return $this;
189
        }
190
191
        $this->statement = "SELECT {$columns} FROM {$this->entity}";
192
        return $this;
193
    }
194
195
    /**
196
     * @param string $value
197
     * @param string $columns
198
     * @return DataLayer|null
199
     */
200
    public function findByPrimaryKey(string $value, string $columns = '*'): ?DataLayer
201
    {
202
        return $this->find("{$this->primary} = :{$this->primary}", "{$this->primary}={$value}", $columns)->fetch();
203
    }
204
205
    /**
206
     * @param string $id
207
     * @param string $columns
208
     * @return DataLayer|null
209
     */
210
    public function findById(string $id, string $columns = '*'): ?DataLayer
211
    {
212
        return $this->find('id = :id', "id={$id}", $columns)->fetch();
213
    }
214
215
    /**
216
     * @param string $group
217
     * @return $this|null
218
     */
219
    public function group(string $group): ?DataLayer
220
    {
221
        $this->group = " GROUP BY {$group}";
222
        return $this;
223
    }
224
225
    /**
226
     * @param string $order
227
     * @return $this|null
228
     */
229
    public function order(string $order): ?DataLayer
230
    {
231
        $this->order = " ORDER BY {$order}";
232
        return $this;
233
    }
234
235
    /**
236
     * @param int $limit
237
     * @return $this|null
238
     */
239
    public function limit(int $limit): ?DataLayer
240
    {
241
        $this->limit = " LIMIT {$limit}";
242
        return $this;
243
    }
244
245
    /**
246
     * @param int $offset
247
     * @return $this|null
248
     */
249
    public function offset(int $offset): ?DataLayer
250
    {
251
        $this->offset = " OFFSET {$offset}";
252
        return $this;
253
    }
254
255
    /**
256
     * @param bool $all
257
     * @return DataLayer|mixed|null
258
     */
259
    public function fetch(bool $all = false)
260
    {
261
        try {
262
            $connect = Connect::testConnection($this->database);
263
            $statement = $connect->prepare($this->statement . $this->group . $this->order . $this->limit . $this->offset);
264
            $statement->execute($this->params);
265
266
            if (!$statement->rowCount()) {
267
                return null;
268
            }
269
270
            if ($all) {
271
                return $statement->fetchAll(PDO::FETCH_CLASS, static::class);
272
            }
273
274
            return $statement->fetchObject(static::class);
275
        } catch (PDOException $exception) {
276
            $this->fail = $exception;
277
            return null;
278
        }
279
    }
280
281
    /**
282
     * @return int|null
283
     */
284
    public function count(): ?int
285
    {
286
        try {
287
            $connect = Connect::testConnection($this->database);
288
            $statement = $connect->prepare($this->statement);
289
            $statement->execute($this->params);
290
291
            return $statement->rowCount();
292
        } catch (PDOException $exception) {
293
            $this->fail = $exception;
294
            return null;
295
        }
296
    }
297
298
    /**
299
     * @param string $column
300
     * @param string $function
301
     * @return void
302
     */
303
    public function functionSql(string $column, string $function): void
304
    {
305
        $this->functionSql[$column] = $function;
306
        $this->$column = $function;
307
    }
308
309
    /**
310
     * @return $this|null
311
     */
312
    public function make(): ?DataLayer
313
    {
314
        $this->saveMethod = 'create';
315
        return $this;
316
    }
317
318
    /**
319
     * @return $this|null
320
     */
321
    public function change(): ?DataLayer
322
    {
323
        $this->saveMethod = 'update';
324
        return $this;
325
    }
326
327
    /**
328
     * @return bool
329
     */
330
    public function save(): bool
331
    {
332
        $primary = $this->primary;
333
        $value = null;
334
335
        try {
336
            if (!$this->required()) {
337
                throw new Exception('Preencha os campos necessários');
338
            }
339
340
            if ($this->saveMethod === 'update') {
341
                $value = $this->data->$primary;
342
                $data = (array) $this->data;
343
344
                unset($data[$primary]);
345
346
                $this->update($data, "{$primary} = :{$primary}", "{$primary}={$value}");
347
            } else {
348
                $value = $this->create((array) $this->data);
349
            }
350
351
            if (!$value) {
352
                return false;
353
            }
354
355
            $this->data = $this->findByPrimaryKey($value)->data();
356
357
            return true;
358
        } catch (Exception $exception) {
359
            $this->fail = $exception;
360
            return false;
361
        }
362
    }
363
364
    /**
365
     * @return bool
366
     */
367
    public function destroy(): bool
368
    {
369
        $primary = $this->primary;
370
        $value = $this->data->$primary;
371
372
        if (empty($value)) {
373
            return false;
374
        }
375
376
        return $this->delete("{$primary} = :{$primary}", "{$primary}={$value}");
377
    }
378
379
    /**
380
     * @return bool
381
     */
382
    private function required(): bool
383
    {
384
        $data = (array) $this->data;
385
386
        foreach ($this->required as $field) {
387
            if (
388
                !isset($data[$field])
389
                || is_string($data[$field])
390
                && $data[$field] == ''
391
            ) {
392
                return false;
393
            }
394
        }
395
396
        return true;
397
    }
398
399
    /**
400
     * @param string $string
401
     * @return string
402
     */
403
    private function toCamelCase(string $string): string
404
    {
405
        $camelCase = str_replace(' ', '', ucwords(str_replace('_', ' ', $string)));
406
        $camelCase[0] = strtolower($camelCase[0]);
407
        return $camelCase;
408
    }
409
}
410