Passed
Push — develop ( cb55ce...1309b5 )
by Andrew
02:54 queued 31s
created

BaseEntity::offsetGet()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 2
eloc 1
nc 2
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 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
112 8
        if (!isset($this->container['created_at']) && !isset($this->container['date_create'])) {
113 5
            $this->setCreatedAt();
114
        }
115
116 8
        $this->container = $this->renameAliases($this->container);
117
118 8
        $this->fieldsValidator->setAction($action);
119
120 8
        foreach ($this->fieldsParams as $key => $params) {
121 8
            $fieldData = isset($this->container[$key]) ? $this->container[$key] : null;
122 8
            if (($this->fieldsValidator->isValid($key, $fieldData)) && (!empty($fieldData))) {
123 8
                $this->setField($key, $fieldData);
124
            }
125
        }
126 8
    }
127
128
    /**
129
     * @return string
130
     */
131 2
    public function getRequestName()
132
    {
133 2
        return $this->requestName;
134
    }
135
136
    /**
137
     * @return array
138
     */
139 5
    public function getFields()
140
    {
141 5
        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 1
    public function setUpdatedAt()
162
    {
163 1
        if ((isset($this->fields['updated_at'])) && ($this->container['updated_at'] === $this->fields['updated_at'])) {
164 1
            $this->container['updated_at'] = time();
165
        }
166 1
    }
167
168 5
    private function setCreatedAt()
169
    {
170 5
        $this->container['created_at'] = time();
171 5
    }
172
173
    /**
174
     * @param array $data
175
     * @return bool
176
     * @throws EntityFieldsException
177
     */
178 10
    private static function validateDataBeforeSet(array $data)
179
    {
180 10
        if (empty($data)) {
181 1
            throw new EntityFieldsException('Data is empty');
182
        }
183
184 9
        if (count(array_filter(array_keys($data), 'is_string')) < 1) {
185 1
            $message = sprintf('Data is not an associative array: "%s"', var_export($data, true));
186 1
            throw new EntityFieldsException($message);
187
        }
188
189 8
        return true;
190
    }
191
192
    /**
193
     * @param array $data
194
     * @return array
195
     */
196 8
    private function renameAliases(array $data)
197
    {
198 8
        foreach ($data as $key => $value) {
199 8
            if (in_array($key, $this->aliases)) {
200 1
                $newKey = array_search($key, $this->aliases);
201 1
                $data[$newKey] = $data[$key];
202 8
                unset($data[$key]);
203
            }
204
        }
205
206 8
        return $data;
207
    }
208
209
    /**
210
     * @param string $key
211
     * @param mixed $value
212
     */
213 8
    private function setField($key, $value)
214
    {
215 8
        switch ($this->fieldsParams[$key]['type']) {
216 8
            case 'int':
217 8
                $value = (int)$value;
218 8
                break;
219 1
            case 'string':
220 1
                $value = (string)$value;
221 1
                break;
222 1
            case 'bool':
223 1
                $value = (bool)$value;
224 1
                break;
225
        }
226
227 8
        $this->fields[$key] = $value;
228 8
    }
229
230
    //////////////////////////////////////////////
231
    // The implementation of ArrayAccess interface
232
    //////////////////////////////////////////////
233
234
    /**
235
     * @param mixed $offset
236
     * @param mixed $value
237
     */
238 12
    public function offsetSet($offset, $value)
239
    {
240 12
        if (is_null($offset)) {
241 1
            $this->container[] = $value;
242
        } else {
243 12
            $this->container[$offset] = $value;
244
        }
245 12
    }
246
247
    /**
248
     * @param mixed $offset
249
     * @return bool
250
     */
251 2
    public function offsetExists($offset)
252
    {
253 2
        return isset($this->container[$offset]);
254
    }
255
256
    /**
257
     * @param mixed $offset
258
     */
259 1
    public function offsetUnset($offset)
260
    {
261 1
        unset($this->container[$offset]);
262 1
    }
263
264
    /**
265
     * @param mixed $offset
266
     * @return mixed|null
267
     */
268 4
    public function offsetGet($offset)
269
    {
270 4
        return isset($this->fields[$offset]) ? $this->fields[$offset] : null;
271
    }
272
}