[ 'prefix' => 'w', 'flag' => true, 'longPrefix' => 'wet-run', 'description' => 'Find and remove all orphan triples related to files for removed items.', ], 'verbose' => [ 'prefix' => 'v', 'flag' => true, 'longPrefix' => 'Verbose', 'description' => 'Force script to be more details', ], ]; } protected function provideDescription() { return 'Tool to remove orphan files attached to removed items. By default in dry-run'; } protected function provideUsage() { return [ 'prefix' => 'h', 'longPrefix' => 'help', 'description' => 'Prints a help statement' ]; } /** * @return Report * @throws \oat\oatbox\service\exception\InvalidServiceManagerException * @throws \common_exception_Error */ protected function run() { $this->init(); $this->report = Report::createInfo('Following files'); /** @var ResourceFileSerializer $serializer */ $serializer = $this->getServiceManager()->get(ResourceFileSerializer::SERVICE_ID); $total = 0; $resourceCollection = new ResourceCollection(GenerisRdf::CLASS_GENERIS_FILE); foreach ($resourceCollection as $resource) { $total++; try { $subject = $this->getResource($resource['subject']); $file = $serializer->unserialize($subject); $isRedundant = $this->isRedundant($file); if ($isRedundant) { $this->manageRedundant($subject, $file); } else { $this->manageOrphan($subject, $file); } } catch (\Exception $exception) { $this->errorsCount++; $this->report->add(Report::createFailure($exception->getMessage())); } } $this->cleanUp(); $this->report->add(new Report(Report::TYPE_SUCCESS, sprintf('%s Total Files Found in RDS, where: ', $total))); $this->prepareReport(); return $this->report; } private function init() { if ($this->getOption('wet-run')) { $this->wetRun = true; } $this->verbose = $this->getOption('verbose'); } protected function showTime() { return true; } /** * @param core_kernel_classes_Resource $resource * @return bool */ private function isOrphan(core_kernel_classes_Resource $resource) { $sql = 'SELECT subject FROM statements s WHERE s.object=?'; $stmt = $this->getPersistence()->query($sql, [$resource->getUri()]); $res = $stmt->fetchAll(); return 0 === count($res); } private function getPersistence() { return $this->getServiceLocator() ->get(\common_persistence_Manager::SERVICE_ID) ->getPersistenceById('default'); } private function getRedundantFiles() { return [ 'qti.xml' //special case, see linked story ( has been stored at RDS, but never referenced via resource ). ]; } /** * @param $resource * @return void */ private function markForRemoval(core_kernel_classes_Resource $resource) { $this->markedTobeRemoved[] = $resource; } /** * @param core_kernel_classes_Resource $resource * @param FileSystemHandler $file */ private function manageRedundant(core_kernel_classes_Resource $resource, FileSystemHandler $file) { $this->redundantCount++; $message = sprintf('resource URI %s : attached file %s', $resource->getUri(), $file->getPrefix()); if ($this->verbose) { $this->report->add(new Report(Report::TYPE_INFO, $message)); } $this->getLogger()->info($message); $this->markForRemoval($resource); } /** * @param core_kernel_classes_Resource $resource * @param FileSystemHandler $file */ private function manageOrphan(core_kernel_classes_Resource $resource, FileSystemHandler $file) { $isOrphan = $this->isOrphan($resource); if ($isOrphan && !$file->exists()) { if ($this->verbose) { $this->report->add(new Report(Report::TYPE_INFO, sprintf('URI %s : File %s', $resource->getUri(), $file->getPrefix()))); } $this->markForRemoval($resource); $this->affectedCount++; } } private function cleanUp() { if ($this->wetRun) { foreach ($this->markedTobeRemoved as $resource) { $resource->delete(); $this->removedCount++; $this->getLogger()->info(sprintf('%s has been removed', $resource->getUri())); } } } /** * @param $file * @return bool */ private function isRedundant(FileSystemHandler $file) { return $file->getFileSystemId() === null; } private function prepareReport() { $this->report->add(new Report(Report::TYPE_SUCCESS, sprintf('%s redundant at RDS', $this->redundantCount))); $this->report->add(new Report(Report::TYPE_SUCCESS, sprintf('%s missing at FS', $this->affectedCount))); $this->report->add(new Report(Report::TYPE_SUCCESS, sprintf('%s removed at FS', $this->removedCount))); $this->report->add(new Report(Report::TYPE_SUCCESS, sprintf('Peak memory %s Mb', memory_get_peak_usage() / 1024 / 1024))); if ($this->errorsCount) { $this->report->add(new Report(Report::TYPE_ERROR, sprintf('%s errors happened, check details above', $this->errorsCount))); } } }