Passed
Push — develop ( 36c731...cb55ce )
by Andrew
02:56
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
16
{
17
    /** @var FieldsValidator */
18
    private $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
    private $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
    private $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
     * Entity data goes here
82
     * @var array
83
     */
84
    private $fields = [];
85
86
    /**
87
     * BaseEntity constructor.
88
     */
89 7
    public function __construct()
90
    {
91
        // Append fields and aliases of abstract parent class with the child entity data.
92 7
        $this->fieldsParams = array_merge($this->fieldsParams, $this->fieldsParamsAppend);
93 7
        $this->aliases = array_merge($this->aliases, $this->aliasesAppend);
94
95 7
        $this->fieldsValidator = new FieldsValidator($this->fieldsParams); // Composition
96 7
    }
97
98
    /**
99
     * @param string $action
100
     * @return void
101
     * @throws InvalidArgumentException
102
     * @throws EntityFieldsException
103
     */
104 5
    public function setFields($action)
105
    {
106 5
        if (('add' !== $action) && ('update' !== $action) && ('fill' !== $action)) {
107 1
            throw new InvalidArgumentException("Action \"$action\" is not a proper action parameter");
108
        }
109
110 4
        self::validateDataBeforeSet($this->container);
111
112 4
        if (!isset($this->container['created_at']) && !isset($this->container['date_create'])) {
113 1
            $this->setCreatedAt();
114
        }
115
116 4
        $this->container = $this->renameAliases($this->container);
117
118 4
        $this->fieldsValidator->setAction($action);
119
120 4
        foreach ($this->fieldsParams as $key => $params) {
121 4
            $fieldData = isset($this->container[$key]) ? $this->container[$key] : null;
122 4
            if (($this->fieldsValidator->isValid($key, $fieldData)) && (!empty($fieldData))) {
123 4
                $this->setField($key, $fieldData);
124
            }
125
        }
126 4
    }
127
128
    /**
129
     * @return string
130
     */
131 1
    public function getRequestName()
132
    {
133 1
        return $this->requestName;
134
    }
135
136
    /**
137
     * @return array
138
     */
139 3
    public function getFields()
140
    {
141 3
        return $this->fields;
142
    }
143
144
    /**
145
     * @param array $data
146
     * @return BaseEntity
147
     * @throws EntityFieldsException
148
     * @throws InvalidArgumentException
149
     */
150 1
    public function fill(array $data)
151
    {
152 1
        $this->container = $data;
153 1
        $this->setFields('fill');
154 1
        return $this;
155
    }
156
157
    /**
158
     * The updated_at field must be greater than the existing one, so
159
     * we update it automatically if none was passed by user.
160
     */
161
    public function setUpdatedAt()
162
    {
163
        if ((isset($this->fields['updated_at'])) && ($this->container['updated_at'] === $this->fields['updated_at'])) {
164
            $this->container['updated_at'] = time();
165
        }
166
    }
167
168 1
    private function setCreatedAt()
169
    {
170 1
        $this->container['created_at'] = time();
171 1
    }
172
173
    /**
174
     * @param array $data
175
     * @return bool
176
     * @throws EntityFieldsException
177
     */
178 4
    private static function validateDataBeforeSet(array $data)
179
    {
180 4
        if (empty($data)) {
181
            throw new EntityFieldsException('Data is empty');
182
        }
183
184 4
        if (count(array_filter(array_keys($data), 'is_string')) < 1) {
185
            $message = sprintf('Data is not an associative array: "%s"', var_export($data, true));
186
            throw new EntityFieldsException($message);
187
        }
188
189 4
        return true;
190
    }
191
192
    /**
193
     * @param array $data
194
     * @return array
195
     */
196 4
    private function renameAliases(array $data)
197
    {
198 4
        foreach ($data as $key => $value) {
199 4
            if (in_array($key, $this->aliases)) {
200
                $newKey = array_search($key, $this->aliases);
201
                $data[$newKey] = $data[$key];
202 4
                unset($data[$key]);
203
            }
204
        }
205
206 4
        return $data;
207
    }
208
209
    /**
210
     * @param string $key
211
     * @param mixed $value
212
     */
213 4
    private function setField($key, $value)
214
    {
215 4
        switch ($this->fieldsParams[$key]['type']) {
216 4
            case 'int':
217 4
                $value = (int)$value;
218 4
                break;
219
            case 'string':
220
                $value = (string)$value;
221
                break;
222
            case 'bool':
223
                $value = (bool)$value;
224
                break;
225
        }
226
227 4
        $this->fields[$key] = $value;
228 4
    }
229
230
    //////////////////////////////////////////////
231
    // The implementation of ArrayAccess interface
232
    //////////////////////////////////////////////
233
234
    /**
235
     * @param mixed $offset
236
     * @param mixed $value
237
     */
238 4
    public function offsetSet($offset, $value)
239
    {
240 4
        if (is_null($offset)) {
241
            $this->container[] = $value;
242
        } else {
243 4
            $this->container[$offset] = $value;
244
        }
245 4
    }
246
247
    /**
248
     * @param mixed $offset
249
     * @return bool
250
     */
251
    public function offsetExists($offset)
252
    {
253
        return isset($this->container[$offset]);
254
    }
255
256
    /**
257
     * @param mixed $offset
258
     */
259
    public function offsetUnset($offset)
260
    {
261
        unset($this->container[$offset]);
262
    }
263
264
    /**
265
     * @param mixed $offset
266
     * @return mixed|null
267
     */
268 1
    public function offsetGet($offset)
269
    {
270 1
        return isset($this->fields[$offset]) ? $this->fields[$offset] : null;
271
    }
272
}