Passed
Push — develop ( 9192d3...9cc5f1 )
by Andrew
02:41
created

BaseEntity::offsetUnset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 1
crap 2
1
<?php
2
3
4
namespace ddlzz\AmoAPI\Entities;
5
6
use ddlzz\AmoAPI\Exceptions\EntityFieldsException;
7
use ddlzz\AmoAPI\Exceptions\InvalidArgumentException;
8
use ddlzz\AmoAPI\Validators\FieldsValidator;
9
10
/**
11
 * Class BaseEntity
12
 * @package ddlzz\AmoAPI\Entities
13
 * @author ddlzz
14
 */
15
abstract class BaseEntity implements \ArrayAccess, EntityInterface
16
{
17
    /** @var FieldsValidator */
18
    protected $fieldsValidator;
19
20
    /** @var string */
21
    protected $requestName = '';
22
23
    /**
24
     * Data container for an ArrayAccess interface implementation.
25
     * @var array
26
     */
27
    protected $container = [];
28
29
    /**
30
     * Fields parameters for validation purposes. These are fields that are used in every entity.
31
     * @var array
32
     */
33
    protected $fieldsParams = [
34
        'id' => [
35
            'type' => 'int',
36
            'required_add' => false,
37
            'required_update' => true,
38
        ],
39
        'responsible_user_id' => [
40
            'type' => 'int',
41
            'required_add' => false,
42
            'required_update' => false,
43
        ],
44
        'created_by' => [
45
            'type' => 'int',
46
            'required_add' => false,
47
            'required_update' => false,
48
        ],
49
        'created_at' => [
50
            'type' => 'int',
51
            'required_add' => true,
52
            'required_update' => false,
53
        ],
54
        'updated_at' => [
55
            'type' => 'int',
56
            'required_add' => false,
57
            'required_update' => true,
58
        ],
59
        'account_id' => [
60
            'type' => 'int',
61
            'required_add' => false,
62
            'required_update' => false,
63
        ],
64
    ];
65
66
    /** @var array */
67
    protected $fieldsParamsAppend = [];
68
69
    /** @var array */
70
    protected $aliases = [
71
        'created_at' => 'date_create',
72
        'updated_at' => 'last_modified',
73
        'created_by' => 'created_user_id',
74
75
    ];
76
77
    /** @var array */
78
    protected $aliasesAppend = [];
79
80
    /**
81
     * EntityInterface data goes here
82
     * @var array
83
     */
84
    protected $fields = [];
85
86
    /**
87
     * BaseEntity constructor.
88
     */
89
    public function __construct()
90
    {
91
        // Append fields and aliases of abstract parent class with the child entity data.
92
        $this->fieldsParams = array_merge($this->fieldsParams, $this->fieldsParamsAppend);
93
        $this->aliases = array_merge($this->aliases, $this->aliasesAppend);
94
95
        $this->fieldsValidator = new FieldsValidator($this->fieldsParams); // Composition
96
    }
97
98
    /**
99
     * @param string $action
100
     * @return void
101
     * @throws InvalidArgumentException
102
     * @throws EntityFieldsException
103
     */
104
    public function setFields($action)
105
    {
106
        if (('add' !== $action) && ('update' !== $action) && ('fill' !== $action)) {
107
            throw new InvalidArgumentException("Action \"$action\" is not a proper action parameter");
108
        }
109
110
        if (!isset($this->container['created_at']) && !isset($this->container['date_create'])) {
111
            $this->setCreatedAt();
112
        }
113
114
        $data = self::validateDataBeforeSet($this->container);
115
        $data = $this->renameAliases($data);
116
117
        $this->fieldsValidator->setAction($action);
118
119
        foreach ($this->fieldsParams as $key => $params) {
120
            $fieldData = isset($data[$key]) ? $data[$key] : null;
121
            if (($this->fieldsValidator->isValid($key, $fieldData)) && (!empty($fieldData))) {
122
                $this->setField($key, $fieldData);
123
            }
124
        }
125
    }
126
127
    /**
128
     * @return string
129
     */
130
    public function getRequestName()
131
    {
132
        return $this->requestName;
133
    }
134
135
    /**
136
     * @return array
137
     */
138
    public function getFields()
139
    {
140
        return $this->fields;
141
    }
142
143
    /**
144
     * @param array $data
145
     * @return EntityInterface $this
146
     * @throws EntityFieldsException
147
     * @throws InvalidArgumentException
148
     */
149
    public function fill(array $data)
150
    {
151
        $this->container = $data;
152
        $this->setFields('fill');
153
        return $this;
154
    }
155
156
    public function setUpdatedAtParam()
157
    {
158
        if ((isset($this->fields['updated_at'])) && ($this->container['updated_at'] === $this->fields['updated_at'])) {
159
            $this->container['updated_at'] = time();
160
        }
161
    }
162
163
    private function setCreatedAt()
164
    {
165
        $this->container['created_at'] = time();
166
    }
167
168
    /**
169
     * @param array $data
170
     * @return array
171
     * @throws EntityFieldsException
172
     */
173
    private static function validateDataBeforeSet(array $data)
174
    {
175
        if (empty($data)) {
176
            throw new EntityFieldsException('Data is empty');
177
        }
178
179
        if (count(array_filter(array_keys($data), 'is_string')) < 1) {
180
            $message = sprintf('Data is not an associative array: "%s"', var_export($data, true));
181
            throw new EntityFieldsException($message);
182
        }
183
184
        return $data;
185
    }
186
187
    /**
188
     * @param array $data
189
     * @return array
190
     */
191
    private function renameAliases(array $data)
192
    {
193
        foreach ($data as $key => $value) {
194
            if (in_array($key, $this->aliases)) {
195
                $newKey = array_search($key, $this->aliases);
196
                $data[$newKey] = $data[$key];
197
                unset($data[$key]);
198
            }
199
        }
200
201
        return $data;
202
    }
203
204
    /**
205
     * @param string $key
206
     * @param mixed $value
207
     */
208
    private function setField($key, $value)
209
    {
210
        switch ($this->fieldsParams[$key]['type']) {
211
            case 'int':
212
                $value = (int)$value;
213
                break;
214
            case 'string':
215
                $value = (string)$value;
216
                break;
217
            case 'bool':
218
                $value = (bool)$value;
219
                break;
220
        }
221
222
        $this->fields[$key] = $value;
223
    }
224
225
    //////////////////////////////////////////////
226
    // The implementation of ArrayAccess interface
227
    //////////////////////////////////////////////
228
229
    /**
230
     * @param mixed $offset
231
     * @param mixed $value
232
     */
233
    public function offsetSet($offset, $value)
234
    {
235
        if (is_null($offset)) {
236
            $this->container[] = $value;
237
        } else {
238
            $this->container[$offset] = $value;
239
        }
240
    }
241
242
    /**
243
     * @param mixed $offset
244
     * @return bool
245
     */
246
    public function offsetExists($offset)
247
    {
248
        return isset($this->container[$offset]);
249
    }
250
251
    /**
252
     * @param mixed $offset
253
     */
254
    public function offsetUnset($offset)
255
    {
256
        unset($this->container[$offset]);
257
    }
258
259
    /**
260
     * @param mixed $offset
261
     * @return mixed|null
262
     */
263
    public function offsetGet($offset)
264
    {
265
        return isset($this->fields[$offset]) ? $this->fields[$offset] : null;
266
    }
267
}