Completed
Push — master ( fc0ef9...fd9cb0 )
by Andrew
04:08
created

BaseEntity::offsetSet()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

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