This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php declare(strict_types=1); |
||
2 | |||
3 | namespace Limoncello\Application\Data; |
||
4 | |||
5 | /** |
||
6 | * Copyright 2015-2020 [email protected] |
||
7 | * |
||
8 | * Licensed under the Apache License, Version 2.0 (the "License"); |
||
9 | * you may not use this file except in compliance with the License. |
||
10 | * You may obtain a copy of the License at |
||
11 | * |
||
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
||
13 | * |
||
14 | * Unless required by applicable law or agreed to in writing, software |
||
15 | * distributed under the License is distributed on an "AS IS" BASIS, |
||
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||
17 | * See the License for the specific language governing permissions and |
||
18 | * limitations under the License. |
||
19 | */ |
||
20 | |||
21 | use DateTimeImmutable; |
||
22 | use Doctrine\DBAL\Connection; |
||
23 | use Doctrine\DBAL\DBALException; |
||
24 | use Doctrine\DBAL\Exception\InvalidArgumentException; |
||
25 | use Doctrine\DBAL\Schema\AbstractSchemaManager; |
||
26 | use Doctrine\DBAL\Schema\Table; |
||
27 | use Doctrine\DBAL\Types\Type; |
||
28 | use Error; |
||
29 | use Exception; |
||
30 | use Generator; |
||
31 | use Limoncello\Contracts\Commands\IoInterface; |
||
32 | use Limoncello\Contracts\Data\MigrationInterface; |
||
33 | use Psr\Container\ContainerExceptionInterface; |
||
34 | use Psr\Container\ContainerInterface; |
||
35 | use Psr\Container\NotFoundExceptionInterface; |
||
36 | use function array_diff; |
||
37 | use function array_reverse; |
||
38 | use function assert; |
||
39 | use function is_string; |
||
40 | |||
41 | /** |
||
42 | * @package Limoncello\Application |
||
43 | * |
||
44 | * @SuppressWarnings(PHPMD.CouplingBetweenObjects) |
||
45 | */ |
||
46 | abstract class BaseMigrationRunner |
||
47 | { |
||
48 | /** Migrations table name */ |
||
49 | const MIGRATIONS_TABLE = '_migrations'; |
||
50 | |||
51 | /** Migration column name */ |
||
52 | const MIGRATIONS_COLUMN_ID = 'id'; |
||
53 | |||
54 | /** Migration column name */ |
||
55 | const MIGRATIONS_COLUMN_CLASS = 'class'; |
||
56 | |||
57 | /** Migration column name */ |
||
58 | const MIGRATIONS_COLUMN_MIGRATED_AT = 'migrated_at'; |
||
59 | |||
60 | /** Seeds table name */ |
||
61 | const SEEDS_TABLE = '_seeds'; |
||
62 | |||
63 | /** |
||
64 | * @var IoInterface |
||
65 | */ |
||
66 | private $inOut; |
||
67 | |||
68 | /** |
||
69 | * @return string[] |
||
70 | 2 | */ |
|
71 | abstract protected function getMigrationClasses(): array; |
||
72 | 2 | ||
73 | /** |
||
74 | * @param IoInterface $inOut |
||
75 | */ |
||
76 | public function __construct(IoInterface $inOut) |
||
77 | { |
||
78 | $this->setIO($inOut); |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * @param ContainerInterface $container |
||
83 | * |
||
84 | 1 | * @return void |
|
85 | * |
||
86 | 1 | * @throws ContainerExceptionInterface |
|
87 | 1 | * @throws NotFoundExceptionInterface |
|
88 | 1 | * @throws DBALException |
|
89 | 1 | * |
|
90 | 1 | * @SuppressWarnings(PHPMD.IfStatementAssignment) |
|
91 | 1 | */ |
|
92 | public function migrate(ContainerInterface $container): void |
||
93 | { |
||
94 | foreach ($this->getMigrations($container) as $class) { |
||
95 | assert(is_string($class)); |
||
96 | $this->getIO()->writeInfo("Starting migration for `$class`..." . PHP_EOL, IoInterface::VERBOSITY_VERBOSE); |
||
97 | if (($migration = $this->createMigration($class, $container)) !== null) { |
||
98 | $migration->init($container)->migrate(); |
||
99 | $this->getIO()->writeInfo("Migration finished for `$class`." . PHP_EOL, IoInterface::VERBOSITY_NORMAL); |
||
100 | } |
||
101 | } |
||
102 | } |
||
103 | |||
104 | /** |
||
105 | * @param ContainerInterface $container |
||
106 | 1 | * |
|
107 | * @return void |
||
108 | 1 | * |
|
109 | 1 | * @throws ContainerExceptionInterface |
|
110 | 1 | * @throws InvalidArgumentException |
|
111 | 1 | * @throws NotFoundExceptionInterface |
|
112 | 1 | * @throws DBALException |
|
113 | 1 | * |
|
114 | * @SuppressWarnings(PHPMD.IfStatementAssignment) |
||
115 | */ |
||
116 | public function rollback(ContainerInterface $container): void |
||
117 | 1 | { |
|
118 | 1 | foreach ($this->getRollbacks($container) as $class) { |
|
119 | 1 | assert(is_string($class)); |
|
120 | $this->getIO()->writeInfo("Starting rollback for `$class`..." . PHP_EOL, IoInterface::VERBOSITY_VERBOSE); |
||
121 | 1 | if (($migration = $this->createMigration($class, $container)) !== null) { |
|
122 | 1 | $migration->init($container)->rollback(); |
|
123 | $this->getIO()->writeInfo("Rollback finished for `$class`." . PHP_EOL, IoInterface::VERBOSITY_NORMAL); |
||
124 | } |
||
125 | } |
||
126 | |||
127 | $manager = $this->getConnection($container)->getSchemaManager(); |
||
128 | if ($manager->tablesExist([static::MIGRATIONS_TABLE]) === true) { |
||
129 | 2 | $manager->dropTable(static::MIGRATIONS_TABLE); |
|
130 | } |
||
131 | 2 | if ($manager->tablesExist([static::SEEDS_TABLE]) === true) { |
|
132 | $manager->dropTable(static::SEEDS_TABLE); |
||
133 | } |
||
134 | } |
||
135 | |||
136 | /** |
||
137 | * @return IoInterface |
||
138 | */ |
||
139 | 3 | protected function getIO(): IoInterface |
|
140 | { |
||
141 | 3 | return $this->inOut; |
|
142 | } |
||
143 | 3 | ||
144 | /** |
||
145 | * @param IoInterface $inOut |
||
146 | * |
||
147 | * @return self |
||
148 | */ |
||
149 | private function setIO(IoInterface $inOut): self |
||
150 | { |
||
151 | $this->inOut = $inOut; |
||
152 | |||
153 | return $this; |
||
154 | } |
||
155 | |||
156 | /** |
||
157 | 1 | * @param ContainerInterface $container |
|
158 | * |
||
159 | 1 | * @return Generator |
|
160 | 1 | * |
|
161 | * @throws ContainerExceptionInterface |
||
162 | 1 | * @throws NotFoundExceptionInterface |
|
163 | 1 | * |
|
164 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
165 | 1 | * @throws DBALException |
|
166 | 1 | */ |
|
167 | private function getMigrations(ContainerInterface $container): Generator |
||
168 | { |
||
169 | 1 | $connection = $this->getConnection($container); |
|
170 | $manager = $connection->getSchemaManager(); |
||
171 | 1 | ||
172 | 1 | if ($manager->tablesExist([static::MIGRATIONS_TABLE]) === true) { |
|
173 | 1 | $migrated = $this->readMigrated($connection); |
|
174 | } else { |
||
175 | $this->createMigrationsTable($manager); |
||
176 | $migrated = []; |
||
177 | } |
||
178 | |||
179 | $notYetMigrated = array_diff($this->getMigrationClasses(), $migrated); |
||
180 | |||
181 | foreach ($notYetMigrated as $class) { |
||
182 | yield $class; |
||
183 | $this->saveMigration($connection, $class); |
||
184 | } |
||
185 | } |
||
186 | |||
187 | 1 | /** |
|
188 | * @param ContainerInterface $container |
||
189 | 1 | * |
|
190 | 1 | * @return Generator |
|
191 | * |
||
192 | 1 | * @throws ContainerExceptionInterface |
|
193 | 1 | * @throws NotFoundExceptionInterface |
|
194 | 1 | * @throws InvalidArgumentException |
|
195 | * @throws DBALException |
||
196 | */ |
||
197 | private function getRollbacks(ContainerInterface $container): Generator |
||
198 | { |
||
199 | $connection = $this->getConnection($container); |
||
200 | $migrated = $this->readMigrated($connection); |
||
201 | |||
202 | foreach (array_reverse($migrated, true) as $index => $class) { |
||
203 | yield $class; |
||
204 | $this->removeMigration($connection, $index); |
||
205 | } |
||
206 | 1 | } |
|
207 | |||
208 | 1 | /** |
|
209 | * @param ContainerInterface $container |
||
210 | * |
||
211 | * @return Connection |
||
212 | * |
||
213 | * @throws ContainerExceptionInterface |
||
214 | * @throws NotFoundExceptionInterface |
||
215 | */ |
||
216 | private function getConnection(ContainerInterface $container): Connection |
||
217 | { |
||
218 | 1 | return $container->get(Connection::class); |
|
219 | } |
||
220 | 1 | ||
221 | /** |
||
222 | * @param AbstractSchemaManager $manager |
||
223 | 1 | * |
|
224 | 1 | * @return void |
|
225 | 1 | * |
|
226 | * @throws DBALException |
||
227 | 1 | */ |
|
228 | 1 | private function createMigrationsTable(AbstractSchemaManager $manager): void |
|
229 | { |
||
230 | 1 | $table = new Table(static::MIGRATIONS_TABLE); |
|
231 | |||
232 | 1 | $table |
|
233 | 1 | ->addColumn(static::MIGRATIONS_COLUMN_ID, Type::INTEGER) |
|
0 ignored issues
–
show
|
|||
234 | ->setUnsigned(true) |
||
235 | 1 | ->setAutoincrement(true); |
|
236 | $table |
||
237 | ->addColumn(static::MIGRATIONS_COLUMN_CLASS, Type::STRING) |
||
0 ignored issues
–
show
The constant
Doctrine\DBAL\Types\Type::STRING has been deprecated with message: Use {@see Types::STRING} instead.
This class constant has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead. ![]() |
|||
238 | ->setLength(255); |
||
239 | $table |
||
240 | ->addColumn(static::MIGRATIONS_COLUMN_MIGRATED_AT, Type::DATETIME); |
||
0 ignored issues
–
show
The constant
Doctrine\DBAL\Types\Type::DATETIME has been deprecated with message: Use {@see Types::DATETIME_MUTABLE} instead.
This class constant has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead. ![]() |
|||
241 | |||
242 | $table->setPrimaryKey([static::MIGRATIONS_COLUMN_ID]); |
||
243 | 1 | $table->addUniqueIndex([static::MIGRATIONS_COLUMN_CLASS]); |
|
244 | |||
245 | 1 | $manager->createTable($table); |
|
246 | 1 | } |
|
247 | |||
248 | 1 | /** |
|
249 | * @param Connection $connection |
||
250 | 1 | * |
|
251 | 1 | * @return array |
|
252 | 1 | */ |
|
253 | 1 | private function readMigrated(Connection $connection): array |
|
254 | 1 | { |
|
255 | 1 | $builder = $connection->createQueryBuilder(); |
|
256 | 1 | $migrated = []; |
|
257 | 1 | ||
258 | 1 | if ($connection->getSchemaManager()->tablesExist([static::MIGRATIONS_TABLE]) === true) { |
|
259 | $migrations = $builder |
||
260 | ->select(static::MIGRATIONS_COLUMN_ID, static::MIGRATIONS_COLUMN_CLASS) |
||
261 | ->from(static::MIGRATIONS_TABLE) |
||
262 | 1 | ->orderBy(static::MIGRATIONS_COLUMN_ID) |
|
263 | ->execute() |
||
264 | ->fetchAll(); |
||
265 | foreach ($migrations as $migration) { |
||
266 | $index = $migration[static::MIGRATIONS_COLUMN_ID]; |
||
267 | $class = $migration[static::MIGRATIONS_COLUMN_CLASS]; |
||
268 | $migrated[$index] = $class; |
||
269 | } |
||
270 | } |
||
271 | |||
272 | return $migrated; |
||
273 | } |
||
274 | 1 | ||
275 | /** |
||
276 | 1 | * @param Connection $connection |
|
277 | 1 | * @param string $class |
|
278 | 1 | * |
|
279 | 1 | * @return void |
|
280 | 1 | * |
|
281 | * @throws DBALException |
||
282 | * @throws Exception |
||
283 | */ |
||
284 | private function saveMigration(Connection $connection, string $class): void |
||
285 | { |
||
286 | $format = $connection->getSchemaManager()->getDatabasePlatform()->getDateTimeFormatString(); |
||
287 | $now = (new DateTimeImmutable())->format($format); |
||
288 | $connection->insert(static::MIGRATIONS_TABLE, [ |
||
289 | static::MIGRATIONS_COLUMN_CLASS => $class, |
||
290 | static::MIGRATIONS_COLUMN_MIGRATED_AT => $now, |
||
291 | ]); |
||
292 | } |
||
293 | |||
294 | 1 | /** |
|
295 | * @param Connection $connection |
||
296 | 1 | * @param int $index |
|
297 | * |
||
298 | * @return void |
||
299 | * |
||
300 | * @throws InvalidArgumentException |
||
301 | * |
||
302 | * @throws DBALException |
||
303 | */ |
||
304 | private function removeMigration(Connection $connection, int $index): void |
||
305 | 2 | { |
|
306 | $connection->delete(static::MIGRATIONS_TABLE, [static::MIGRATIONS_COLUMN_ID => $index]); |
||
307 | 2 | } |
|
308 | |||
309 | /** |
||
310 | * @param string $class |
||
311 | 2 | * @param ContainerInterface $container |
|
312 | 1 | * |
|
313 | 1 | * @return MigrationInterface|null |
|
314 | */ |
||
315 | private function createMigration(string $class, ContainerInterface $container): ?MigrationInterface |
||
316 | 2 | { |
|
317 | $migration = null; |
||
318 | |||
319 | try { |
||
320 | /** @var MigrationInterface $migration */ |
||
321 | $migration = new $class($container); |
||
322 | } catch (Error $exception) { |
||
323 | $this->getIO()->writeWarning("Migration `$class` not found." . PHP_EOL); |
||
324 | } |
||
325 | |||
326 | return $migration; |
||
327 | } |
||
328 | } |
||
329 |
This class constant has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.