Passed
Pull Request — master (#90)
by Damien
02:52
created

AuditManager::getHelper()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace DH\DoctrineAuditBundle\Manager;
4
5
use DH\DoctrineAuditBundle\AuditConfiguration;
6
use DH\DoctrineAuditBundle\Helper\AuditHelper;
7
use Doctrine\ORM\EntityManager;
8
use Doctrine\ORM\EntityManagerInterface;
9
use Doctrine\ORM\Mapping\ClassMetadata;
10
11
class AuditManager
12
{
13
    /**
14
     * @var \DH\DoctrineAuditBundle\AuditConfiguration
15
     */
16
    private $configuration;
17
18
    /**
19
     * @var AuditHelper
20
     */
21
    private $helper;
22
23
    public function __construct(AuditConfiguration $configuration, AuditHelper $helper)
24
    {
25
        $this->configuration = $configuration;
26
        $this->helper = $helper;
27
    }
28
29
    /**
30
     * @return \DH\DoctrineAuditBundle\AuditConfiguration
31
     */
32
    public function getConfiguration(): AuditConfiguration
33
    {
34
        return $this->configuration;
35
    }
36
37
    /**
38
     * @param AuditTransaction $transaction
39
     *
40
     * @throws \Doctrine\DBAL\DBALException
41
     * @throws \Doctrine\ORM\Mapping\MappingException
42
     */
43
    public function process(AuditTransaction $transaction): void
44
    {
45
        $this->processInsertions($transaction);
46
        $this->processUpdates($transaction);
47
        $this->processAssociations($transaction);
48
        $this->processDissociations($transaction);
49
        $this->processDeletions($transaction);
50
    }
51
52
    /**
53
     * Adds an insert entry to the audit table.
54
     *
55
     * @param EntityManager $em
56
     * @param object        $entity
57
     * @param array         $ch
58
     * @param string        $transactionHash
59
     *
60
     * @throws \Doctrine\DBAL\DBALException
61
     * @throws \Doctrine\ORM\Mapping\MappingException
62
     */
63
    public function insert(EntityManager $em, $entity, array $ch, string $transactionHash): void
64
    {
65
        $meta = $em->getClassMetadata(\get_class($entity));
66
        $this->audit($em, [
67
            'action' => 'insert',
68
            'blame' => $this->helper->blame(),
69
            'diff' => $this->helper->diff($em, $entity, $ch),
70
            'table' => $meta->getTableName(),
71
            'schema' => $meta->getSchemaName(),
72
            'id' => $this->helper->id($em, $entity),
73
            'transaction_hash' => $transactionHash,
74
            'discriminator' => ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE === $meta->inheritanceType ? \get_class($entity) : null,
75
        ]);
76
    }
77
78
    /**
79
     * Adds an update entry to the audit table.
80
     *
81
     * @param EntityManager $em
82
     * @param object        $entity
83
     * @param array         $ch
84
     * @param string        $transactionHash
85
     *
86
     * @throws \Doctrine\DBAL\DBALException
87
     * @throws \Doctrine\ORM\Mapping\MappingException
88
     */
89
    public function update(EntityManager $em, $entity, array $ch, string $transactionHash): void
90
    {
91
        $diff = $this->helper->diff($em, $entity, $ch);
92
        if (0 === \count($diff)) {
93
            return; // if there is no entity diff, do not log it
94
        }
95
        $meta = $em->getClassMetadata(\get_class($entity));
96
        $this->audit($em, [
97
            'action' => 'update',
98
            'blame' => $this->helper->blame(),
99
            'diff' => $diff,
100
            'table' => $meta->getTableName(),
101
            'schema' => $meta->getSchemaName(),
102
            'id' => $this->helper->id($em, $entity),
103
            'transaction_hash' => $transactionHash,
104
            'discriminator' => ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE === $meta->inheritanceType ? \get_class($entity) : null,
105
        ]);
106
    }
107
108
    /**
109
     * Adds a remove entry to the audit table.
110
     *
111
     * @param EntityManager $em
112
     * @param object        $entity
113
     * @param mixed         $id
114
     * @param string        $transactionHash
115
     *
116
     * @throws \Doctrine\DBAL\DBALException
117
     * @throws \Doctrine\ORM\Mapping\MappingException
118
     */
119
    public function remove(EntityManager $em, $entity, $id, string $transactionHash): void
120
    {
121
        $meta = $em->getClassMetadata(\get_class($entity));
122
        $this->audit($em, [
123
            'action' => 'remove',
124
            'blame' => $this->helper->blame(),
125
            'diff' => $this->helper->summarize($em, $entity, $id),
126
            'table' => $meta->getTableName(),
127
            'schema' => $meta->getSchemaName(),
128
            'id' => $id,
129
            'transaction_hash' => $transactionHash,
130
            'discriminator' => ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE === $meta->inheritanceType ? \get_class($entity) : null,
131
        ]);
132
    }
133
134
    /**
135
     * Adds an association entry to the audit table.
136
     *
137
     * @param EntityManager $em
138
     * @param object        $source
139
     * @param object        $target
140
     * @param array         $mapping
141
     * @param string        $transactionHash
142
     *
143
     * @throws \Doctrine\DBAL\DBALException
144
     * @throws \Doctrine\ORM\Mapping\MappingException
145
     */
146
    public function associate(EntityManager $em, $source, $target, array $mapping, string $transactionHash): void
147
    {
148
        $this->associateOrDissociate('associate', $em, $source, $target, $mapping, $transactionHash);
149
    }
150
151
    /**
152
     * Adds a dissociation entry to the audit table.
153
     *
154
     * @param EntityManager $em
155
     * @param object        $source
156
     * @param object        $target
157
     * @param array         $mapping
158
     * @param string        $transactionHash
159
     *
160
     * @throws \Doctrine\DBAL\DBALException
161
     * @throws \Doctrine\ORM\Mapping\MappingException
162
     */
163
    public function dissociate(EntityManager $em, $source, $target, array $mapping, string $transactionHash): void
164
    {
165
        $this->associateOrDissociate('dissociate', $em, $source, $target, $mapping, $transactionHash);
166
    }
167
168
    /**
169
     * Adds an association entry to the audit table.
170
     *
171
     * @param string        $type
172
     * @param EntityManager $em
173
     * @param object        $source
174
     * @param object        $target
175
     * @param array         $mapping
176
     * @param string        $transactionHash
177
     *
178
     * @throws \Doctrine\DBAL\DBALException
179
     * @throws \Doctrine\ORM\Mapping\MappingException
180
     */
181
    private function associateOrDissociate(string $type, EntityManager $em, $source, $target, array $mapping, string $transactionHash): void
182
    {
183
        $meta = $em->getClassMetadata(\get_class($source));
184
        $data = [
185
            'action' => $type,
186
            'blame' => $this->helper->blame(),
187
            'diff' => [
188
                'source' => $this->helper->summarize($em, $source),
189
                'target' => $this->helper->summarize($em, $target),
190
            ],
191
            'table' => $meta->getTableName(),
192
            'schema' => $meta->getSchemaName(),
193
            'id' => $this->helper->id($em, $source),
194
            'transaction_hash' => $transactionHash,
195
            'discriminator' => ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE === $meta->inheritanceType ? \get_class($source) : null,
196
        ];
197
198
        if (isset($mapping['joinTable']['name'])) {
199
            $data['diff']['table'] = $mapping['joinTable']['name'];
200
        }
201
202
        $this->audit($em, $data);
203
    }
204
205
    /**
206
     * Adds an entry to the audit table.
207
     *
208
     * @param EntityManager $em
209
     * @param array         $data
210
     *
211
     * @throws \Doctrine\DBAL\DBALException
212
     */
213
    private function audit(EntityManager $em, array $data): void
214
    {
215
        $schema = $data['schema'] ? $data['schema'].'.' : '';
216
        $auditTable = $schema.$this->configuration->getTablePrefix().$data['table'].$this->configuration->getTableSuffix();
217
        $fields = [
218
            'type' => ':type',
219
            'object_id' => ':object_id',
220
            'discriminator' => ':discriminator',
221
            'transaction_hash' => ':transaction_hash',
222
            'diffs' => ':diffs',
223
            'blame_id' => ':blame_id',
224
            'blame_user' => ':blame_user',
225
            'blame_user_fqdn' => ':blame_user_fqdn',
226
            'blame_user_firewall' => ':blame_user_firewall',
227
            'ip' => ':ip',
228
            'created_at' => ':created_at',
229
        ];
230
231
        $query = sprintf(
232
            'INSERT INTO %s (%s) VALUES (%s)',
233
            $auditTable,
234
            implode(', ', array_keys($fields)),
235
            implode(', ', array_values($fields))
236
        );
237
238
        $storage = $this->selectStorageSpace($em);
239
        $statement = $storage->getConnection()->prepare($query);
240
241
        $dt = new \DateTime('now', new \DateTimeZone($this->getConfiguration()->getTimezone()));
242
        $statement->bindValue('type', $data['action']);
243
        $statement->bindValue('object_id', (string) $data['id']);
244
        $statement->bindValue('discriminator', $data['discriminator']);
245
        $statement->bindValue('transaction_hash', (string) $data['transaction_hash']);
246
        $statement->bindValue('diffs', json_encode($data['diff']));
247
        $statement->bindValue('blame_id', $data['blame']['user_id']);
248
        $statement->bindValue('blame_user', $data['blame']['username']);
249
        $statement->bindValue('blame_user_fqdn', $data['blame']['user_fqdn']);
250
        $statement->bindValue('blame_user_firewall', $data['blame']['user_firewall']);
251
        $statement->bindValue('ip', $data['blame']['client_ip']);
252
        $statement->bindValue('created_at', $dt->format('Y-m-d H:i:s'));
253
        $statement->execute();
254
    }
255
256
    /**
257
     * Set the value of helper.
258
     *
259
     * @param AuditHelper $helper
260
     */
261
    public function setHelper(AuditHelper $helper): void
262
    {
263
        $this->helper = $helper;
264
    }
265
266
    /**
267
     * Get the value of helper.
268
     *
269
     * @return AuditHelper
270
     */
271
    public function getHelper(): AuditHelper
272
    {
273
        return $this->helper;
274
    }
275
276
    /**
277
     * @param AuditTransaction $transaction
278
     *
279
     * @throws \Doctrine\DBAL\DBALException
280
     * @throws \Doctrine\ORM\Mapping\MappingException
281
     */
282
    public function processInsertions(AuditTransaction $transaction): void
283
    {
284
        $em = $transaction->getEntityManager();
285
        $uow = $em->getUnitOfWork();
286
        foreach ($transaction->getInserted() as list($entity, $ch)) {
287
            // the changeset might be updated from UOW extra updates
288
            $ch = array_merge($ch, $uow->getEntityChangeSet($entity));
289
            $this->insert($em, $entity, $ch, $transaction->getTransactionHash());
290
        }
291
    }
292
293
    /**
294
     * @param AuditTransaction $transaction
295
     *
296
     * @throws \Doctrine\DBAL\DBALException
297
     * @throws \Doctrine\ORM\Mapping\MappingException
298
     */
299
    public function processUpdates(AuditTransaction $transaction): void
300
    {
301
        $em = $transaction->getEntityManager();
302
        $uow = $em->getUnitOfWork();
303
        foreach ($transaction->getUpdated() as list($entity, $ch)) {
304
            // the changeset might be updated from UOW extra updates
305
            $ch = array_merge($ch, $uow->getEntityChangeSet($entity));
306
            $this->update($em, $entity, $ch, $transaction->getTransactionHash());
307
        }
308
    }
309
310
    /**
311
     * @param AuditTransaction $transaction
312
     *
313
     * @throws \Doctrine\DBAL\DBALException
314
     * @throws \Doctrine\ORM\Mapping\MappingException
315
     */
316
    public function processAssociations(AuditTransaction $transaction): void
317
    {
318
        $em = $transaction->getEntityManager();
319
        foreach ($transaction->getAssociated() as list($source, $target, $mapping)) {
320
            $this->associate($em, $source, $target, $mapping, $transaction->getTransactionHash());
321
        }
322
    }
323
324
    /**
325
     * @param AuditTransaction $transaction
326
     *
327
     * @throws \Doctrine\DBAL\DBALException
328
     * @throws \Doctrine\ORM\Mapping\MappingException
329
     */
330
    public function processDissociations(AuditTransaction $transaction): void
331
    {
332
        $em = $transaction->getEntityManager();
333
        foreach ($transaction->getDissociated() as list($source, $target, $id, $mapping)) {
334
            $this->dissociate($em, $source, $target, $mapping, $transaction->getTransactionHash());
335
        }
336
    }
337
338
    /**
339
     * @param AuditTransaction $transaction
340
     *
341
     * @throws \Doctrine\DBAL\DBALException
342
     * @throws \Doctrine\ORM\Mapping\MappingException
343
     */
344
    public function processDeletions(AuditTransaction $transaction): void
345
    {
346
        $em = $transaction->getEntityManager();
347
        foreach ($transaction->getRemoved() as list($entity, $id)) {
348
            $this->remove($em, $entity, $id, $transaction->getTransactionHash());
349
        }
350
    }
351
352
    /**
353
     * @param EntityManagerInterface $em
354
     *
355
     * @return EntityManagerInterface
356
     */
357
    private function selectStorageSpace(EntityManagerInterface $em): EntityManagerInterface
358
    {
359
        return $this->configuration->getEntityManager() ?? $em;
360
    }
361
}
362