Passed
Pull Request — master (#61)
by Damien
05:55 queued 02:48
created

Configuration   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 336
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 41
eloc 100
dl 0
loc 336
rs 9.1199
c 2
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
A setExtraFields() 0 5 1
A getStorageMapper() 0 3 1
A getExtraIndices() 0 3 1
A disableViewer() 0 5 1
A getExtraFields() 0 3 1
A getIgnoredColumns() 0 3 1
A prepareExtraIndices() 0 11 2
A enableViewer() 0 5 1
A configureOptions() 0 26 1
A setStorageMapper() 0 5 1
A isViewerEnabled() 0 3 1
A getTablePrefix() 0 3 1
A setProvider() 0 3 1
A getAllFields() 0 5 1
A getProvider() 0 3 1
A enableAuditFor() 0 7 2
B __construct() 0 35 10
B getEntities() 0 15 7
A setExtraIndices() 0 5 1
A setEntities() 0 5 1
A getAllIndices() 0 5 1
A disableAuditFor() 0 7 2
A getTableSuffix() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Configuration 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.

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 Configuration, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace DH\Auditor\Provider\Doctrine;
4
5
use DH\Auditor\Provider\ConfigurationInterface;
6
use DH\Auditor\Provider\Doctrine\Persistence\Helper\SchemaHelper;
7
use DH\Auditor\Provider\Doctrine\Service\AuditingService;
8
use Symfony\Component\OptionsResolver\OptionsResolver;
9
10
class Configuration implements ConfigurationInterface
11
{
12
    /**
13
     * @var DoctrineProvider
14
     */
15
    private $provider;
16
17
    /**
18
     * @var string
19
     */
20
    private $tablePrefix;
21
22
    /**
23
     * @var string
24
     */
25
    private $tableSuffix;
26
27
    /**
28
     * @var array
29
     */
30
    private $extraFields = [];
31
32
    /**
33
     * @var array
34
     */
35
    private $extraIndices = [];
36
37
    /**
38
     * @var array
39
     */
40
    private $ignoredColumns;
41
42
    /**
43
     * @var null|array
44
     */
45
    private $entities;
46
47
    /**
48
     * @var array
49
     */
50
    private $storageServices = [];
51
52
    /**
53
     * @var array
54
     */
55
    private $auditingServices = [];
56
57
    /**
58
     * @var bool
59
     */
60
    private $isViewerEnabled;
61
62
    /**
63
     * @var callable
64
     */
65
    private $storageMapper;
66
67
    /**
68
     * @var array
69
     */
70
    private $annotationLoaded = [];
71
72
    public function __construct(array $options)
73
    {
74
        $resolver = new OptionsResolver();
75
        $this->configureOptions($resolver);
76
        $config = $resolver->resolve($options);
77
78
        $this->tablePrefix = $config['table_prefix'];
79
        $this->tableSuffix = $config['table_suffix'];
80
        $this->ignoredColumns = $config['ignored_columns'];
81
82
        if (isset($config['entities']) && !empty($config['entities'])) {
83
            // use entity names as array keys for easier lookup
84
            foreach ($config['entities'] as $auditedEntity => $entityOptions) {
85
                $this->entities[$auditedEntity] = $entityOptions;
86
            }
87
        }
88
89
        if (isset($config['extra_fields']) && !empty($config['extra_fields'])) {
90
            // use field names as array keys for easier lookup
91
            foreach ($config['extra_fields'] as $fieldName => $fieldOptions) {
92
                $this->extraFields[$fieldName] = $fieldOptions;
93
            }
94
        }
95
96
        if (isset($config['extra_indices']) && !empty($config['extra_indices'])) {
97
            // use index names as array keys for easier lookup
98
            foreach ($config['extra_indices'] as $indexName => $indexOptions) {
99
                $this->extraIndices[$indexName] = $indexOptions;
100
            }
101
        }
102
103
        $this->storageServices = $config['storage_services'];
104
        $this->auditingServices = $config['auditing_services'];
105
        $this->isViewerEnabled = $config['viewer'];
106
        $this->storageMapper = $config['storage_mapper'];
107
    }
108
109
    public function configureOptions(OptionsResolver $resolver): void
110
    {
111
        // https://symfony.com/doc/current/components/options_resolver.html
112
        $resolver
113
            ->setDefaults([
114
                'table_prefix' => '',
115
                'table_suffix' => '_audit',
116
                'ignored_columns' => [],
117
                'entities' => [],
118
                'extra_fields' => [],
119
                'extra_indices' => [],
120
                'storage_services' => [],
121
                'auditing_services' => [],
122
                'viewer' => true,
123
                'storage_mapper' => null,
124
            ])
125
            ->setAllowedTypes('table_prefix', 'string')
126
            ->setAllowedTypes('table_suffix', 'string')
127
            ->setAllowedTypes('ignored_columns', 'array')
128
            ->setAllowedTypes('entities', 'array')
129
            ->setAllowedTypes('extra_fields', 'array')
130
            ->setAllowedTypes('extra_indices', 'array')
131
            ->setAllowedTypes('storage_services', 'array')
132
            ->setAllowedTypes('auditing_services', 'array')
133
            ->setAllowedTypes('viewer', 'bool')
134
            ->setAllowedTypes('storage_mapper', ['null', 'string', 'callable'])
135
        ;
136
    }
137
138
    /**
139
     * Set the value of entities.
140
     *
141
     * This method completely overrides entities configuration
142
     * including annotation configuration
143
     *
144
     * @param array<int|string, mixed> $entities
145
     */
146
    public function setEntities(array $entities): self
147
    {
148
        $this->entities = $entities;
149
150
        return $this;
151
    }
152
153
    /**
154
     * enable audit Controller and its routing.
155
     *
156
     * @return $this
157
     */
158
    public function enableViewer(): self
159
    {
160
        $this->isViewerEnabled = true;
161
162
        return $this;
163
    }
164
165
    /**
166
     * disable audit Controller and its routing.
167
     *
168
     * @return $this
169
     */
170
    public function disableViewer(): self
171
    {
172
        $this->isViewerEnabled = false;
173
174
        return $this;
175
    }
176
177
    /**
178
     * Get enabled flag.
179
     */
180
    public function isViewerEnabled(): bool
181
    {
182
        return $this->isViewerEnabled;
183
    }
184
185
    /**
186
     * Get the value of tablePrefix.
187
     */
188
    public function getTablePrefix(): string
189
    {
190
        return $this->tablePrefix;
191
    }
192
193
    /**
194
     * Get the value of tableSuffix.
195
     */
196
    public function getTableSuffix(): string
197
    {
198
        return $this->tableSuffix;
199
    }
200
201
    /**
202
     * Get the value of excludedColumns.
203
     *
204
     * @return array<string>
205
     */
206
    public function getIgnoredColumns(): array
207
    {
208
        return $this->ignoredColumns;
209
    }
210
211
    public function getExtraFields(): array
212
    {
213
        return $this->extraFields;
214
    }
215
216
    public function getAllFields(): array
217
    {
218
        return array_merge(
219
            SchemaHelper::getAuditTableColumns(),
220
            $this->extraFields
221
        );
222
    }
223
224
    /**
225
     * @param array<string, mixed> $extraFields
226
     *
227
     * @return $this
228
     */
229
    public function setExtraFields(array $extraFields): self
230
    {
231
        $this->extraFields = $extraFields;
232
233
        return $this;
234
    }
235
236
    public function getExtraIndices(): array
237
    {
238
        return $this->extraIndices;
239
    }
240
241
    public function prepareExtraIndices(string $tablename): array
242
    {
243
        $indices = [];
244
        foreach ($this->extraIndices as $extraIndexField => $extraIndexOptions) {
245
            $indices[$extraIndexField] = [
246
                'type' => $extraIndexOptions['type'] ?? 'index',
247
                'name' => sprintf('%s_%s_idx', $extraIndexOptions['name_prefix'] ?? $extraIndexField, md5($tablename)),
248
            ];
249
        }
250
251
        return $indices;
252
    }
253
254
    public function getAllIndices(string $tablename): array
255
    {
256
        return array_merge(
257
            SchemaHelper::getAuditTableIndices($tablename),
258
            $this->prepareExtraIndices($tablename)
259
        );
260
    }
261
262
    /**
263
     * @param array<string, mixed> $extraIndices
264
     *
265
     * @return $this
266
     */
267
    public function setExtraIndices(array $extraIndices): self
268
    {
269
        $this->extraIndices = $extraIndices;
270
271
        return $this;
272
    }
273
274
    /**
275
     * Get the value of entities.
276
     */
277
    public function getEntities(): array
278
    {
279
        if (null !== $this->provider) {
280
            /** @var AuditingService[] $auditingServices */
281
            $auditingServices = $this->provider->getAuditingServices();
282
            foreach ($auditingServices as $auditingService) {
283
                // do not load annotations if they're already loaded
284
                if (!isset($this->annotationLoaded[$auditingService->getName()]) || !$this->annotationLoaded[$auditingService->getName()]) {
285
                    $this->provider->loadAnnotations($auditingService->getEntityManager(), null === $this->entities ? [] : $this->entities);
286
                    $this->annotationLoaded[$auditingService->getName()] = true;
287
                }
288
            }
289
        }
290
291
        return null === $this->entities ? [] : $this->entities;
292
    }
293
294
    /**
295
     * Enables auditing for a specific entity.
296
     *
297
     * @param string $entity Entity class name
298
     *
299
     * @return $this
300
     */
301
    public function enableAuditFor(string $entity): self
302
    {
303
        if (isset($this->getEntities()[$entity])) {
304
            $this->entities[$entity]['enabled'] = true;
305
        }
306
307
        return $this;
308
    }
309
310
    /**
311
     * Disables auditing for a specific entity.
312
     *
313
     * @param string $entity Entity class name
314
     *
315
     * @return $this
316
     */
317
    public function disableAuditFor(string $entity): self
318
    {
319
        if (isset($this->getEntities()[$entity])) {
320
            $this->entities[$entity]['enabled'] = false;
321
        }
322
323
        return $this;
324
    }
325
326
    public function setStorageMapper(callable $mapper): self
327
    {
328
        $this->storageMapper = $mapper;
329
330
        return $this;
331
    }
332
333
    public function getStorageMapper(): ?callable
334
    {
335
        return $this->storageMapper;
336
    }
337
338
    public function getProvider(): DoctrineProvider
339
    {
340
        return $this->provider;
341
    }
342
343
    public function setProvider(DoctrineProvider $provider): void
344
    {
345
        $this->provider = $provider;
346
    }
347
}
348