1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of the eZ Publish Kernel package. |
5
|
|
|
* |
6
|
|
|
* @copyright Copyright (C) eZ Systems AS. All rights reserved. |
7
|
|
|
* @license For full copyright and license information view LICENSE file distributed with this source code. |
8
|
|
|
*/ |
9
|
|
|
namespace eZ\Bundle\EzPublishMigrationBundle\Command\LegacyStorage; |
10
|
|
|
|
11
|
|
|
use eZ\Publish\API\Repository\Exceptions\ForbiddenException; |
12
|
|
|
use eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\Gateway as UrlAliasGateway; |
13
|
|
|
use eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\Handler as UrlAliasHandler; |
14
|
|
|
use eZ\Publish\Core\Persistence\Legacy\Handler as LegacyStorageEngine; |
15
|
|
|
use eZ\Publish\SPI\Persistence\Content\UrlAlias; |
16
|
|
|
use Doctrine\DBAL\Query\QueryBuilder; |
17
|
|
|
use Doctrine\DBAL\Schema\Schema; |
18
|
|
|
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; |
19
|
|
|
use Symfony\Component\Console\Input\InputArgument; |
20
|
|
|
use Symfony\Component\Console\Input\InputInterface; |
21
|
|
|
use Symfony\Component\Console\Helper\ProgressBar; |
22
|
|
|
use Symfony\Component\Console\Output\OutputInterface; |
23
|
|
|
use RuntimeException; |
24
|
|
|
use Exception; |
25
|
|
|
use PDO; |
26
|
|
|
|
27
|
|
|
class RegenerateUrlAliasesCommand extends ContainerAwareCommand |
28
|
|
|
{ |
29
|
|
|
const MIGRATION_TABLE = '__migration_ezurlalias_ml'; |
30
|
|
|
const CUSTOM_ALIAS_BACKUP_TABLE = '__migration_backup_custom_alias'; |
31
|
|
|
const GLOBAL_ALIAS_BACKUP_TABLE = '__migration_backup_global_alias'; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @var \eZ\Publish\API\Repository\ContentService |
35
|
|
|
*/ |
36
|
|
|
protected $contentService; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @var \eZ\Publish\Core\Repository\Helper\NameSchemaService |
40
|
|
|
*/ |
41
|
|
|
protected $nameSchemaResolver; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @var \eZ\Publish\SPI\Persistence\Content\UrlAlias\Handler |
45
|
|
|
*/ |
46
|
|
|
protected $urlAliasHandler; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* @var \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\Gateway |
50
|
|
|
*/ |
51
|
|
|
protected $urlAliasGateway; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @var \Doctrine\DBAL\Connection |
55
|
|
|
*/ |
56
|
|
|
protected $connection; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @var int |
60
|
|
|
*/ |
61
|
|
|
protected $bulkCount; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @var \Symfony\Component\Console\Output\OutputInterface |
65
|
|
|
*/ |
66
|
|
|
protected $output; |
67
|
|
|
|
68
|
|
|
protected $actionSet = [ |
69
|
|
|
'full' => true, |
70
|
|
|
'autogenerate' => true, |
71
|
|
|
'backup-custom' => true, |
72
|
|
|
'restore-custom' => true, |
73
|
|
|
'backup-global' => true, |
74
|
|
|
'restore-global' => true, |
75
|
|
|
]; |
76
|
|
|
|
77
|
|
|
protected function configure() |
78
|
|
|
{ |
79
|
|
|
$this |
80
|
|
|
->setName('ezplatform:regenerate:legacy_storage_url_aliases') |
81
|
|
|
->setDescription( |
82
|
|
|
'Regenerates Location URL aliases (autogenerated) and migrates custom Location ' . |
83
|
|
|
'and global URL aliases with Legacy Storage Engine' |
84
|
|
|
) |
85
|
|
|
->addArgument( |
86
|
|
|
'action', |
87
|
|
|
InputArgument::REQUIRED, |
88
|
|
|
'Action to perform, one of: full, autogenerate, backup-custom, restore-custom, backup-global, restore-global' |
89
|
|
|
) |
90
|
|
|
->addArgument( |
91
|
|
|
'bulk-count', |
92
|
|
|
InputArgument::OPTIONAL, |
93
|
|
|
'Number of items (Locations, URL aliases) processed at once', |
94
|
|
|
50 |
95
|
|
|
) |
96
|
|
|
->setHelp( |
97
|
|
|
<<<EOT |
98
|
|
|
The command <info>%command.name%</info> regenerates URL aliases for Locations |
99
|
|
|
and migrates existing custom Location and global URL aliases to a separate database table. Separate |
100
|
|
|
table must be named '__migration_ezurlalias_ml' and should be created manually to be identical (but |
101
|
|
|
empty) as the existing table 'ezurlalias_ml' before the command is executed. |
102
|
|
|
|
103
|
|
|
After the script finishes, to complete migration the table should be renamed to 'ezurlalias_ml' |
104
|
|
|
manually. |
105
|
|
|
|
106
|
|
|
Using available options for 'action' argument, you can backup custom Location and global URL aliases |
107
|
|
|
separately and inspect them before restoring them to the migration table. They will be stored in |
108
|
|
|
backup tables named '__migration_backup_custom_alias' and '__migration_backup_global_alias' (created |
109
|
|
|
automatically). |
110
|
|
|
|
111
|
|
|
It is also possible to skip custom Location and global URL aliases altogether and regenerate only |
112
|
|
|
automatically created URL aliases for Locations (use 'autogenerate' action to achieve this). |
113
|
|
|
|
114
|
|
|
<error>During the script execution the database should not be modified.</error> |
115
|
|
|
|
116
|
|
|
Since this script can potentially run for a very long time, to avoid memory exhaustion run it in |
117
|
|
|
production environment using <info>--env=prod</info> switch. |
118
|
|
|
|
119
|
|
|
EOT |
120
|
|
|
); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
protected function execute(InputInterface $input, OutputInterface $output) |
124
|
|
|
{ |
125
|
|
|
$this->checkStorage(); |
126
|
|
|
|
127
|
|
|
$action = $input->getArgument('action'); |
128
|
|
|
$this->bulkCount = $input->getArgument('bulk-count'); |
129
|
|
|
|
130
|
|
|
if (!isset($this->actionSet[$action])) { |
131
|
|
|
throw new RuntimeException( |
132
|
|
|
"Action '{$action}' is not supported, use one of: " . |
133
|
|
|
implode(', ', array_keys($this->actionSet)) |
134
|
|
|
); |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
if ($action === 'full' || $action === 'backup-custom') { |
138
|
|
|
$this->backupCustomLocationAliases(); |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
if ($action === 'full' || $action === 'backup-global') { |
142
|
|
|
$this->backupGlobalAliases(); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
if ($action === 'full' || $action === 'autogenerate') { |
146
|
|
|
$this->generateLocationAliases(); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
if ($action === 'full' || $action === 'restore-custom') { |
150
|
|
|
$this->restoreCustomLocationAliases(); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
if ($action === 'full' || $action === 'restore-global') { |
154
|
|
|
$this->restoreGlobalAliases(); |
155
|
|
|
} |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
protected function initialize(InputInterface $input, OutputInterface $output) |
159
|
|
|
{ |
160
|
|
|
/** @var \eZ\Publish\Core\Persistence\Database\DatabaseHandler $databaseHandler */ |
161
|
|
|
$databaseHandler = $this->getContainer()->get('ezpublish.connection'); |
162
|
|
|
/** @var \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\Gateway $gateway */ |
163
|
|
|
$gateway = $this->getContainer()->get('ezpublish.persistence.legacy.url_alias.gateway'); |
164
|
|
|
/** @var \eZ\Publish\SPI\Persistence\Handler $persistenceHandler */ |
165
|
|
|
$persistenceHandler = $this->getContainer()->get('ezpublish.api.persistence_handler'); |
166
|
|
|
/** @var \eZ\Publish\Core\Repository\Repository $innerRepository */ |
167
|
|
|
$innerRepository = $this->getContainer()->get('ezpublish.api.inner_repository'); |
168
|
|
|
/** @var \eZ\Publish\API\Repository\Repository $repository */ |
169
|
|
|
$repository = $this->getContainer()->get('ezpublish.api.repository'); |
170
|
|
|
|
171
|
|
|
$administratorUser = $repository->getUserService()->loadUser(14); |
172
|
|
|
$repository->getPermissionResolver()->setCurrentUserReference($administratorUser); |
173
|
|
|
|
174
|
|
|
$this->contentService = $repository->getContentService(); |
175
|
|
|
$this->nameSchemaResolver = $innerRepository->getNameSchemaService(); |
176
|
|
|
$this->urlAliasHandler = $persistenceHandler->urlAliasHandler(); |
177
|
|
|
$this->urlAliasGateway = $gateway; |
178
|
|
|
$this->connection = $databaseHandler->getConnection(); |
179
|
|
|
$this->output = $output; |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Checks that configured storage engine is Legacy Storage Engine. |
184
|
|
|
*/ |
185
|
|
|
protected function checkStorage() |
186
|
|
|
{ |
187
|
|
|
$storageEngine = $this->getContainer()->get('ezpublish.api.storage_engine'); |
188
|
|
|
|
189
|
|
|
if (!$storageEngine instanceof LegacyStorageEngine) { |
190
|
|
|
throw new RuntimeException( |
191
|
|
|
'Expected to find Legacy Storage Engine but found something else.' |
192
|
|
|
); |
193
|
|
|
} |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* Sets storage gateway to the default table. |
198
|
|
|
* |
199
|
|
|
* @see \eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\Gateway::TABLE |
200
|
|
|
*/ |
201
|
|
|
protected function setDefaultTable() |
202
|
|
|
{ |
203
|
|
|
$this->urlAliasGateway->setTable(UrlAliasGateway::TABLE); |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
/** |
207
|
|
|
* Sets storage gateway to the migration table. |
208
|
|
|
* |
209
|
|
|
* @see \eZ\Bundle\EzPublishMigrationBundle\Command\LegacyStorage\RegenerateUrlAliasesCommand::MIGRATION_TABLE |
210
|
|
|
*/ |
211
|
|
|
protected function setMigrationTable() |
212
|
|
|
{ |
213
|
|
|
$this->urlAliasGateway->setTable(static::MIGRATION_TABLE); |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* Backups custom Location URL aliases the custom URL alias backup table. |
218
|
|
|
*/ |
219
|
|
View Code Duplication |
protected function backupCustomLocationAliases() |
220
|
|
|
{ |
221
|
|
|
$table = static::CUSTOM_ALIAS_BACKUP_TABLE; |
222
|
|
|
|
223
|
|
|
if (!$this->tableExists($table)) { |
224
|
|
|
$this->createCustomLocationUrlAliasBackupTable(); |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
if (!$this->isTableEmpty($table)) { |
228
|
|
|
throw new RuntimeException( |
229
|
|
|
"Table '{$table}' contains data. " . |
230
|
|
|
"Ensure it's empty or non-existent (it will be automatically created)." |
231
|
|
|
); |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
$this->doBackupCustomLocationAliases(); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* Internal method for backing up custom Location URL aliases. |
239
|
|
|
* |
240
|
|
|
* @see \eZ\Bundle\EzPublishMigrationBundle\Command\LegacyStorage\RegenerateUrlAliasesCommand::backupCustomLocationAliases() |
241
|
|
|
*/ |
242
|
|
|
protected function doBackupCustomLocationAliases() |
243
|
|
|
{ |
244
|
|
|
$totalCount = $this->getTotalLocationCount(); |
245
|
|
|
$passCount = ceil($totalCount / $this->bulkCount); |
246
|
|
|
$customAliasCount = 0; |
247
|
|
|
$customAliasPathCount = 0; |
248
|
|
|
|
249
|
|
|
if ($totalCount === 0) { |
250
|
|
|
$this->output->writeln('Could not find any Locations, nothing to backup.'); |
251
|
|
|
$this->output->writeln(''); |
252
|
|
|
|
253
|
|
|
return; |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
$queryBuilder = $this->connection->createQueryBuilder(); |
257
|
|
|
$queryBuilder |
258
|
|
|
->select('node_id', 'parent_node_id', 'contentobject_id') |
259
|
|
|
->from('ezcontentobject_tree') |
260
|
|
|
->where($queryBuilder->expr()->neq('node_id', 1)) |
261
|
|
|
->orderBy('depth', 'ASC') |
262
|
|
|
->orderBy('node_id', 'ASC'); |
263
|
|
|
|
264
|
|
|
$this->output->writeln("Backing up custom URL alias(es) for {$totalCount} Location(s)."); |
265
|
|
|
|
266
|
|
|
$progressBar = $this->getProgressBar($totalCount); |
267
|
|
|
$progressBar->start(); |
268
|
|
|
|
269
|
|
|
for ($pass = 0; $pass <= $passCount; ++$pass) { |
270
|
|
|
$rows = $this->loadLocationData($queryBuilder, $pass); |
271
|
|
|
|
272
|
|
|
foreach ($rows as $row) { |
273
|
|
|
$customAliases = $this->urlAliasHandler->listURLAliasesForLocation( |
274
|
|
|
$row['node_id'], |
275
|
|
|
true |
276
|
|
|
); |
277
|
|
|
|
278
|
|
|
$customAliasCount += count($customAliases); |
279
|
|
|
$customAliasPathCount += $this->storeCustomAliases($customAliases); |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
$progressBar->advance(count($rows)); |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
$progressBar->finish(); |
286
|
|
|
|
287
|
|
|
$this->output->writeln(''); |
288
|
|
|
$this->output->writeln( |
289
|
|
|
"Done. Backed up {$customAliasCount} custom URL alias(es) " . |
290
|
|
|
"with {$customAliasPathCount} path(s)." |
291
|
|
|
); |
292
|
|
|
$this->output->writeln(''); |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
/** |
296
|
|
|
* Restores custom Location URL aliases from the backup table. |
297
|
|
|
*/ |
298
|
|
View Code Duplication |
protected function restoreCustomLocationAliases() |
299
|
|
|
{ |
300
|
|
|
$mainTable = static::MIGRATION_TABLE; |
301
|
|
|
$backupTable = static::CUSTOM_ALIAS_BACKUP_TABLE; |
302
|
|
|
|
303
|
|
|
if (!$this->tableExists($mainTable)) { |
304
|
|
|
throw new RuntimeException( |
305
|
|
|
"Could not find main URL alias migration table '{$mainTable}'. " . |
306
|
|
|
'Ensure that table exists (you will have to create it manually).' |
307
|
|
|
); |
308
|
|
|
} |
309
|
|
|
|
310
|
|
|
if (!$this->tableExists($backupTable)) { |
311
|
|
|
throw new RuntimeException( |
312
|
|
|
"Could not find custom Location URL alias backup table '{$backupTable}'. " . |
313
|
|
|
"Ensure that table is created by 'backup-custom' action." |
314
|
|
|
); |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
$this->doRestoreCustomLocationAliases(); |
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
/** |
321
|
|
|
* Restores custom Location URL aliases from the backup table. |
322
|
|
|
* |
323
|
|
|
* @see \eZ\Bundle\EzPublishMigrationBundle\Command\LegacyStorage\RegenerateUrlAliasesCommand::restoreCustomLocationAliases() |
324
|
|
|
*/ |
325
|
|
View Code Duplication |
protected function doRestoreCustomLocationAliases() |
326
|
|
|
{ |
327
|
|
|
$totalCount = $this->getTotalBackupCount(static::CUSTOM_ALIAS_BACKUP_TABLE); |
328
|
|
|
$passCount = ceil($totalCount / $this->bulkCount); |
329
|
|
|
$createdAliasCount = 0; |
330
|
|
|
$conflictCount = 0; |
331
|
|
|
|
332
|
|
|
if ($totalCount === 0) { |
333
|
|
|
$this->output->writeln( |
334
|
|
|
'Could not find any backed up custom Location URL aliases, nothing to restore.' |
335
|
|
|
); |
336
|
|
|
$this->output->writeln(''); |
337
|
|
|
|
338
|
|
|
return; |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
$queryBuilder = $this->connection->createQueryBuilder(); |
342
|
|
|
$queryBuilder |
343
|
|
|
->select('*') |
344
|
|
|
->from(static::CUSTOM_ALIAS_BACKUP_TABLE) |
345
|
|
|
->orderBy('id', 'ASC'); |
346
|
|
|
|
347
|
|
|
$this->output->writeln("Restoring {$totalCount} custom URL alias(es)."); |
348
|
|
|
|
349
|
|
|
$progressBar = $this->getProgressBar($totalCount); |
350
|
|
|
$progressBar->start(); |
351
|
|
|
|
352
|
|
|
for ($pass = 0; $pass <= $passCount; ++$pass) { |
353
|
|
|
$rows = $this->loadPassData($queryBuilder, $pass); |
354
|
|
|
|
355
|
|
|
foreach ($rows as $row) { |
356
|
|
|
try { |
357
|
|
|
$this->setMigrationTable(); |
358
|
|
|
$this->urlAliasHandler->createCustomUrlAlias( |
359
|
|
|
$row['location_id'], |
360
|
|
|
$row['path'], |
361
|
|
|
(bool)$row['forwarding'], |
362
|
|
|
$row['language_code'], |
363
|
|
|
(bool)$row['always_available'] |
364
|
|
|
); |
365
|
|
|
$createdAliasCount += 1; |
366
|
|
|
$this->setDefaultTable(); |
367
|
|
|
} catch (ForbiddenException $e) { |
368
|
|
|
$conflictCount += 1; |
369
|
|
|
} catch (Exception $e) { |
370
|
|
|
$this->setDefaultTable(); |
371
|
|
|
throw $e; |
372
|
|
|
} |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
$progressBar->advance(count($rows)); |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
$progressBar->finish(); |
379
|
|
|
|
380
|
|
|
$this->output->writeln(''); |
381
|
|
|
$this->output->writeln( |
382
|
|
|
"Done. Restored {$createdAliasCount} custom URL alias(es) " . |
383
|
|
|
"with {$conflictCount} conflict(s)." |
384
|
|
|
); |
385
|
|
|
$this->output->writeln(''); |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
/** |
389
|
|
|
* Loads Location data for the given $pass. |
390
|
|
|
* |
391
|
|
|
* @param \Doctrine\DBAL\Query\QueryBuilder $queryBuilder |
392
|
|
|
* @param int $pass |
393
|
|
|
* |
394
|
|
|
* @return array |
395
|
|
|
*/ |
396
|
|
View Code Duplication |
protected function loadPassData(QueryBuilder $queryBuilder, $pass) |
397
|
|
|
{ |
398
|
|
|
$queryBuilder->setFirstResult($pass * $this->bulkCount); |
399
|
|
|
$queryBuilder->setMaxResults($this->bulkCount); |
400
|
|
|
|
401
|
|
|
$statement = $queryBuilder->execute(); |
402
|
|
|
|
403
|
|
|
$rows = $statement->fetchAll(PDO::FETCH_ASSOC); |
404
|
|
|
|
405
|
|
|
return $rows; |
406
|
|
|
} |
407
|
|
|
|
408
|
|
|
/** |
409
|
|
|
* Stores given custom $aliases to the custom alias backup table. |
410
|
|
|
* |
411
|
|
|
* @param \eZ\Publish\SPI\Persistence\Content\UrlAlias[] $aliases |
412
|
|
|
* |
413
|
|
|
* @return int |
414
|
|
|
*/ |
415
|
|
|
protected function storeCustomAliases(array $aliases) |
416
|
|
|
{ |
417
|
|
|
$pathCount = 0; |
418
|
|
|
|
419
|
|
|
foreach ($aliases as $alias) { |
420
|
|
|
$paths = $this->combinePaths($alias->pathData); |
421
|
|
|
$pathCount += count($paths); |
422
|
|
|
|
423
|
|
View Code Duplication |
foreach ($paths as $path) { |
|
|
|
|
424
|
|
|
$this->storeCustomAliasPath( |
425
|
|
|
$alias->destination, |
426
|
|
|
$path, |
427
|
|
|
reset($alias->languageCodes), |
428
|
|
|
$alias->alwaysAvailable, |
429
|
|
|
$alias->forward |
430
|
|
|
); |
431
|
|
|
} |
432
|
|
|
} |
433
|
|
|
|
434
|
|
|
return $pathCount; |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
/** |
438
|
|
|
* Stores custom URL alias data for $path to the backup table. |
439
|
|
|
* |
440
|
|
|
* @param int $locationId |
441
|
|
|
* @param string $path |
442
|
|
|
* @param string $languageCode |
443
|
|
|
* @param bool $alwaysAvailable |
444
|
|
|
* @param bool $forwarding |
445
|
|
|
*/ |
446
|
|
View Code Duplication |
protected function storeCustomAliasPath( |
447
|
|
|
$locationId, |
448
|
|
|
$path, |
449
|
|
|
$languageCode, |
450
|
|
|
$alwaysAvailable, |
451
|
|
|
$forwarding |
452
|
|
|
) { |
453
|
|
|
$queryBuilder = $this->connection->createQueryBuilder(); |
454
|
|
|
|
455
|
|
|
$queryBuilder->insert(static::CUSTOM_ALIAS_BACKUP_TABLE); |
456
|
|
|
$queryBuilder->values( |
457
|
|
|
[ |
458
|
|
|
'id' => '?', |
459
|
|
|
'location_id' => '?', |
460
|
|
|
'path' => '?', |
461
|
|
|
'language_code' => '?', |
462
|
|
|
'always_available' => '?', |
463
|
|
|
'forwarding' => '?', |
464
|
|
|
] |
465
|
|
|
); |
466
|
|
|
$queryBuilder->setParameter(0, 0); |
467
|
|
|
$queryBuilder->setParameter(1, $locationId); |
468
|
|
|
$queryBuilder->setParameter(2, $path); |
469
|
|
|
$queryBuilder->setParameter(3, $languageCode); |
470
|
|
|
$queryBuilder->setParameter(4, (int)$alwaysAvailable); |
471
|
|
|
$queryBuilder->setParameter(5, (int)$forwarding); |
472
|
|
|
|
473
|
|
|
$queryBuilder->execute(); |
474
|
|
|
} |
475
|
|
|
|
476
|
|
|
/** |
477
|
|
|
* Combines path data to an array of URL alias paths. |
478
|
|
|
* |
479
|
|
|
* Explanation: |
480
|
|
|
* |
481
|
|
|
* Custom Location and global URL aliases can generate NOP entries, which can be taken over by |
482
|
|
|
* the autogenerated aliases. When multiple languages exists for the Location that took over, |
483
|
|
|
* multiple entries with the same link will exist on the same level. In that case it will not be |
484
|
|
|
* possible to reliably reconstruct what was the path for the original custom alias. For that |
485
|
|
|
* reason we combine path data to get all possible path combinations. |
486
|
|
|
* |
487
|
|
|
* Note: it could happen that original NOP entry was historized after being taken over by the |
488
|
|
|
* autogenerated alias. So to be complete this would have to take into account history entries |
489
|
|
|
* as well, but at the moment we lack API to do that. |
490
|
|
|
* |
491
|
|
|
* Proper solution of this problem would be introducing separate database table to store |
492
|
|
|
* custom/global URL alias data. |
493
|
|
|
* |
494
|
|
|
* @see https://jira.ez.no/browse/EZP-20777 |
495
|
|
|
* |
496
|
|
|
* @param array $pathData |
497
|
|
|
* |
498
|
|
|
* @return string[] |
499
|
|
|
*/ |
500
|
|
|
protected function combinePaths(array $pathData) |
501
|
|
|
{ |
502
|
|
|
$paths = []; |
503
|
|
|
$levelData = array_shift($pathData); |
504
|
|
|
$levelElements = $this->extractPathElements($levelData); |
505
|
|
|
|
506
|
|
|
if (!empty($pathData)) { |
507
|
|
|
$nextElements = $this->combinePaths($pathData); |
508
|
|
|
|
509
|
|
|
foreach ($levelElements as $element1) { |
510
|
|
|
foreach ($nextElements as $element2) { |
511
|
|
|
$paths[] = $element1 . '/' . $element2; |
512
|
|
|
} |
513
|
|
|
} |
514
|
|
|
|
515
|
|
|
return $paths; |
516
|
|
|
} |
517
|
|
|
|
518
|
|
|
return $levelElements; |
519
|
|
|
} |
520
|
|
|
|
521
|
|
|
/** |
522
|
|
|
* Returns all path element strings found for the given path $levelData. |
523
|
|
|
* |
524
|
|
|
* @param array $levelData |
525
|
|
|
* |
526
|
|
|
* @return string[] |
527
|
|
|
*/ |
528
|
|
|
protected function extractPathElements(array $levelData) |
529
|
|
|
{ |
530
|
|
|
$elements = []; |
531
|
|
|
|
532
|
|
|
if (isset($levelData['translations']['always-available'])) { |
533
|
|
|
// NOP entry |
534
|
|
|
$elements[] = $levelData['translations']['always-available']; |
535
|
|
|
} else { |
536
|
|
|
// Language(s) entry |
537
|
|
|
$elements = array_values($levelData['translations']); |
538
|
|
|
} |
539
|
|
|
|
540
|
|
|
return $elements; |
541
|
|
|
} |
542
|
|
|
|
543
|
|
|
/** |
544
|
|
|
* Generates URL aliases from the Location and Content data to the migration table. |
545
|
|
|
*/ |
546
|
|
View Code Duplication |
protected function generateLocationAliases() |
547
|
|
|
{ |
548
|
|
|
$tableName = static::MIGRATION_TABLE; |
549
|
|
|
|
550
|
|
|
if (!$this->tableExists($tableName)) { |
551
|
|
|
throw new RuntimeException( |
552
|
|
|
"Could not find main URL alias migration table '{$tableName}'. " . |
553
|
|
|
'Ensure that table exists (you will have to create it manually).' |
554
|
|
|
); |
555
|
|
|
} |
556
|
|
|
|
557
|
|
|
if (!$this->isTableEmpty($tableName)) { |
558
|
|
|
throw new RuntimeException("Table '{$tableName}' contains data."); |
559
|
|
|
} |
560
|
|
|
|
561
|
|
|
$this->doGenerateLocationAliases(); |
562
|
|
|
} |
563
|
|
|
|
564
|
|
|
/** |
565
|
|
|
* Internal method for generating URL aliases. |
566
|
|
|
* |
567
|
|
|
* @see \eZ\Bundle\EzPublishMigrationBundle\Command\LegacyStorage\RegenerateUrlAliasesCommand::generateLocationAliases() |
568
|
|
|
*/ |
569
|
|
|
protected function doGenerateLocationAliases() |
570
|
|
|
{ |
571
|
|
|
$totalLocationCount = $this->getTotalLocationCount(); |
572
|
|
|
$totalContentCount = $this->getTotalLocationContentCount(); |
573
|
|
|
$passCount = ceil($totalLocationCount / $this->bulkCount); |
574
|
|
|
$publishedAliasCount = 0; |
575
|
|
|
|
576
|
|
|
if ($totalLocationCount === 0) { |
577
|
|
|
$this->output->writeln('Could not find any Locations, nothing to generate.'); |
578
|
|
|
$this->output->writeln(''); |
579
|
|
|
|
580
|
|
|
return; |
581
|
|
|
} |
582
|
|
|
|
583
|
|
|
$queryBuilder = $this->connection->createQueryBuilder(); |
584
|
|
|
$queryBuilder |
585
|
|
|
->select('node_id', 'parent_node_id', 'contentobject_id') |
586
|
|
|
->from('ezcontentobject_tree') |
587
|
|
|
->where($queryBuilder->expr()->neq('node_id', 1)) |
588
|
|
|
->orderBy('depth', 'ASC') |
589
|
|
|
->orderBy('node_id', 'ASC'); |
590
|
|
|
|
591
|
|
|
$this->output->writeln( |
592
|
|
|
"Publishing URL aliases for {$totalLocationCount} Location(s) " . |
593
|
|
|
"with {$totalContentCount} Content item(s) in all languages." |
594
|
|
|
); |
595
|
|
|
|
596
|
|
|
$progressBar = $this->getProgressBar($totalLocationCount); |
597
|
|
|
$progressBar->start(); |
598
|
|
|
|
599
|
|
|
for ($pass = 0; $pass <= $passCount; ++$pass) { |
600
|
|
|
$rows = $this->loadLocationData($queryBuilder, $pass); |
601
|
|
|
|
602
|
|
|
foreach ($rows as $row) { |
603
|
|
|
$publishedAliasCount += $this->publishAliases( |
604
|
|
|
$row['node_id'], |
605
|
|
|
$row['parent_node_id'], |
606
|
|
|
$row['contentobject_id'] |
607
|
|
|
); |
608
|
|
|
} |
609
|
|
|
|
610
|
|
|
$progressBar->advance(count($rows)); |
611
|
|
|
} |
612
|
|
|
|
613
|
|
|
$progressBar->finish(); |
614
|
|
|
|
615
|
|
|
$this->output->writeln(''); |
616
|
|
|
$this->output->writeln("Done. Published {$publishedAliasCount} URL alias(es)."); |
617
|
|
|
$this->output->writeln(''); |
618
|
|
|
} |
619
|
|
|
|
620
|
|
|
/** |
621
|
|
|
* Backups global URL aliases the custom URL alias backup table. |
622
|
|
|
*/ |
623
|
|
View Code Duplication |
protected function backupGlobalAliases() |
624
|
|
|
{ |
625
|
|
|
$table = static::GLOBAL_ALIAS_BACKUP_TABLE; |
626
|
|
|
|
627
|
|
|
if (!$this->tableExists($table)) { |
628
|
|
|
$this->createGlobalUrlAliasBackupTable(); |
629
|
|
|
} |
630
|
|
|
|
631
|
|
|
if (!$this->isTableEmpty($table)) { |
632
|
|
|
throw new RuntimeException( |
633
|
|
|
"Table '{$table}' contains data. " . |
634
|
|
|
"Ensure it's empty or non-existent (it will be automatically created)." |
635
|
|
|
); |
636
|
|
|
} |
637
|
|
|
|
638
|
|
|
$this->doBackupGlobalAliases(); |
639
|
|
|
} |
640
|
|
|
|
641
|
|
|
/** |
642
|
|
|
* Internal method for backing up global URL aliases. |
643
|
|
|
* |
644
|
|
|
* @see \eZ\Bundle\EzPublishMigrationBundle\Command\LegacyStorage\RegenerateUrlAliasesCommand::backupGlobalAliases() |
645
|
|
|
*/ |
646
|
|
|
protected function doBackupGlobalAliases() |
647
|
|
|
{ |
648
|
|
|
$aliases = $this->urlAliasHandler->listGlobalURLAliases(); |
649
|
|
|
$totalCount = count($aliases); |
650
|
|
|
$pathCount = 0; |
651
|
|
|
|
652
|
|
|
if ($totalCount === 0) { |
653
|
|
|
$this->output->writeln('Could not find any global URL aliases, nothing to backup.'); |
654
|
|
|
$this->output->writeln(''); |
655
|
|
|
|
656
|
|
|
return; |
657
|
|
|
} |
658
|
|
|
|
659
|
|
|
$this->output->writeln("Backing up {$totalCount} global URL aliases."); |
660
|
|
|
|
661
|
|
|
$progressBar = $this->getProgressBar($totalCount); |
662
|
|
|
$progressBar->start(); |
663
|
|
|
|
664
|
|
|
foreach ($aliases as $alias) { |
665
|
|
|
$pathCount += $this->storeGlobalAlias($alias); |
666
|
|
|
$progressBar->advance(); |
667
|
|
|
} |
668
|
|
|
|
669
|
|
|
$progressBar->finish(); |
670
|
|
|
|
671
|
|
|
$this->output->writeln(''); |
672
|
|
|
$this->output->writeln( |
673
|
|
|
"Done. Backed up {$totalCount} global URL alias(es) " . |
674
|
|
|
"with {$pathCount} path(s)." |
675
|
|
|
); |
676
|
|
|
$this->output->writeln(''); |
677
|
|
|
} |
678
|
|
|
|
679
|
|
|
/** |
680
|
|
|
* Stores given global URL $alias to the global URL alias backup table. |
681
|
|
|
* |
682
|
|
|
* @param \eZ\Publish\SPI\Persistence\Content\UrlAlias $alias |
683
|
|
|
* |
684
|
|
|
* @return int |
685
|
|
|
*/ |
686
|
|
|
protected function storeGlobalAlias(UrlAlias $alias) |
687
|
|
|
{ |
688
|
|
|
$paths = $this->combinePaths($alias->pathData); |
689
|
|
|
|
690
|
|
View Code Duplication |
foreach ($paths as $path) { |
|
|
|
|
691
|
|
|
$this->storeGlobalAliasPath( |
692
|
|
|
$alias->destination, |
693
|
|
|
$path, |
694
|
|
|
reset($alias->languageCodes), |
695
|
|
|
$alias->alwaysAvailable, |
696
|
|
|
$alias->forward |
697
|
|
|
); |
698
|
|
|
} |
699
|
|
|
|
700
|
|
|
return count($paths); |
701
|
|
|
} |
702
|
|
|
|
703
|
|
|
/** |
704
|
|
|
* Stores global URL alias data for $path to the backup table. |
705
|
|
|
* |
706
|
|
|
* @param string $resource |
707
|
|
|
* @param string $path |
708
|
|
|
* @param string $languageCode |
709
|
|
|
* @param bool $alwaysAvailable |
710
|
|
|
* @param bool $forwarding |
711
|
|
|
*/ |
712
|
|
View Code Duplication |
protected function storeGlobalAliasPath( |
713
|
|
|
$resource, |
714
|
|
|
$path, |
715
|
|
|
$languageCode, |
716
|
|
|
$alwaysAvailable, |
717
|
|
|
$forwarding |
718
|
|
|
) { |
719
|
|
|
$queryBuilder = $this->connection->createQueryBuilder(); |
720
|
|
|
|
721
|
|
|
$queryBuilder->insert(static::GLOBAL_ALIAS_BACKUP_TABLE); |
722
|
|
|
$queryBuilder->values( |
723
|
|
|
[ |
724
|
|
|
'id' => '?', |
725
|
|
|
'resource' => '?', |
726
|
|
|
'path' => '?', |
727
|
|
|
'language_code' => '?', |
728
|
|
|
'always_available' => '?', |
729
|
|
|
'forwarding' => '?', |
730
|
|
|
] |
731
|
|
|
); |
732
|
|
|
$queryBuilder->setParameter(0, 0); |
733
|
|
|
$queryBuilder->setParameter(1, 'module:' . $resource); |
734
|
|
|
$queryBuilder->setParameter(2, $path); |
735
|
|
|
$queryBuilder->setParameter(3, $languageCode); |
736
|
|
|
$queryBuilder->setParameter(4, (int)$alwaysAvailable); |
737
|
|
|
$queryBuilder->setParameter(5, (int)$forwarding); |
738
|
|
|
|
739
|
|
|
$queryBuilder->execute(); |
740
|
|
|
} |
741
|
|
|
|
742
|
|
|
/** |
743
|
|
|
* Restores global URL aliases from the backup table. |
744
|
|
|
*/ |
745
|
|
View Code Duplication |
protected function restoreGlobalAliases() |
746
|
|
|
{ |
747
|
|
|
$table = static::MIGRATION_TABLE; |
748
|
|
|
$backupTable = static::GLOBAL_ALIAS_BACKUP_TABLE; |
749
|
|
|
|
750
|
|
|
if (!$this->tableExists($table)) { |
751
|
|
|
throw new RuntimeException( |
752
|
|
|
"Could not find main URL alias migration table '{$table}'. " . |
753
|
|
|
'Ensure that table exists (you will have to create it manually).' |
754
|
|
|
); |
755
|
|
|
} |
756
|
|
|
|
757
|
|
|
if (!$this->tableExists($backupTable)) { |
758
|
|
|
throw new RuntimeException( |
759
|
|
|
"Could not find global URL alias backup table '$backupTable'. " . |
760
|
|
|
"Ensure that table is created by 'backup-global' action." |
761
|
|
|
); |
762
|
|
|
} |
763
|
|
|
|
764
|
|
|
$this->doRestoreGlobalAliases(); |
765
|
|
|
} |
766
|
|
|
|
767
|
|
|
/** |
768
|
|
|
* Restores global URL aliases from the backup table. |
769
|
|
|
* |
770
|
|
|
* @see \eZ\Bundle\EzPublishMigrationBundle\Command\LegacyStorage\RegenerateUrlAliasesCommand::restoreGlobalAliases() |
771
|
|
|
*/ |
772
|
|
View Code Duplication |
protected function doRestoreGlobalAliases() |
773
|
|
|
{ |
774
|
|
|
$totalCount = $this->getTotalBackupCount(static::GLOBAL_ALIAS_BACKUP_TABLE); |
775
|
|
|
$passCount = ceil($totalCount / $this->bulkCount); |
776
|
|
|
$createdAliasCount = 0; |
777
|
|
|
$conflictCount = 0; |
778
|
|
|
|
779
|
|
|
if ($totalCount === 0) { |
780
|
|
|
$this->output->writeln( |
781
|
|
|
'Could not find any backed up global URL aliases, nothing to restore.' |
782
|
|
|
); |
783
|
|
|
$this->output->writeln(''); |
784
|
|
|
|
785
|
|
|
return; |
786
|
|
|
} |
787
|
|
|
|
788
|
|
|
$queryBuilder = $this->connection->createQueryBuilder(); |
789
|
|
|
$queryBuilder |
790
|
|
|
->select('*') |
791
|
|
|
->from(static::GLOBAL_ALIAS_BACKUP_TABLE) |
792
|
|
|
->orderBy('id', 'ASC'); |
793
|
|
|
|
794
|
|
|
$this->output->writeln("Restoring {$totalCount} custom URL alias(es)."); |
795
|
|
|
|
796
|
|
|
$progressBar = $this->getProgressBar($totalCount); |
797
|
|
|
$progressBar->start(); |
798
|
|
|
|
799
|
|
|
for ($pass = 0; $pass <= $passCount; ++$pass) { |
800
|
|
|
$rows = $this->loadPassData($queryBuilder, $pass); |
801
|
|
|
|
802
|
|
|
foreach ($rows as $row) { |
803
|
|
|
try { |
804
|
|
|
$this->setMigrationTable(); |
805
|
|
|
$this->urlAliasHandler->createGlobalUrlAlias( |
806
|
|
|
$row['resource'], |
807
|
|
|
$row['path'], |
808
|
|
|
(bool)$row['forwarding'], |
809
|
|
|
$row['language_code'], |
810
|
|
|
(bool)$row['always_available'] |
811
|
|
|
); |
812
|
|
|
$createdAliasCount += 1; |
813
|
|
|
$this->setDefaultTable(); |
814
|
|
|
} catch (ForbiddenException $e) { |
815
|
|
|
$conflictCount += 1; |
816
|
|
|
} catch (Exception $e) { |
817
|
|
|
$this->setDefaultTable(); |
818
|
|
|
throw $e; |
819
|
|
|
} |
820
|
|
|
} |
821
|
|
|
|
822
|
|
|
$progressBar->advance(count($rows)); |
823
|
|
|
} |
824
|
|
|
|
825
|
|
|
$progressBar->finish(); |
826
|
|
|
|
827
|
|
|
$this->output->writeln(''); |
828
|
|
|
$this->output->writeln( |
829
|
|
|
"Done. Restored {$createdAliasCount} custom URL alias(es) " . |
830
|
|
|
"with {$conflictCount} conflict(s)." |
831
|
|
|
); |
832
|
|
|
$this->output->writeln(''); |
833
|
|
|
} |
834
|
|
|
|
835
|
|
|
/** |
836
|
|
|
* Publishes URL aliases in all languages for the given parameters. |
837
|
|
|
* |
838
|
|
|
* @throws \Exception |
839
|
|
|
* |
840
|
|
|
* @param int|string $locationId |
841
|
|
|
* @param int|string $parentLocationId |
842
|
|
|
* @param int|string $contentId |
843
|
|
|
* |
844
|
|
|
* @return int |
845
|
|
|
*/ |
846
|
|
|
protected function publishAliases($locationId, $parentLocationId, $contentId) |
847
|
|
|
{ |
848
|
|
|
$content = $this->contentService->loadContent($contentId); |
849
|
|
|
|
850
|
|
|
$urlAliasNames = $this->nameSchemaResolver->resolveUrlAliasSchema($content); |
851
|
|
|
|
852
|
|
|
foreach ($urlAliasNames as $languageCode => $name) { |
853
|
|
|
try { |
854
|
|
|
$this->setMigrationTable(); |
855
|
|
|
$this->urlAliasHandler->publishUrlAliasForLocation( |
856
|
|
|
$locationId, |
857
|
|
|
$parentLocationId, |
858
|
|
|
$name, |
859
|
|
|
$languageCode, |
860
|
|
|
$content->contentInfo->alwaysAvailable |
861
|
|
|
); |
862
|
|
|
$this->setDefaultTable(); |
863
|
|
|
} catch (Exception $e) { |
864
|
|
|
$this->setDefaultTable(); |
865
|
|
|
throw $e; |
866
|
|
|
} |
867
|
|
|
} |
868
|
|
|
|
869
|
|
|
return count($urlAliasNames); |
870
|
|
|
} |
871
|
|
|
|
872
|
|
|
/** |
873
|
|
|
* Loads Location data for the given $pass. |
874
|
|
|
* |
875
|
|
|
* @param \Doctrine\DBAL\Query\QueryBuilder $queryBuilder |
876
|
|
|
* @param int $pass |
877
|
|
|
* |
878
|
|
|
* @return array |
879
|
|
|
*/ |
880
|
|
View Code Duplication |
protected function loadLocationData(QueryBuilder $queryBuilder, $pass) |
881
|
|
|
{ |
882
|
|
|
$queryBuilder->setFirstResult($pass * $this->bulkCount); |
883
|
|
|
$queryBuilder->setMaxResults($this->bulkCount); |
884
|
|
|
|
885
|
|
|
$statement = $queryBuilder->execute(); |
886
|
|
|
|
887
|
|
|
$rows = $statement->fetchAll(PDO::FETCH_ASSOC); |
888
|
|
|
|
889
|
|
|
return $rows; |
890
|
|
|
} |
891
|
|
|
|
892
|
|
|
/** |
893
|
|
|
* Returns total number of Locations in the database. |
894
|
|
|
* |
895
|
|
|
* The number excludes absolute root Location, which does not have an URL alias. |
896
|
|
|
*/ |
897
|
|
View Code Duplication |
protected function getTotalLocationCount() |
898
|
|
|
{ |
899
|
|
|
$platform = $this->connection->getDatabasePlatform(); |
900
|
|
|
|
901
|
|
|
$queryBuilder = $this->connection->createQueryBuilder(); |
902
|
|
|
$queryBuilder |
903
|
|
|
->select($platform->getCountExpression('node_id')) |
904
|
|
|
->from('ezcontentobject_tree') |
905
|
|
|
->where( |
906
|
|
|
$queryBuilder->expr()->neq( |
907
|
|
|
'node_id', |
908
|
|
|
UrlAliasHandler::ROOT_LOCATION_ID |
909
|
|
|
) |
910
|
|
|
); |
911
|
|
|
|
912
|
|
|
return $queryBuilder->execute()->fetchColumn(); |
913
|
|
|
} |
914
|
|
|
|
915
|
|
|
/** |
916
|
|
|
* Returns total number of Content objects having a Location in the database. |
917
|
|
|
* |
918
|
|
|
* The number excludes absolute root Location, which does not have an URL alias. |
919
|
|
|
*/ |
920
|
|
View Code Duplication |
protected function getTotalLocationContentCount() |
921
|
|
|
{ |
922
|
|
|
$platform = $this->connection->getDatabasePlatform(); |
923
|
|
|
|
924
|
|
|
$queryBuilder = $this->connection->createQueryBuilder(); |
925
|
|
|
$queryBuilder |
926
|
|
|
->select($platform->getCountExpression('DISTINCT contentobject_id')) |
927
|
|
|
->from('ezcontentobject_tree') |
928
|
|
|
->where( |
929
|
|
|
$queryBuilder->expr()->neq( |
930
|
|
|
'node_id', |
931
|
|
|
UrlAliasHandler::ROOT_LOCATION_ID |
932
|
|
|
) |
933
|
|
|
); |
934
|
|
|
|
935
|
|
|
return $queryBuilder->execute()->fetchColumn(); |
936
|
|
|
} |
937
|
|
|
|
938
|
|
|
/** |
939
|
|
|
* Return the number of rows in the given $table (on ID column). |
940
|
|
|
* |
941
|
|
|
* @param string $table |
942
|
|
|
* |
943
|
|
|
* @return int |
944
|
|
|
*/ |
945
|
|
View Code Duplication |
protected function getTotalBackupCount($table) |
946
|
|
|
{ |
947
|
|
|
$platform = $this->connection->getDatabasePlatform(); |
948
|
|
|
|
949
|
|
|
$queryBuilder = $this->connection->createQueryBuilder(); |
950
|
|
|
$queryBuilder |
951
|
|
|
->select($platform->getCountExpression('id')) |
952
|
|
|
->from($table); |
953
|
|
|
|
954
|
|
|
return (int)$queryBuilder->execute()->fetchColumn(); |
955
|
|
|
} |
956
|
|
|
|
957
|
|
|
/** |
958
|
|
|
* Creates database table for custom Location URL alias backup. |
959
|
|
|
*/ |
960
|
|
View Code Duplication |
protected function createCustomLocationUrlAliasBackupTable() |
961
|
|
|
{ |
962
|
|
|
$schema = new Schema(); |
963
|
|
|
|
964
|
|
|
$table = $schema->createTable(static::CUSTOM_ALIAS_BACKUP_TABLE); |
965
|
|
|
|
966
|
|
|
$table->addColumn('id', 'integer', ['autoincrement' => true]); |
967
|
|
|
$table->addColumn('location_id', 'integer'); |
968
|
|
|
$table->addColumn('path', 'text'); |
969
|
|
|
$table->addColumn('language_code', 'string'); |
970
|
|
|
$table->addColumn('always_available', 'integer'); |
971
|
|
|
$table->addColumn('forwarding', 'integer'); |
972
|
|
|
$table->setPrimaryKey(['id']); |
973
|
|
|
|
974
|
|
|
$queries = $schema->toSql($this->connection->getDatabasePlatform()); |
975
|
|
|
|
976
|
|
|
foreach ($queries as $query) { |
977
|
|
|
$this->connection->exec($query); |
978
|
|
|
} |
979
|
|
|
} |
980
|
|
|
|
981
|
|
|
/** |
982
|
|
|
* Creates database table for custom URL alias backup. |
983
|
|
|
*/ |
984
|
|
View Code Duplication |
protected function createGlobalUrlAliasBackupTable() |
985
|
|
|
{ |
986
|
|
|
$schema = new Schema(); |
987
|
|
|
|
988
|
|
|
$table = $schema->createTable(static::GLOBAL_ALIAS_BACKUP_TABLE); |
989
|
|
|
|
990
|
|
|
$table->addColumn('id', 'integer', ['autoincrement' => true]); |
991
|
|
|
$table->addColumn('resource', 'text'); |
992
|
|
|
$table->addColumn('path', 'text'); |
993
|
|
|
$table->addColumn('language_code', 'string'); |
994
|
|
|
$table->addColumn('always_available', 'integer'); |
995
|
|
|
$table->addColumn('forwarding', 'integer'); |
996
|
|
|
$table->setPrimaryKey(['id']); |
997
|
|
|
|
998
|
|
|
$queries = $schema->toSql($this->connection->getDatabasePlatform()); |
999
|
|
|
|
1000
|
|
|
foreach ($queries as $query) { |
1001
|
|
|
$this->connection->exec($query); |
1002
|
|
|
} |
1003
|
|
|
} |
1004
|
|
|
|
1005
|
|
|
/** |
1006
|
|
|
* Checks if database table $name exists. |
1007
|
|
|
* |
1008
|
|
|
* @param string $name |
1009
|
|
|
* |
1010
|
|
|
* @return bool |
1011
|
|
|
*/ |
1012
|
|
|
protected function tableExists($name) |
1013
|
|
|
{ |
1014
|
|
|
return $this->connection->getSchemaManager()->tablesExist([$name]); |
1015
|
|
|
} |
1016
|
|
|
|
1017
|
|
|
/** |
1018
|
|
|
* Checks if database table $name is empty. |
1019
|
|
|
* |
1020
|
|
|
* @param string $name |
1021
|
|
|
* |
1022
|
|
|
* @return bool |
1023
|
|
|
*/ |
1024
|
|
View Code Duplication |
protected function isTableEmpty($name) |
1025
|
|
|
{ |
1026
|
|
|
$queryBuilder = $this->connection->createQueryBuilder(); |
1027
|
|
|
$queryBuilder |
1028
|
|
|
->select($this->connection->getDatabasePlatform()->getCountExpression('*')) |
1029
|
|
|
->from($name); |
1030
|
|
|
|
1031
|
|
|
$count = $queryBuilder->execute()->fetchColumn(); |
1032
|
|
|
|
1033
|
|
|
return $count == 0; |
1034
|
|
|
} |
1035
|
|
|
|
1036
|
|
|
/** |
1037
|
|
|
* Returns configured progress bar helper. |
1038
|
|
|
* |
1039
|
|
|
* @param int $maxSteps |
1040
|
|
|
* |
1041
|
|
|
* @return \Symfony\Component\Console\Helper\ProgressBar |
1042
|
|
|
*/ |
1043
|
|
|
protected function getProgressBar($maxSteps) |
1044
|
|
|
{ |
1045
|
|
|
$progressBar = new ProgressBar($this->output, $maxSteps); |
1046
|
|
|
$progressBar->setFormat( |
1047
|
|
|
' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%' |
1048
|
|
|
); |
1049
|
|
|
|
1050
|
|
|
return $progressBar; |
1051
|
|
|
} |
1052
|
|
|
} |
1053
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.