Completed
Push — dev-master ( e1a6ef...11f3cc )
by Vijay
03:14
created

Mapper::__construct()   C

Complexity

Conditions 8
Paths 4

Size

Total Lines 78
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 48
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 78
rs 6.102

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace FFCMS\Mappers;
4
5
use FFMVC\Helpers;
6
use FFCMS\Traits;
7
use FFCMS\Models;
8
9
/**
10
 * Base Database Mapper Class extends f3's DB\SQL\Mapper
11
 *
12
 * @author Vijay Mahrra <[email protected]>
13
 * @copyright (c) Copyright 2016 Vijay Mahrra
14
 * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html)
15
 * @link https://fatfreeframework.com/sql-mapper
16
 * @link https://github.com/Wixel/GUMP
17
 */
18
19
// abstract class Magic implements ArrayAccess
20
// abstract class Cursor extends \Magic implements \IteratorAggregate
21
// class Mapper extends \DB\Cursor
22
/**
23
 * @property string $key
24
 * @property string $value
25
 * @property string $created
26
 */
27
abstract class Mapper extends \DB\SQL\Mapper
28
{
29
    use Traits\Validation;
30
31
    /**
32
     * Fields and their visibility to clients, boolean or string of visible field name
33
     *
34
     * @var array $fieldsVisible
35
     */
36
    protected $fieldsVisible = [];
37
38
    /**
39
     * Fields that are editable to clients, boolean or string of visible field name
40
     *
41
     * @var array $fieldsEditable
42
     */
43
    protected $fieldsEditable = [];
44
45
    /**
46
     * @var object database class
47
     */
48
    protected $db;
49
50
    /**
51
     * @var string $table for the mapper - this string gets automatically quoted
52
     */
53
    protected $table;
54
55
    /**
56
     * @var string $mapperName name for the mapper
57
     */
58
    protected $mapperName;
59
60
    /**
61
     * @var string $uuid the fieldname used for the uuid
62
     */
63
    protected $uuidField = 'uuid';
64
65
    /**
66
     * @var boolean $valid the data after validation is valid?
67
     */
68
    protected $valid = null;
69
70
    /**
71
     * @var array $originalData the original data when object created/loaded
72
     */
73
    protected $originalData = [];
74
75
    /**
76
     * @var array $auditData data to write to audit log
77
     */
78
    protected $auditData = [];
79
80
    /**
81
     * initialize with array of params
82
     *
83
     */
84
    public function __construct(array $params = [])
85
    {
86
        $f3 = \Base::instance();
87
88
        $this->db = \Registry::get('db');
89
90
        // guess the table name from the class name if not specified as a class member
91
        $class = strrchr(get_class($this), '\\');
92
        $class = \UTF::instance()->substr($class,1);
93
        if (empty($this->table)) {
94
            $table = $f3->snakecase($class);
95
        } else {
96
            $table = $this->table;
97
        }
98
        $this->table = $table; // this gets quoted
99
        $this->mapperName = $table; // this doesn't
100
101
        parent::__construct($this->db, $table);
102
103
        foreach ($params as $k => $v) {
104
            $this->$k = $v;
105
        }
106
107
        // save default validation rules and filter rules in-case we add rules
108
        $this->validationRulesDefault = $this->validationRules;
109
        $this->filterRulesDefault = $this->filterRules;
110
111
        // set original data when object loaded
112
        $this->onload(function($mapper){
113
            $mapper->originalData = $mapper->cast();
114
        });
115
116
        // filter data, set UUID and date created before insert
117
        $this->beforeinsert(function($mapper){
118
            $mapper->setUUID($mapper->uuidField);
119
            $mapper->copyFrom($mapper->filter());
120
            if (in_array('created', $mapper->fields()) && empty($mapper->created)) {
121
                $mapper->created = Helpers\Time::database();
122
            }
123
            return $mapper->validate();
124
        });
125
126
        // filter data, set updated field if present before update
127
        $this->beforeupdate(function($mapper){
128
            $mapper->copyFrom($mapper->filter());
129
            return $mapper->validate();
130
        });
131
132
        // write audit data after save
133
        $this->aftersave(function($mapper){
134
            if ('audit' == $mapper->mapperName) {
135
                return;
136
            }
137
            $data = array_merge([
138
                'event' => (empty($mapper->originalData) ? 'created-'  : 'updated-') . $mapper->mapperName,
139
                'old' => $mapper->originalData,
140
                'new' => $mapper->cast()
141
            ], $this->auditData);
142
            Models\Audit::instance()->write($data);
143
            $mapper->originalData = $data['new'];
144
            $mapper->auditData = [];
145
        });
146
147
        // write audit data after erase
148
        $this->aftererase(function($mapper){
149
            if ('audit' == $mapper->mapperName) {
150
                return;
151
            }
152
            $data = array_merge([
153
                'event' => 'deleted-' . $mapper->mapperName,
154
                'old' => $mapper->originalData,
155
                'new' => $mapper->cast()
156
            ], $this->auditData);
157
            Models\Audit::instance()->write($data);
158
            $mapper->originalData = $mapper->auditData = [];
159
        });
160
161
    }
162
163
164
    /**
165
     * return string representation of class - json of data
166
     *
167
     * @param string
168
     */
169
    public function __toString(): string
170
    {
171
        return json_encode($this->cast(), JSON_PRETTY_PRINT);
172
    }
173
174
175
    /**
176
     * return array representation of class - json of data
177
     *
178
     * @param array
179
     */
180
    public function __toArray(): array
181
    {
182
        return $this->cast();
183
    }
184
185
    /**
186
     * Cast the mapper data to an array using only provided fields
187
     *
188
     * @param mixed string|array fields to return in response
189
     * @param array optional data optional data to use instead of fields
190
     * @return array $data
191
     */
192
    public function castFields($fields = null, array $data = []): array
193
    {
194 View Code Duplication
        if (!empty($fields)) {
195
            if (is_string($fields)) {
196
                $fields = preg_split("/[\s,]+/", strtolower($fields));
197
            } else if (!is_array($fields)) {
198
                $fields = [];
199
            }
200
        }
201
202
        if (empty($data) || !is_array($data)) {
203
            $data = $this->cast();
204
        }
205
206
        if (empty($fields)) {
207
            $fields = array_keys($data);
208
        }
209
210
        // remove fields not in the list
211
        foreach ($data as $k => $v) {
212
            if (!in_array($k, $fields)) {
213
                unset($data[$k]);
214
            }
215
        }
216
217
        $data['object'] = $this->table;
218
219
        return $data;
220
    }
221
222
    /**
223
     * Cast the mapper data to an array and modify (for external clients typically)
224
     * using the visible fields and names for export, converting dates to unixtime
225
     * optionally pass in a comma (or space)-separated list of fields or an array of fields
226
     *
227
     * @param mixed string|array fields to return in response
228
     * @param array optional data optional data to use instead of fields
229
     * @return array $data
230
     */
231
    public function exportArray($fields = null, array $data = []): array
232
    {
233 View Code Duplication
        if (!empty($fields)) {
234
            if (is_string($fields)) {
235
                $fields = preg_split("/[\s,]+/", strtolower($fields));
236
            } else if (!is_array($fields)) {
237
                $fields = [];
238
            }
239
        }
240
241
        if (empty($data) || !is_array($data)) {
242
            $data = $this->cast();
243
        }
244
245
        foreach ($data as $k => $v) {
246
            if (empty($this->fieldsVisible[$k])) {
247
                unset($data[$k]);
248
                continue;
249
            } elseif (true !== $this->fieldsVisible[$k]) {
250
                unset($data[$k]);
251
                $k = $this->fieldsVisible[$k];
252
                $data[$k] = $v;
253
            }
254
            // convert date to unix timestamp
255
            if ('updated' == $k || 'created' == $k || (
256
                strlen($v) == 19 && preg_match("/^[\d]{4}-[\d]{2}-[\d]{2}[\s]+[\d]{2}:[\d]{2}:[\d]{2}/", $v, $m))) {
257
                $time = strtotime($v);
258
                if ($time < 0) {
259
                    $time = 0;
260
                }
261
                $data[$k] = $time;
262
            }
263
            if (!empty($fields) && $k !== 'id' && $k !== 'object' && !in_array($k, $fields)) {
264
                unset($data[$k]);
265
            }
266
        }
267
268
        $data['object'] = $this->table;
269
270
        return $data;
271
    }
272
273
274
    /**
275
     * Convert the mapper object to format suitable for JSON
276
     *
277
     * @param boolean $unmodified cast as public (visible) data or raw db data?
278
     * @param mixed $fields optional string|array fields to include
279
     * @return string json-encoded data
280
     */
281
    public function exportJson(bool $unmodified = false, $fields = null): string
282
    {
283
        return json_encode(empty($unmodified) ? $this->castFields($fields) : $this->exportArray($fields), JSON_PRETTY_PRINT);
284
    }
285
286
287
    /**
288
     * Set a field (default named uuid) to a UUID value if one is not present.
289
     *
290
     * @param string $field the name of the field to check and set
291
     * @return null|string $uuid the new uuid generated
292
     */
293
    public function setUUID(string $field = 'uuid')
294
    {
295
        $db = \Registry::get('db');
296
        // a proper uuid is 36 characters
297
        if (in_array($field, $this->fields()) &&
298
            (empty($this->$field) || strlen($this->$field) < 36)) {
299
            $tmp = clone $this;
300
301
            do {
302
                $uuid = Helpers\Str::uuid();
303
            }
304
            while ($tmp->load([$db->quotekey($field) . ' = ?', $uuid]));
305
306
            unset($tmp);
307
            $this->$field = $uuid;
308
            return $uuid;
309
        }
310
        return empty($this->$field) ? null : $this->$field;
311
    }
312
313
314
    /**
315
     * Write data for audit logging
316
     *
317
     * @param $data array of data to audit log
318
     * @return $this->auditData return the updated audit data for the mapper
0 ignored issues
show
Documentation introduced by
The doc-type $this->auditData could not be parsed: Unknown type name "$this-" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
319
     */
320
    public function audit(array $data = []): array
321
    {
322
        $this->auditData = array_merge($this->auditData, $data);
323
        return $this->auditData;
324
    }
325
326
}
327