SchemaSynchronizer   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 78
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 43
c 4
b 0
f 0
dl 0
loc 78
rs 10
wmc 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A updateTable() 0 16 4
A ensureTableExists() 0 13 2
A generateTable() 0 20 3
A __construct() 0 14 1
1
<?php
2
3
namespace Avoran\RapidoAdapter\DoctrineDbalStorage;
4
5
use Avoran\Rapido\ReadModel\DataType\DateTime;
6
use Avoran\Rapido\ReadModel\ReadModelConfiguration;
7
use Avoran\Rapido\ReadModel\ReadModelField;
8
use Doctrine\DBAL\Schema\AbstractSchemaManager;
9
use Doctrine\DBAL\Schema\Comparator;
10
use Doctrine\DBAL\Schema\Index;
11
use Doctrine\DBAL\Schema\Table;
12
13
class SchemaSynchronizer
14
{
15
    private $schemaManager;
16
    private $schemaComparator;
17
    private $tableNameGenerator;
18
    private $idColumnName;
19
    private $columnFactory;
20
21
    public function __construct
22
    (
23
        AbstractSchemaManager $schemaManager,
24
        Comparator $schemaComparator,
25
        NameGenerator $tableNameGenerator,
26
        $idColumnName,
27
        ColumnFactory $columnFactory
28
    )
29
    {
30
        $this->schemaManager = $schemaManager;
31
        $this->schemaComparator = $schemaComparator;
32
        $this->tableNameGenerator = $tableNameGenerator;
33
        $this->idColumnName = $idColumnName;
34
        $this->columnFactory = $columnFactory;
35
    }
36
37
    public function ensureTableExists(ReadModelConfiguration $metadata)
38
    {
39
        $table = $this->generateTable($metadata);
40
        $table->setPrimaryKey([$this->idColumnName]);
41
42
        $this->updateTable($table);
43
44
        if (!$metadata->generateSnapshot()) return;
45
46
        $table = $this->generateTable($metadata, true);
47
        $table->setPrimaryKey([$this->idColumnName, $metadata->getSnapshotColumnName()]);
48
49
        $this->updateTable($table);
50
    }
51
52
    private function generateTable(ReadModelConfiguration $metadata, $snapshot = false)
53
    {
54
        $predefinedColumns = [$this->columnFactory->createColumn($metadata->getId()->getDataType(), $this->idColumnName)];
55
        $name = $this->tableNameGenerator->generate($metadata->getName());
56
57
        if ($snapshot) {
58
            $predefinedColumns[] = $this->columnFactory->createColumn(new DateTime(), $metadata->getSnapshotColumnName());
59
            $name = $this->tableNameGenerator->generateWithSuffix($metadata->getName());
60
            $indices = [new Index(sprintf('IDX_%s', $metadata->getSnapshotColumnName()), [$metadata->getSnapshotColumnName()])];
61
        } else {
62
            $indices = [new Index(sprintf('IDX_%s', $this->idColumnName), [$this->idColumnName])];
63
        }
64
65
        return new Table($name,
66
            array_merge($predefinedColumns, array_map(function(ReadModelField $field) use (&$indices) {
67
                if ($field->useIndex()) $indices[] = new Index(sprintf('IDX_%s', $field->getId()), [$field->getId()]);
68
69
                return $this->columnFactory->createColumn($field->getDataType(), $field->getId());
70
            }, $metadata->getFields())),
71
            $indices
72
        );
73
    }
74
75
    private function updateTable(Table $table)
76
    {
77
        $existingTables = array_filter(
78
            $this->schemaManager->listTables(),
79
            function(Table $existingTable) use ($table) { return $table->getName() == $existingTable->getName(); }
80
        );
81
82
        if (count($existingTables) > 1)
83
            throw new \UnexpectedValueException(sprintf("Multiple tables with the name '%s' exist.", $table->getName()));
84
85
        if (count($existingTables) == 1) {
86
            $tableDiff = $this->schemaComparator->diffTable(current($existingTables), $table);
87
            if ($tableDiff)
88
                $this->schemaManager->alterTable($tableDiff);
89
        } else {
90
            $this->schemaManager->createTable($table);
91
        }
92
    }
93
}
94