Passed
Push — master ( 998d51...9a71d1 )
by Damien
02:39
created

AuditHelper::getAuditTableColumns()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 74
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 54
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 74
rs 9.0036

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace DH\DoctrineAuditBundle\Helper;
4
5
use DH\DoctrineAuditBundle\AuditConfiguration;
6
use DH\DoctrineAuditBundle\User\UserInterface;
7
use Doctrine\DBAL\Types\Type;
8
use Doctrine\ORM\EntityManager;
9
10
class AuditHelper
11
{
12
    /**
13
     * @var \DH\DoctrineAuditBundle\AuditConfiguration
14
     */
15
    private $configuration;
16
17
    /**
18
     * @param AuditConfiguration $configuration
19
     */
20
    public function __construct(AuditConfiguration $configuration)
21
    {
22
        $this->configuration = $configuration;
23
    }
24
25
    /**
26
     * @return \DH\DoctrineAuditBundle\AuditConfiguration
27
     */
28
    public function getConfiguration(): AuditConfiguration
29
    {
30
        return $this->configuration;
31
    }
32
33
    /**
34
     * Returns the primary key value of an entity.
35
     *
36
     * @param EntityManager $em
37
     * @param object        $entity
38
     *
39
     * @throws \Doctrine\DBAL\DBALException
40
     * @throws \Doctrine\ORM\Mapping\MappingException
41
     *
42
     * @return mixed
43
     */
44
    public function id(EntityManager $em, $entity)
45
    {
46
        $meta = $em->getClassMetadata(\get_class($entity));
47
        $pk = $meta->getSingleIdentifierFieldName();
48
49
        if (isset($meta->fieldMappings[$pk])) {
50
            $type = Type::getType($meta->fieldMappings[$pk]['type']);
51
52
            return $this->value($em, $type, $meta->getReflectionProperty($pk)->getValue($entity));
53
        }
54
55
        /**
56
         * Primary key is not part of fieldMapping.
57
         *
58
         * @see https://github.com/DamienHarper/DoctrineAuditBundle/issues/40
59
         * @see https://www.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/composite-primary-keys.html#identity-through-foreign-entities
60
         * We try to get it from associationMapping (will throw a MappingException if not available)
61
         */
62
        $targetEntity = $meta->getReflectionProperty($pk)->getValue($entity);
63
64
        $mapping = $meta->getAssociationMapping($pk);
65
        $meta = $em->getClassMetadata($mapping['targetEntity']);
66
        $pk = $meta->getSingleIdentifierFieldName();
67
        $type = Type::getType($meta->fieldMappings[$pk]['type']);
68
69
        return $this->value($em, $type, $meta->getReflectionProperty($pk)->getValue($targetEntity));
70
    }
71
72
    /**
73
     * Computes a usable diff.
74
     *
75
     * @param EntityManager $em
76
     * @param object        $entity
77
     * @param array         $ch
78
     *
79
     * @throws \Doctrine\DBAL\DBALException
80
     * @throws \Doctrine\ORM\Mapping\MappingException
81
     *
82
     * @return array
83
     */
84
    public function diff(EntityManager $em, $entity, array $ch): array
85
    {
86
        $meta = $em->getClassMetadata(\get_class($entity));
87
        $diff = [];
88
89
        foreach ($ch as $fieldName => list($old, $new)) {
90
            $o = null;
91
            $n = null;
92
93
            if (
94
                $meta->hasField($fieldName) &&
95
                !isset($meta->embeddedClasses[$fieldName]) &&
96
                $this->configuration->isAuditedField($entity, $fieldName)
97
            ) {
98
                $mapping = $meta->fieldMappings[$fieldName];
99
                $type = Type::getType($mapping['type']);
100
                $o = $this->value($em, $type, $old);
101
                $n = $this->value($em, $type, $new);
102
            } elseif (
103
                $meta->hasAssociation($fieldName) &&
104
                $meta->isSingleValuedAssociation($fieldName) &&
105
                $this->configuration->isAuditedField($entity, $fieldName)
106
            ) {
107
                $o = $this->summarize($em, $old);
108
                $n = $this->summarize($em, $new);
109
            }
110
111
            if ($o !== $n) {
112
                $diff[$fieldName] = [
113
                    'old' => $o,
114
                    'new' => $n,
115
                ];
116
            }
117
        }
118
119
        return $diff;
120
    }
121
122
    /**
123
     * Type converts the input value and returns it.
124
     *
125
     * @param EntityManager $em
126
     * @param Type          $type
127
     * @param mixed         $value
128
     *
129
     * @throws \Doctrine\DBAL\DBALException
130
     *
131
     * @return mixed
132
     */
133
    private function value(EntityManager $em, Type $type, $value)
134
    {
135
        if (null === $value) {
136
            return null;
137
        }
138
139
        $platform = $em->getConnection()->getDatabasePlatform();
140
141
        switch ($type->getName()) {
142
            case Type::DECIMAL:
143
            case Type::BIGINT:
144
                $convertedValue = (string) $value;
145
146
                break;
147
            case Type::INTEGER:
148
            case Type::SMALLINT:
149
                $convertedValue = (int) $value;
150
151
                break;
152
            case Type::FLOAT:
153
            case Type::BOOLEAN:
154
                $convertedValue = $type->convertToPHPValue($value, $platform);
155
156
                break;
157
            default:
158
                $convertedValue = $type->convertToDatabaseValue($value, $platform);
159
        }
160
161
        return $convertedValue;
162
    }
163
164
    /**
165
     * Blames an audit operation.
166
     *
167
     * @return array
168
     */
169
    public function blame(): array
170
    {
171
        $user_id = null;
172
        $username = null;
173
        $client_ip = null;
174
        $user_fqdn = null;
175
        $user_firewall = null;
176
177
        $request = $this->configuration->getRequestStack()->getCurrentRequest();
178
        if (null !== $request) {
179
            $client_ip = $request->getClientIp();
180
            $user_firewall = null === $this->configuration->getFirewallMap()->getFirewallConfig($request) ? null : $this->configuration->getFirewallMap()->getFirewallConfig($request)->getName();
181
        }
182
183
        $user = $this->configuration->getUserProvider()->getUser();
184
        if ($user instanceof UserInterface) {
185
            $user_id = $user->getId();
186
            $username = $user->getUsername();
187
            $user_fqdn = \get_class($user);
188
        }
189
190
        return [
191
            'user_id' => $user_id,
192
            'username' => $username,
193
            'client_ip' => $client_ip,
194
            'user_fqdn' => $user_fqdn,
195
            'user_firewall' => $user_firewall,
196
        ];
197
    }
198
199
    /**
200
     * Returns an array describing an entity.
201
     *
202
     * @param EntityManager $em
203
     * @param object        $entity
204
     * @param mixed         $id
205
     *
206
     * @throws \Doctrine\DBAL\DBALException
207
     * @throws \Doctrine\ORM\Mapping\MappingException
208
     *
209
     * @return array
210
     */
211
    public function summarize(EntityManager $em, $entity = null, $id = null): ?array
212
    {
213
        if (null === $entity) {
214
            return null;
215
        }
216
217
        $em->getUnitOfWork()->initializeObject($entity); // ensure that proxies are initialized
218
        $meta = $em->getClassMetadata(\get_class($entity));
219
        $pkName = $meta->getSingleIdentifierFieldName();
220
        $pkValue = $id ?? $this->id($em, $entity);
221
222
        if (method_exists($entity, '__toString')) {
223
            $label = (string) $entity;
224
        } else {
225
            $label = \get_class($entity).'#'.$pkValue;
226
        }
227
228
        return [
229
            'label' => $label,
230
            'class' => $meta->name,
231
            'table' => $meta->getTableName(),
232
            $pkName => $pkValue,
233
        ];
234
    }
235
236
    /**
237
     * Return columns of audit tables.
238
     *
239
     * @return array
240
     */
241
    public function getAuditTableColumns(): array
242
    {
243
        return [
244
            'id' => [
245
                'type' => Type::INTEGER,
246
                'options' => [
247
                    'autoincrement' => true,
248
                    'unsigned' => true,
249
                ],
250
            ],
251
            'type' => [
252
                'type' => Type::STRING,
253
                'options' => [
254
                    'notnull' => true,
255
                    'length' => 10,
256
                ],
257
            ],
258
            'object_id' => [
259
                'type' => Type::STRING,
260
                'options' => [
261
                    'notnull' => true,
262
                ],
263
            ],
264
            'diffs' => [
265
                'type' => Type::JSON_ARRAY,
266
                'options' => [
267
                    'default' => null,
268
                    'notnull' => false,
269
                ],
270
            ],
271
            'blame_id' => [
272
                'type' => Type::INTEGER,
273
                'options' => [
274
                    'default' => null,
275
                    'notnull' => false,
276
                    'unsigned' => true,
277
                ],
278
            ],
279
            'blame_user' => [
280
                'type' => Type::STRING,
281
                'options' => [
282
                    'default' => null,
283
                    'notnull' => false,
284
                    'length' => 255,
285
                ],
286
            ],
287
            'blame_user_fqdn' => [
288
                'type' => Type::STRING,
289
                'options' => [
290
                    'default' => null,
291
                    'notnull' => false,
292
                    'length' => 255,
293
                ],
294
            ],
295
            'blame_user_firewall' => [
296
                'type' => Type::STRING,
297
                'options' => [
298
                    'default' => null,
299
                    'notnull' => false,
300
                    'length' => 100,
301
                ],
302
            ],
303
            'ip' => [
304
                'type' => Type::STRING,
305
                'options' => [
306
                    'default' => null,
307
                    'notnull' => false,
308
                    'length' => 45,
309
                ],
310
            ],
311
            'created_at' => [
312
                'type' => Type::DATETIME,
313
                'options' => [
314
                    'notnull' => true,
315
                ],
316
            ],
317
        ];
318
    }
319
320
    public function getAuditTableIndices(string $tablename): array
321
    {
322
        return [
323
            'id' => [
324
                'type' => 'primary',
325
            ],
326
            'type' => [
327
                'type' => 'index',
328
                'name' => 'type_'.md5($tablename).'_idx',
329
            ],
330
            'object_id' => [
331
                'type' => 'index',
332
                'name' => 'object_id_'.md5($tablename).'_idx',
333
            ],
334
            'blame_id' => [
335
                'type' => 'index',
336
                'name' => 'blame_id_'.md5($tablename).'_idx',
337
            ],
338
            'created_at' => [
339
                'type' => 'index',
340
                'name' => 'created_at_'.md5($tablename).'_idx',
341
            ],
342
        ];
343
    }
344
345
    public static function paramToNamespace(string $entity): string
346
    {
347
        return str_replace('-', '\\', $entity);
348
    }
349
350
    public static function namespaceToParam(string $entity): string
351
    {
352
        return str_replace('\\', '-', $entity);
353
    }
354
}
355