'%$' . LoggerInterface::class, ]; /** @var Logger */ private $logger; public function __construct() { Deprecation::notice('4.12.0', 'Will be removed without equivalent functionality to replace it', Deprecation::SCOPE_CLASS); parent::__construct(); } public function run($request) { $this->addLogHandlers(); $args = $request->getVars(); $this->validateArgs($args); Injector::inst()->get(FileHashingService::class)->enableCache(); // Set max time and memory limit Environment::increaseTimeLimitTo(); Environment::setMemoryLimitMax(-1); Environment::increaseMemoryLimitTo(-1); $this->extend('preFileMigration'); $this->logger->warn( 'Please read https://docs.silverstripe.org/en/4/developer_guides/files/file_migration/ ' . 'before running this task.' ); $subtasks = !empty($args['only']) ? explode(',', $args['only']) : $this->defaultSubtasks; $subtask = 'move-files'; if (in_array($subtask, $subtasks ?? [])) { if (!class_exists(FileMigrationHelper::class)) { $this->logger->error("No file migration helper detected"); } else { $this->extend('preFileMigrationSubtask', $subtask); $this->logger->notice("######################################################"); $this->logger->notice("Migrating filesystem and database records ({$subtask})"); $this->logger->notice("######################################################"); FileMigrationHelper::singleton() ->setLogger($this->logger) ->run(); $this->extend('postFileMigrationSubtask', $subtask); } } $subtask = 'migrate-folders'; if (in_array($subtask, $subtasks ?? [])) { if (!class_exists(FolderMigrationHelper::class)) { $this->logger->error("No folder migration helper detected"); } else { $this->extend('preFileMigrationSubtask', $subtask); $this->logger->notice("######################################################"); $this->logger->notice("Migrating folder database records ({$subtask})"); $this->logger->notice("######################################################"); FolderMigrationHelper::singleton() ->setLogger($this->logger) ->run(); $this->extend('postFileMigrationSubtask', $subtask); } } $subtask = 'move-thumbnails'; if (in_array($subtask, $subtasks ?? [])) { if (!class_exists(LegacyThumbnailMigrationHelper::class)) { $this->logger->error("LegacyThumbnailMigrationHelper not found"); } else { $this->extend('preFileMigrationSubtask', $subtask); $this->logger->notice("#############################################################"); $this->logger->notice("Migrating existing thumbnails to new file format ({$subtask})"); $this->logger->notice("#############################################################"); $paths = LegacyThumbnailMigrationHelper::singleton() ->setLogger($this->logger) ->run($this->getStore()); if ($paths) { $this->logger->info(sprintf("%d thumbnails moved", count($paths ?? []))); } else { $this->logger->info("No thumbnails needed to be moved"); } $this->extend('postFileMigrationSubtask', $subtask); } } $subtask = 'generate-cms-thumbnails'; if (in_array($subtask, $subtasks ?? [])) { if (!class_exists(ImageThumbnailHelper::class)) { $this->logger->error("ImageThumbnailHelper not found"); } else { $this->extend('preFileMigrationSubtask', $subtask); $this->logger->notice("#############################################"); $this->logger->notice("Generating new CMS UI thumbnails ({$subtask})"); $this->logger->notice("#############################################"); $count = ImageThumbnailHelper::singleton() ->setLogger($this->logger) ->run(); if ($count > 0) { $this->logger->info("Created {$count} CMS UI thumbnails"); } else { $this->logger->info("No CMS UI thumbnails needed to be created"); } $this->extend('postFileMigrationSubtask', $subtask); } } $subtask = 'fix-folder-permissions'; if (in_array($subtask, $subtasks ?? [])) { if (!class_exists(FixFolderPermissionsHelper::class)) { $this->logger->error("FixFolderPermissionsHelper not found"); } else { $this->extend('preFileMigrationSubtask', $subtask); $this->logger->notice("####################################################"); $this->logger->notice("Fixing secure-assets folder permissions ({$subtask})"); $this->logger->notice("####################################################"); $this->logger->debug('Only required if the 3.x project included silverstripe/secure-assets'); $count = FixFolderPermissionsHelper::singleton() ->setLogger($this->logger) ->run(); if ($count > 0) { $this->logger->info("Repaired {$count} folders with broken CanViewType settings"); } else { $this->logger->info("No folders required fixes"); } $this->extend('postFileMigrationSubtask', $subtask); } } $subtask = 'fix-secureassets'; if (in_array($subtask, $subtasks ?? [])) { if (!class_exists(SecureAssetsMigrationHelper::class)) { $this->logger->error("SecureAssetsMigrationHelper not found"); } else { $this->extend('preFileMigrationSubtask', $subtask); $this->logger->notice("#####################################################"); $this->logger->notice("Fixing secure-assets folder restrictions ({$subtask})"); $this->logger->notice("#####################################################"); $this->logger->debug('Only required if the 3.x project included silverstripe/secure-assets'); $paths = SecureAssetsMigrationHelper::singleton() ->setLogger($this->logger) ->run($this->getStore()); if (count($paths ?? []) > 0) { $this->logger->info(sprintf("Repaired %d folders broken folder restrictions", count($paths ?? []))); } else { $this->logger->info("No folders required fixes"); } $this->extend('postFileMigrationSubtask', $subtask); } } $subtask = 'normalise-access'; if (in_array($subtask, $subtasks ?? [])) { if (!class_exists(NormaliseAccessMigrationHelper::class)) { $this->logger->error("No normalise access migration helper detected"); } else { $this->extend('preFileMigrationSubtask', $subtask); $this->logger->notice("######################################################"); $this->logger->notice("Migrating filesystem and database records ({$subtask})"); $this->logger->notice("######################################################"); NormaliseAccessMigrationHelper::singleton() ->setLogger($this->logger) ->run(); $this->extend('postFileMigrationSubtask', $subtask); } } $subtask = 'relocate-userform-uploads-2020-9280'; if (in_array($subtask, $subtasks ?? [])) { if (!class_exists(RecoverUploadLocationsHelper::class)) { $this->logger->error("No UserForms helper detected"); } else { $this->extend('preFileMigrationSubtask', $subtask); $this->logger->notice("######################################################"); $this->logger->notice("Recovering UserForm uploaded file locations ({$subtask})"); $this->logger->notice("######################################################"); RecoverUploadLocationsHelper::singleton() ->setLogger($this->logger) ->run(); $this->extend('postFileMigrationSubtask', $subtask); } } $this->extend('postFileMigration'); $this->logger->info("Done!"); } public function getDescription() { return <<logger = $logger; return $this; } /** * @return AssetStore */ protected function getStore() { return singleton(AssetStore::class); } /** * @param array $args * @throws \InvalidArgumentException */ protected function validateArgs($args) { if (!empty($args['only'])) { $only = explode(',', $args['only'] ?? ''); $diff = array_diff($only ?? [], $this->defaultSubtasks); $diff = array_diff($diff ?? [], $this->optInSubtasks); if ($diff) { throw new \InvalidArgumentException('Invalid subtasks detected: ' . implode(', ', $diff)); } } } /** * TODO Refactor this whole mess into Symfony Console on a TaskRunner level, * with a thin wrapper to show coloured console output via a browser: * https://github.com/silverstripe/silverstripe-framework/issues/5542 * @throws \Exception */ protected function addLogHandlers() { // Using a global service here so other systems can control and redirect log output, // for example when this task is run as part of a queuedjob $logger = Injector::inst()->get(LoggerInterface::class)->withName('log'); $formatter = new ColoredLineFormatter(); $formatter->ignoreEmptyContextAndExtra(); $errorHandler = new StreamHandler('php://stderr', Logger::ERROR); $errorHandler->setFormatter($formatter); $standardHandler = new StreamHandler('php://stdout'); $standardHandler->setFormatter($formatter); // Avoid double logging of errors $standardFilterHandler = new FilterHandler( $standardHandler, Logger::DEBUG, Logger::WARNING ); $logger->pushHandler($standardFilterHandler); $logger->pushHandler($errorHandler); $this->logger = $logger; } }