Database
2 weeks ago
DatabaseAdjustment
2 weeks ago
FileAdjustment
1 week ago
Filesystem
2 weeks ago
CleanupStagingFilesTask.php
1 year ago
CleanupStagingTablesTask.php
2 weeks ago
CleanupStagingTablesTask.php
186 lines
| 1 | <?php |
| 2 | |
| 3 | namespace WPStaging\Staging\Tasks\StagingSite; |
| 4 | |
| 5 | use Exception; |
| 6 | use WPStaging\Framework\Adapter\DatabaseInterface; |
| 7 | use WPStaging\Framework\Database\TableService; |
| 8 | use WPStaging\Framework\Job\Dto\TaskResponseDto; |
| 9 | use WPStaging\Framework\Job\Dto\StepsDto; |
| 10 | use WPStaging\Framework\Queue\SeekableQueueInterface; |
| 11 | use WPStaging\Framework\Utils\Cache\Cache; |
| 12 | use WPStaging\Staging\Interfaces\StagingDatabaseDtoInterface; |
| 13 | use WPStaging\Staging\Interfaces\StagingSiteDtoInterface; |
| 14 | use WPStaging\Staging\Tasks\StagingTask; |
| 15 | use WPStaging\Staging\Traits\WithStagingDatabase; |
| 16 | use WPStaging\Vendor\Psr\Log\LoggerInterface; |
| 17 | |
| 18 | class CleanupStagingTablesTask extends StagingTask |
| 19 | { |
| 20 | use WithStagingDatabase; |
| 21 | |
| 22 | /** @var array An array with the name of all existing tables. */ |
| 23 | protected $tables = []; |
| 24 | |
| 25 | /** @var array An array with the name of all existing views. */ |
| 26 | protected $views = []; |
| 27 | |
| 28 | /** @var DatabaseInterface */ |
| 29 | protected $productionDb; |
| 30 | |
| 31 | public function __construct(LoggerInterface $logger, Cache $cache, StepsDto $stepsDto, DatabaseInterface $productionDb, SeekableQueueInterface $taskQueue) |
| 32 | { |
| 33 | parent::__construct($logger, $cache, $stepsDto, $taskQueue); |
| 34 | $this->productionDb = $productionDb; |
| 35 | } |
| 36 | |
| 37 | public static function getTaskName() |
| 38 | { |
| 39 | return "staging_cleanup_tables"; |
| 40 | } |
| 41 | |
| 42 | public static function getTaskTitle() |
| 43 | { |
| 44 | return 'Cleaning Up Staging Site Tables'; |
| 45 | } |
| 46 | |
| 47 | /** |
| 48 | * @return TaskResponseDto |
| 49 | */ |
| 50 | public function execute() |
| 51 | { |
| 52 | $stagingPrefix = $this->prepareCleanupTask(); |
| 53 | |
| 54 | if (empty($stagingPrefix)) { |
| 55 | return $this->generateResponse(true); |
| 56 | } |
| 57 | |
| 58 | $this->views = $this->getStagingViews($stagingPrefix); |
| 59 | $this->tables = $this->getStagingTables($stagingPrefix); |
| 60 | |
| 61 | while (!$this->isThreshold() && !$this->stepsDto->isFinished()) { |
| 62 | $tableOrViewName = $this->taskQueue->dequeue(); |
| 63 | |
| 64 | // Double-check we are deleting a temporary table just to be extra-careful. |
| 65 | if (strpos($tableOrViewName, $stagingPrefix) !== 0) { |
| 66 | $this->logger->warning(sprintf( |
| 67 | '%s: Staging site table "%s" did not start with staging prefix "%s" and was skipped.', |
| 68 | static::getTaskTitle(), |
| 69 | esc_html($tableOrViewName), |
| 70 | esc_html($stagingPrefix) |
| 71 | )); |
| 72 | |
| 73 | continue; |
| 74 | } |
| 75 | |
| 76 | $label = 'table'; |
| 77 | |
| 78 | if (in_array($tableOrViewName, $this->views)) { |
| 79 | $label = 'view'; |
| 80 | $deleted = $this->tableService->deleteViews([$tableOrViewName]); |
| 81 | } elseif (in_array($tableOrViewName, $this->tables)) { |
| 82 | $deleted = $this->tableService->deleteTables([$tableOrViewName]); |
| 83 | } else { |
| 84 | $deleted = false; |
| 85 | } |
| 86 | |
| 87 | $this->stepsDto->incrementCurrentStep(); |
| 88 | |
| 89 | if ($deleted) { |
| 90 | $this->logger->debug(sprintf( |
| 91 | '%s: Deleted staging site %s "%s".', |
| 92 | static::getTaskTitle(), |
| 93 | esc_html($label), |
| 94 | esc_html($tableOrViewName) |
| 95 | )); |
| 96 | } else { |
| 97 | $this->logger->warning(sprintf( |
| 98 | '%s: Staging site %s "%s" was not successfully deleted.', |
| 99 | static::getTaskTitle(), |
| 100 | esc_html($label), |
| 101 | esc_html($tableOrViewName) |
| 102 | )); |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | if ($this->taskQueue->isFinished()) { |
| 107 | $this->stepsDto->finish(); |
| 108 | } |
| 109 | |
| 110 | if ($this->stepsDto->isFinished()) { |
| 111 | // Successfully deleted |
| 112 | $this->logger->info(sprintf( |
| 113 | '%s: Tables with staging site prefix "%s" successfully cleaned up.', |
| 114 | static::getTaskTitle(), |
| 115 | esc_html($stagingPrefix) |
| 116 | )); |
| 117 | } |
| 118 | |
| 119 | |
| 120 | return $this->generateResponse(false); |
| 121 | } |
| 122 | |
| 123 | /** |
| 124 | * @return string |
| 125 | */ |
| 126 | public function prepareCleanupTask(): string |
| 127 | { |
| 128 | if (!$this->jobDataDto instanceof StagingSiteDtoInterface) { |
| 129 | throw new Exception('Clone ID not found in job data.'); |
| 130 | } |
| 131 | |
| 132 | /** @var StagingSiteDtoInterface */ |
| 133 | $jobDataDto = $this->jobDataDto; |
| 134 | |
| 135 | $this->initStagingDatabase($this->getStagingSiteDto($this->jobDataDto->getCloneId())); |
| 136 | $this->tableService = new TableService($this->stagingDb); |
| 137 | |
| 138 | // Early bail: Already prepared |
| 139 | if ($this->stepsDto->getTotal() > 0) { |
| 140 | return $jobDataDto->getStagingSite()->getUsedPrefix(); |
| 141 | } |
| 142 | |
| 143 | $stagingSiteDto = $this->getStagingSiteDto($jobDataDto->getCloneId()); |
| 144 | $jobDataDto->setStagingSite($stagingSiteDto); |
| 145 | |
| 146 | $stagingPrefix = $stagingSiteDto->getUsedPrefix(); |
| 147 | |
| 148 | if (!$stagingSiteDto->getIsExternalDatabase() && $this->productionDb->getPrefix() === $stagingPrefix) { |
| 149 | $this->logger->warning(sprintf( |
| 150 | '%s: Staging site prefix "%s" is the same as the WordPress table prefix, it is also not a external database connection. This is not allowed.', |
| 151 | static::getTaskTitle(), |
| 152 | esc_html($stagingPrefix) |
| 153 | )); |
| 154 | |
| 155 | return ''; |
| 156 | } |
| 157 | |
| 158 | $tmpViews = $this->getStagingViews($stagingPrefix); |
| 159 | $tmpTables = $this->getStagingTables($stagingPrefix); |
| 160 | $toDelete = array_merge($tmpViews, $tmpTables); |
| 161 | $count = 0; |
| 162 | $excludedTables = $jobDataDto instanceof StagingDatabaseDtoInterface ? $jobDataDto->getExcludedTables() : []; |
| 163 | |
| 164 | foreach ($toDelete as $tableOrViewName) { |
| 165 | if (in_array($tableOrViewName, $excludedTables, true)) { |
| 166 | $this->logger->debug(sprintf( |
| 167 | '%s: Skipping excluded staging site table "%s".', |
| 168 | static::getTaskTitle(), |
| 169 | esc_html($tableOrViewName) |
| 170 | )); |
| 171 | |
| 172 | continue; |
| 173 | } |
| 174 | |
| 175 | $count++; |
| 176 | $this->taskQueue->enqueue($tableOrViewName); |
| 177 | } |
| 178 | |
| 179 | $this->taskQueue->seek(0); |
| 180 | |
| 181 | $this->stepsDto->setTotal($count); |
| 182 | |
| 183 | return $stagingPrefix; |
| 184 | } |
| 185 | } |
| 186 |