Issues (590)

src/Schema/RepositoryUpgrader.php (2 issues)

Labels
Severity
1
<?php
2
3
namespace Bdf\Prime\Schema;
4
5
use Bdf\Prime\Connection\ConnectionInterface;
6
use Bdf\Prime\Exception\DBALException;
7
use Bdf\Prime\Exception\PrimeException;
8
use Bdf\Prime\Schema\Adapter\ConstraintTable;
9
use Bdf\Prime\Schema\Adapter\MapperInfo\MapperInfoConstraintSet;
10
use Bdf\Prime\Schema\Adapter\MapperInfo\Resolver\MapperInfoForeignKeyResolver;
11
use Bdf\Prime\Schema\Adapter\Metadata\MetadataTable;
12
use Bdf\Prime\Schema\Builder\TableBuilder;
13
use Bdf\Prime\ServiceLocator;
14
use Bdf\Prime\Mapper\Metadata;
15
use Doctrine\DBAL\Exception\TableNotFoundException;
16
17
/**
18
 * Handle structure migration of repository tables
19
 *
20
 * @todo gestion du renommage de champs dans le cas où d'autres attributs ont été changés
21
 */
22
class RepositoryUpgrader implements StructureUpgraderInterface
23
{
24
    /**
25
     * @var ServiceLocator
26
     */
27
    protected $service;
28
29
    /**
30
     * @var Metadata
31
     */
32
    protected $metadata;
33
34
    /**
35
     * @var SchemaManagerInterface
36
     */
37
    protected $schema;
38
39
40
    /**
41
     * @param ServiceLocator $service Prime service
42
     * @param Metadata $metadata The entity metadata
43
     * @param SchemaManagerInterface|null $schema If given, force using this schema manager instead of resolving using the configured connection name
44
     */
45 871
    public function __construct(ServiceLocator $service, Metadata $metadata, SchemaManagerInterface $schema = null)
46
    {
47 871
        $this->service  = $service;
48 871
        $this->metadata = $metadata;
49 871
        $this->schema   = $schema;
50
    }
51
52
    /**
53
     * {@inheritdoc}
54
     */
55 861
    public function migrate(bool $listDrop = true): void
56
    {
57 861
        $schema = $this->schema()->useDrop($listDrop);
58 861
        $schema->add($this->table());
59
60 861
        if (($schemaSequence = $this->schemaSequence()) !== null) {
61 524
            $schemaSequence->useDrop($listDrop);
62 524
            $schemaSequence->add($this->sequence());
63
64 524
            $this->insertSequenceId();
65
        }
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71 6
    public function diff(bool $listDrop = true): array
72
    {
73 6
        $queries = $this->schema()
74 6
            ->simulate(function (SchemaManagerInterface $schema) use ($listDrop) {
75 6
                $schema->useDrop($listDrop);
76 6
                $schema->add($this->table());
77 6
            })
78 6
            ->pending();
79
80 6
        if (($schemaSequence = $this->schemaSequence()) === null) {
81 5
            return $queries;
82
        }
83
84 1
        $sequenceQueries = $schemaSequence
85 1
            ->simulate(function (SchemaManagerInterface $schema) use ($listDrop) {
86 1
                $schema->useDrop($listDrop);
87 1
                $schema->add($this->sequence());
88 1
            })
89 1
            ->pending();
90
91 1
        return array_merge($queries, $sequenceQueries);
92
    }
93
94
    /**
95
     * Create table schema from meta
96
     *
97
     * @param bool $foreignKeys Add foreign key constraints to the schema ?
98
     *
99
     * @return TableInterface
100
     * @throws PrimeException
101
     */
102 867
    public function table(bool $foreignKeys = false): TableInterface
103
    {
104 867
        $table = new MetadataTable(
105 867
            $this->metadata,
106 867
            $this->connection()->platform()->types()
107 867
        );
108
109 867
        if ($foreignKeys) {
110 1
            $table = new ConstraintTable(
111 1
                $table,
112 1
                new MapperInfoConstraintSet(
113 1
                    $this->service->repository($this->metadata->entityName)->mapper()->info(),
114 1
                    [
115 1
                        new MapperInfoForeignKeyResolver($this->service)
116 1
                    ]
117 1
                )
118 1
            );
119
        }
120
121 867
        return $table;
122
    }
123
124
    /**
125
     * Create sequence schema from meta
126
     *
127
     * @return null|TableInterface The table or null if the current repository has no sequence
128
     * @throws PrimeException
129
     */
130 527
    public function sequence(): ?TableInterface
131
    {
132 527
        if (!$this->metadata->isSequencePrimaryKey()) {
133 1
            return null;
134
        }
135
136 526
        $table = new TableBuilder($this->metadata->sequence['table']);
137 526
        $table->options($this->metadata->sequence['options']);
138 526
        $table->add(
139 526
            $this->metadata->sequence['column'],
140 526
            $this->connection($this->metadata->sequence['connection'])->platform()->types()->native('bigint')
141 526
        );
142 526
        $table->primary($this->metadata->sequence['column']);
143
144 526
        return $table->build();
145
    }
146
147
    /**
148
     * Insert sequence id into sequence table
149
     *
150
     * @throws PrimeException
151
     *
152
     * @return void
153
     */
154 524
    public function insertSequenceId(): void
155
    {
156 524
        if (!$this->metadata->isSequencePrimaryKey()) {
157
            return;
158
        }
159
160
        /** @var ConnectionInterface&\Doctrine\DBAL\Connection $connection */
161 524
        $connection = $this->connection($this->metadata->sequence['connection']);
162 524
        $table  = $this->metadata->sequence['table'];
163
164
        /** @psalm-suppress UndefinedInterfaceMethod */
165 524
        $nb = $connection->from($table)->count();
0 ignored issues
show
The method count() does not exist on Bdf\Prime\Query\ReadCommandInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Bdf\Prime\Query\QueryInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

165
        $nb = $connection->from($table)->/** @scrutinizer ignore-call */ count();
Loading history...
166
167 524
        if ($nb == 0) {
168 524
            $connection->insert($table, [$this->metadata->sequence['column'] => 0]);
0 ignored issues
show
The method insert() does not exist on Bdf\Prime\Connection\ConnectionInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Bdf\Prime\Connection\ConnectionInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

168
            $connection->/** @scrutinizer ignore-call */ 
169
                         insert($table, [$this->metadata->sequence['column'] => 0]);
Loading history...
169
        }
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175 1
    public function truncate(bool $cascade = false): bool
176
    {
177 1
        $this->schema()->truncate($this->metadata->table, $cascade);
178
179 1
        return true;
180
    }
181
182
    /**
183
     * {@inheritdoc}
184
     */
185 812
    public function drop(): bool
186
    {
187
        try {
188 812
            $this->schema()->drop($this->metadata->table);
189
190 808
            if (($schemaSequence = $this->schemaSequence()) !== null) {
191 516
                $schemaSequence->drop($this->metadata->sequence['table']);
192
            }
193
194 808
            return true;
195 61
        } catch (DBALException $e) {
196 61
            if ($e->getPrevious() instanceof TableNotFoundException) {
197 61
                return false;
198
            }
199
200
            throw $e;
201
        }
202
    }
203
204
    /**
205
     * Get the schema builder
206
     *
207
     * @return SchemaManagerInterface
208
     * @throws PrimeException
209
     */
210 865
    protected function schema()
211
    {
212 865
        if ($this->schema !== null) {
213
            return $this->schema;
214
        }
215
216 865
        return $this->connection()->schema();
217
    }
218
219
    /**
220
     * Get the schema builder for sequence
221
     *
222
     * @return SchemaManagerInterface|null
223
     * @throws PrimeException
224
     */
225 863
    protected function schemaSequence()
226
    {
227 863
        if (!$this->metadata->isSequencePrimaryKey()) {
228 855
            return null;
229
        }
230
231 525
        if ($this->schema !== null) {
232
            return $this->schema;
233
        }
234
235 525
        return $this->connection($this->metadata->sequence['connection'])->schema();
236
    }
237
238
    /**
239
     * Get the connection
240
     *
241
     * @param string $profile
242
     *
243
     * @return ConnectionInterface
244
     */
245 870
    protected function connection($profile = null)
246
    {
247 870
        return $this->service->connection($profile ?: $this->metadata->connection);
248
    }
249
}
250