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

UpdateHelper::__construct()   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 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
        $expected = $this->manager->getHelper()->getAuditTableColumns();
99
        $processed = [];
100
101
        foreach ($columns as $column) {
102
            if (array_key_exists($column->getName(), $expected)) {
103
                // column is part of expected columns
104
                $table->dropColumn($column->getName());
105
                $table->addColumn($column->getName(), $expected[$column->getName()]['type'], $expected[$column->getName()]['options']);
106
            } else {
107
                // column is not part of expected columns so it has to be removed
108
                $table->dropColumn($column->getName());
109
            }
110
111
            $processed[] = $column->getName();
112
        }
113
114
        foreach ($expected as $column => $options) {
0 ignored issues
show
Comprehensibility Bug introduced by
$column is overwriting a variable from outer foreach loop.
Loading history...
115
            if (!\in_array($column, $processed, true)) {
116
                // expected column in not part of concrete ones so it's a new column, we need to add it
117
                $table->addColumn($column, $options['type'], $options['options']);
118
            }
119
        }
120
121
        $sql = $fromSchema->getMigrateToSql($toSchema, $schemaManager->getDatabasePlatform());
122
        foreach ($sql as $query) {
123
            try {
124
                $statement = $em->getConnection()->prepare($query);
125
                $statement->execute();
126
            } catch (\Exception $e) {
127
                throw new UpdateException(sprintf('Failed to update/fix "%s" audit table.', $table->getName()));
128
            }
129
        }
130
    }
131
}
132