Passed
Pull Request — master (#51)
by Damien
02:10
created

UpdateHelper   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 128
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 56
dl 0
loc 128
rs 10
c 0
b 0
f 0
wmc 18

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getConfiguration() 0 3 1
B createAuditTable() 0 33 7
A __construct() 0 3 1
B updateAuditTable() 0 51 9
1
<?php
2
3
namespace DH\DoctrineAuditBundle\Helper;
4
5
use DH\DoctrineAuditBundle\AuditConfiguration;
6
use DH\DoctrineAuditBundle\AuditManager;
7
use DH\DoctrineAuditBundle\Exception\UpdateException;
8
use Doctrine\DBAL\Schema\AbstractSchemaManager;
9
use Doctrine\DBAL\Schema\Column;
10
use Doctrine\DBAL\Schema\Schema;
11
use Doctrine\DBAL\Schema\Table;
12
use Doctrine\ORM\EntityManager;
13
14
class UpdateHelper
15
{
16
    /**
17
     * @var AuditManager
18
     */
19
    private $manager;
20
21
    /**
22
     * @param AuditManager $manager
23
     */
24
    public function __construct(AuditManager $manager)
25
    {
26
        $this->manager = $manager;
27
    }
28
29
    /**
30
     * @return \DH\DoctrineAuditBundle\AuditConfiguration
31
     */
32
    public function getConfiguration(): AuditConfiguration
33
    {
34
        return $this->manager->getConfiguration();
35
    }
36
37
    /**
38
     * Creates an audit table.
39
     *
40
     * @param Schema $schema
41
     * @param Table  $table
42
     */
43
    public function createAuditTable(Schema $schema, Table $table): void
44
    {
45
        $entityTablename = $table->getName();
46
        $regex = sprintf('#^(%s\.)(.*)$#', preg_quote($schema->getName(), '#'));
47
        if (preg_match($regex, $entityTablename)) {
48
            // entityTablename already prefixed with schema name
49
            $auditTablename = preg_replace(
50
                $regex,
51
                sprintf(
52
                    '$1%s$2%s',
53
                    preg_quote($this->getConfiguration()->getTablePrefix(), '#'),
54
                    preg_quote($this->getConfiguration()->getTableSuffix(), '#')
55
                ),
56
                $entityTablename
57
            );
58
        } else {
59
            $auditTablename = $this->getConfiguration()->getTablePrefix().$table->getName().$this->getConfiguration()->getTableSuffix();
60
        }
61
62
        if (null !== $auditTablename && !$schema->hasTable($auditTablename)) {
63
            $auditTable = $schema->createTable($auditTablename);
64
65
            // Add columns to audit table
66
            foreach ($this->manager->getHelper()->getAuditTableColumns() as $name => $struct) {
67
                $auditTable->addColumn($name, $struct['type'], $struct['options']);
68
            }
69
70
            // Add indices to audit table
71
            foreach ($this->manager->getHelper()->getAuditTableIndices($auditTablename) as $column => $struct) {
72
                if ('primary' === $struct['type']) {
73
                    $auditTable->setPrimaryKey([$column]);
74
                } else {
75
                    $auditTable->addIndex([$column], $struct['name']);
76
                }
77
            }
78
        }
79
    }
80
81
    /**
82
     * Ensures an audit table's structure is valid.
83
     *
84
     * @param AbstractSchemaManager $schemaManager
85
     * @param Table                 $table
86
     * @param EntityManager         $em
87
     *
88
     * @throws UpdateException
89
     * @throws \Doctrine\DBAL\Schema\SchemaException
90
     */
91
    public function updateAuditTable(AbstractSchemaManager $schemaManager, Table $table, EntityManager $em): void
92
    {
93
        $fromSchema = $schemaManager->createSchema();
94
        $toSchema = clone $fromSchema;
95
96
        $table = $toSchema->getTable($table->getName());
97
        $columns = $schemaManager->listTableColumns($table->getName());
98
        $expectedColumns = $this->manager->getHelper()->getAuditTableColumns();
99
        $expectedIndices = $this->manager->getHelper()->getAuditTableIndices($table->getName());
100
        $processed = [];
101
102
        // process columns
103
        foreach ($columns as $column) {
104
            if (array_key_exists($column->getName(), $expectedColumns)) {
105
                // column is part of expected columns
106
                $table->dropColumn($column->getName());
107
                $table->addColumn($column->getName(), $expectedColumns[$column->getName()]['type'], $expectedColumns[$column->getName()]['options']);
108
            } else {
109
                // column is not part of expected columns so it has to be removed
110
                $table->dropColumn($column->getName());
111
            }
112
113
            $processed[] = $column->getName();
114
        }
115
116
        foreach ($expectedColumns as $column => $options) {
0 ignored issues
show
Comprehensibility Bug introduced by
$column is overwriting a variable from outer foreach loop.
Loading history...
117
            if (!\in_array($column, $processed, true)) {
118
                // expected column in not part of concrete ones so it's a new column, we need to add it
119
                $table->addColumn($column, $options['type'], $options['options']);
120
            }
121
        }
122
123
        // process indices
124
        foreach ($expectedIndices as $column => $options) {
0 ignored issues
show
Comprehensibility Bug introduced by
$options is overwriting a variable from outer foreach loop.
Loading history...
Comprehensibility Bug introduced by
$column is overwriting a variable from outer foreach loop.
Loading history...
125
            if ('primary' === $options['type']) {
126
                $table->dropPrimaryKey();
127
                $table->setPrimaryKey([$column]);
128
            } else {
129
                $table->dropIndex($options['name']);
130
                $table->addIndex([$column], $options['name']);
131
            }
132
        }
133
134
        // apply changes
135
        $sql = $fromSchema->getMigrateToSql($toSchema, $schemaManager->getDatabasePlatform());
136
        foreach ($sql as $query) {
137
            try {
138
                $statement = $em->getConnection()->prepare($query);
139
                $statement->execute();
140
            } catch (\Exception $e) {
141
                throw new UpdateException(sprintf('Failed to update/fix "%s" audit table.', $table->getName()));
142
            }
143
        }
144
    }
145
}
146