AbstractEntity   A
last analyzed

Complexity

Total Complexity 41

Size/Duplication

Total Lines 239
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 41
lcom 2
cbo 1
dl 0
loc 239
ccs 82
cts 82
cp 1
rs 9.1199
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A toArray() 0 16 3
C getData() 0 36 16
A getMapping() 0 6 2
A getRelationshipMap() 0 4 1
A getRelationships() 0 4 1
A addRelationship() 0 6 1
A getDecorators() 0 11 2
A getValidator() 0 4 1
A hydrate() 0 8 2
A offsetSet() 0 16 6
A offsetGet() 0 10 2
A offsetExists() 0 4 1
A offsetUnset() 0 4 1
A getReadScope() 0 4 1
A getWriteScope() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like AbstractEntity often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractEntity, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Percy\Entity;
4
5
use InvalidArgumentException;
6
use RuntimeException;
7
use Percy\Exception\ScopeException;
8
use Percy\Store\StoreInterface;
9
10
abstract class AbstractEntity implements EntityInterface
11
{
12
    /**
13
     * @var array
14
     */
15
    protected $data = [];
16
17
    /**
18
     * @var array
19
     */
20
    protected $mapping = [];
21
22
    /**
23
     * @var array
24
     */
25
    protected $relationshipMap = [];
26
27
    /**
28
     * @var array
29
     */
30
    protected $relationships = [];
31
32
    /**
33
     * @var array
34
     */
35
    protected $decorators = [];
36
37
    /**
38
     * @var string
39
     */
40
    protected $validator;
41
42
    /**
43
     * @var string
44
     */
45
    protected $readScope;
46
47
    /**
48
     * @var string
49
     */
50
    protected $writeScope;
51
52
    /**
53
     * {@inheritdoc}
54
     */
55 2
    public function toArray(array $scopes = [])
56
    {
57
        $data = [
58 2
            '_relationships' => []
59 2
        ];
60
61 2
        foreach ($this->getRelationships() as $key => $value) {
62
            try {
63 1
                $data['_relationships'][$key] = $value->toArray($scopes);
64 1
            } catch (ScopeException $e) {
65 1
                continue;
66
            }
67 2
        }
68
69 2
        return array_merge($this->getData($scopes, false), $data);
70
    }
71
72
    /**
73
     * {@inheritdoc}
74
     */
75 6
    public function getData(array $scopes = [], $toPersist = false)
76
    {
77 6
        if (! is_null($this->getReadScope()) && ! in_array($this->getReadScope(), $scopes)) {
78 1
            throw new ScopeException(sprintf(
79 1
                '(%s) scope needed to read (%s) resource', $this->getReadScope(), get_called_class()
80 1
            ));
81
        }
82
83 5
        if (! is_null($this->getWriteScope()) && ! in_array($this->getWriteScope(), $scopes) && $toPersist === true) {
84 1
            throw new ScopeException(sprintf(
85 1
                '(%s) scope needed to write (%s) resource', $this->getWriteScope(), get_called_class()
86 1
            ));
87
        }
88
89 4
        $data = [];
90
91 4
        foreach ($this->mapping as $prop => $options) {
92 4
            if (array_key_exists('persist', $options) && $options['persist'] === false && $toPersist === true) {
93 1
                continue;
94
            }
95
96 4
            if (array_key_exists('read', $options) && ! in_array($options['read'], $scopes)) {
97 1
                continue;
98
            }
99
100 4
            if (array_key_exists('write', $options) && ! in_array($options['write'], $scopes) && $toPersist === true) {
101 1
                continue;
102
            }
103
104 4
            if (array_key_exists($prop, $this->data)) {
105 3
                $data[$prop] = $this->data[$prop];
106 3
            }
107 4
        }
108
109 4
        return $data;
110
    }
111
112
    /**
113
     * {@inheritdoc}
114
     */
115
    public function getMapping()
116
    {
117 9
        return array_combine(array_keys($this->mapping), array_map(function ($value) {
118 9
            return (array_key_exists('type', $value)) ? $value['type'] : null;
119 9
        }, $this->mapping));
120
    }
121
122
    /**
123
     * {@inheritdoc}
124
     */
125 2
    public function getRelationshipMap()
126
    {
127 2
        return $this->relationshipMap;
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133 3
    public function getRelationships()
134
    {
135 3
        return $this->relationships;
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141 3
    public function addRelationship($relationship, Collection $collection)
142
    {
143 3
        $this->relationships[$relationship] = $collection;
144
145 3
        return $this;
146
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151 4
    public function getDecorators($action = null)
152
    {
153 4
        $decorators = array_replace([
154 4
            StoreInterface::ON_CREATE => [],
155 4
            StoreInterface::ON_READ   => [],
156 4
            StoreInterface::ON_UPDATE => [],
157 4
            StoreInterface::ON_DELETE => []
158 4
        ], $this->decorators);
159
160 4
        return (is_null($action)) ? $decorators : $decorators[$action];
161
    }
162
163
    /**
164
     * {@inheritdoc}
165
     */
166 1
    public function getValidator()
167
    {
168 1
        return $this->validator;
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     */
174 6
    public function hydrate(array $data)
175
    {
176 6
        foreach ($data as $key => $value) {
177 3
            $this[$key] = $value;
178 6
        }
179
180 6
        return $this;
181
    }
182
183
    /**
184
     * {@inheritdoc}
185
     */
186 5
    public function offsetSet($offset, $value)
187
    {
188 5
        $mapping = $this->getMapping();
189
190 5
        if (! array_key_exists($offset, $mapping)) {
191 1
            throw new InvalidArgumentException(
192 1
                sprintf('(%s) is not an accepted field for (%s)', $offset, get_class($this))
193 1
            );
194
        }
195
196 4
        if (array_key_exists($offset, $mapping) && ! is_null($mapping[$offset]) && ! is_null($value)) {
197 2
            settype($value, $mapping[$offset]);
198 2
        }
199
200 4
        $this->data[$offset] = (! isset($value)) ? null : $value;
201 4
    }
202
203
    /**
204
     * {@inheritdoc}
205
     */
206 3
    public function offsetGet($offset)
207
    {
208 3
        if (array_key_exists($offset, $this->data)) {
209 2
            return $this->data[$offset];
210
        }
211
212 1
        throw new InvalidArgumentException(
213 1
            sprintf('Undefined offset (%s) on (%s)', $offset, get_class($this))
214 1
        );
215
    }
216
217
    /**
218
     * {@inheritdoc}
219
     */
220 1
    public function offsetExists($offset)
221
    {
222 1
        return isset($this->data);
223
    }
224
225
    /**
226
     * {@inheritdoc}
227
     */
228 1
    public function offsetUnset($offset)
229
    {
230 1
        unset($this->data[$offset]);
231 1
    }
232
233
    /**
234
     * {@inheritdoc}
235
     */
236 6
    public function getReadScope()
237
    {
238 6
        return $this->readScope;
239
    }
240
241
    /**
242
     * {@inheritdoc}
243
     */
244 5
    public function getWriteScope()
245
    {
246 5
        return $this->writeScope;
247
    }
248
}
249