Completed
Push — dev-master ( 84c696...872305 )
by Vijay
03:29
created

Mapper::validateSave()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 12
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
dl 0
loc 12
rs 9.2
c 0
b 0
f 0
eloc 5
nc 4
nop 1
1
<?php
2
3
namespace FFCMS\Mappers;
4
5
use FFCMS\Traits;
6
use FFMVC\Helpers;
7
8
/**
9
 * Base Database Mapper Class extends f3's DB\SQL\Mapper
10
 *
11
 * @author Vijay Mahrra <[email protected]>
12
 * @copyright (c) Copyright 2016 Vijay Mahrra
13
 * @license GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html)
14
 * @link https://fatfreeframework.com/sql-mapper
15
 * @link https://github.com/Wixel/GUMP
16
 */
17
18
// abstract class Magic implements ArrayAccess
19
// abstract class Cursor extends \Magic implements \IteratorAggregate
20
// class Mapper extends \DB\Cursor
21
/**
22
 * @property string $key
23
 * @property string $value
24
 * @property string $created
25
 */
26
abstract class Mapper extends \DB\SQL\Mapper
27
{
28
    use Traits\Logger,
29
        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
52
     */
53
    protected $table;
54
55
    /**
56
     * @var string $uuid the fieldname used for the uuid
57
     */
58
    protected $uuidField = 'uuid';
59
60
    /**
61
     * @var boolean $valid the data after validation is valid?
62
     */
63
    protected $valid = null;
64
65
    /**
66
     * initialize with array of params
67
     *
68
     */
69
    public function __construct(array $params = [])
70
    {
71
        $f3 = \Base::instance();
72
73
        $this->oLog = \Registry::get('logger');
74
        $this->db = \Registry::get('db');
75
76
        // guess the table name from the class name if not specified as a class member
77
        $class = strrchr(get_class($this), '\\');
78
        $class = \UTF::instance()->substr($class,1);
79
        if (empty($this->table)) {
80
            $table = $f3->snakecase($class);
81
        } else {
82
            $table = $this->table;
83
        }
84
        $this->table = $table;
85
86
        parent::__construct($this->db, $table);
87
88
        foreach ($params as $k => $v) {
89
            $this->$k = $v;
90
        }
91
92
        // save default validation rules and filter rules in-case we add rules
93
        $this->validationRulesDefault = $this->validationRules;
94
        $this->filterRulesDefault = $this->filterRules;
95
96
        // filter data, set UUID and date created before insert
97
        $this->beforeinsert(function($mapper){
98
            $mapper->setUUID($mapper->uuidField);
99
            $mapper->copyFrom($mapper->filter());
100
            if (in_array('created', $mapper->fields()) && empty($mapper->created)) {
101
                $mapper->created = Helpers\Time::database();
102
            }
103
            return $mapper->validate();
104
        });
105
106
        // filter data, set updated field if present before update
107
        $this->beforeupdate(function($mapper){
108
            $mapper->copyFrom($mapper->filter());
109
            return $mapper->validate();
110
        });
111
112
    }
113
114
115
    /**
116
     * return string representation of class - json of data
117
     *
118
     * @param string
119
     */
120
    public function __toString(): string
121
    {
122
        return json_encode($this->cast(), JSON_PRETTY_PRINT);
123
    }
124
125
126
    /**
127
     * return array representation of class - json of data
128
     *
129
     * @param array
130
     */
131
    public function __toArray(): array
132
    {
133
        return $this->cast();
134
    }
135
136
    /**
137
     * Cast the mapper data to an array using only provided fields
138
     *
139
     * @param mixed string|array fields to return in response
140
     * @param array optional data optional data to use instead of fields
141
     * @return array $data
142
     */
143
    public function castFields($fields = null, array $data = []): array
144
    {
145 View Code Duplication
        if (!empty($fields)) {
146
            if (is_string($fields)) {
147
                $fields = preg_split("/[\s,]+/", strtolower($fields));
148
            } else if (!is_array($fields)) {
149
                $fields = [];
150
            }
151
        }
152
153
        if (empty($data) || !is_array($data)) {
154
            $data = $this->cast();
155
        }
156
157
        if (empty($fields)) {
158
            $fields = array_keys($data);
159
        }
160
161
        // remove fields not in the list
162
        foreach ($data as $k => $v) {
163
            if (!in_array($k, $fields)) {
164
                unset($data[$k]);
165
            }
166
        }
167
168
        $data['object'] = $this->table;
169
170
        return $data;
171
    }
172
173
    /**
174
     * Cast the mapper data to an array and modify (for external clients typically)
175
     * using the visible fields and names for export, converting dates to unixtime
176
     * optionally pass in a comma (or space)-separated list of fields or an array of fields
177
     *
178
     * @param mixed string|array fields to return in response
179
     * @param array optional data optional data to use instead of fields
180
     * @return array $data
181
     */
182
    public function exportArray($fields = null, array $data = []): array
183
    {
184 View Code Duplication
        if (!empty($fields)) {
185
            if (is_string($fields)) {
186
                $fields = preg_split("/[\s,]+/", strtolower($fields));
187
            } else if (!is_array($fields)) {
188
                $fields = [];
189
            }
190
        }
191
192
        if (empty($data) || !is_array($data)) {
193
            $data = $this->cast();
194
        }
195
196
        foreach ($data as $k => $v) {
197
            if (empty($this->fieldsVisible[$k])) {
198
                unset($data[$k]);
199
                continue;
200
            } elseif (true !== $this->fieldsVisible[$k]) {
201
                unset($data[$k]);
202
                $k = $this->fieldsVisible[$k];
203
                $data[$k] = $v;
204
            }
205
            // convert date to unix timestamp
206
            if ('updated' == $k || 'created' == $k || (
207
                strlen($v) == 19 && preg_match("/^[\d]{4}-[\d]{2}-[\d]{2}[\s]+[\d]{2}:[\d]{2}:[\d]{2}/", $v, $m))) {
208
                $time = strtotime($v);
209
                if ($time < 0) {
210
                    $time = 0;
211
                }
212
                $data[$k] = $time;
213
            }
214
            if (!empty($fields) && $k !== 'id' && $k !== 'object' && !in_array($k, $fields)) {
215
                unset($data[$k]);
216
            }
217
        }
218
219
        $data['object'] = $this->table;
220
221
        return $data;
222
    }
223
224
225
    /**
226
     * Convert the mapper object to format suitable for JSON
227
     *
228
     * @param boolean $unmodified cast as public (visible) data or raw db data?
229
     * @param mixed $fields optional string|array fields to include
230
     * @return string json-encoded data
231
     */
232
    public function exportJson(bool $unmodified = false, $fields = null): string
233
    {
234
        return json_encode(empty($unmodified) ? $this->castFields($fields) : $this->exportArray($fields), JSON_PRETTY_PRINT);
235
    }
236
237
238
    /**
239
     * Set a field (default named uuid) to a UUID value if one is not present.
240
     *
241
     * @param string $field the name of the field to check and set
242
     * @return null|string $uuid the new uuid generated
243
     */
244
    public function setUUID(string $field = 'uuid')
245
    {
246
        $db = \Registry::get('db');
247
        // a proper uuid is 36 characters
248
        if (in_array($field, $this->fields()) &&
249
            (empty($this->$field) || strlen($this->$field) < 36)) {
250
            $tmp = clone $this;
251
252
            do {
253
                $uuid = Helpers\Str::uuid();
254
            }
255
            while ($tmp->load([$db->quotekey($field) . ' = ?', $uuid]));
256
257
            unset($tmp);
258
            $this->$field = $uuid;
259
            return $uuid;
260
        }
261
        return empty($this->$field) ? null : $this->$field;
262
    }
263
}
264