entityManager = $entityManager; $this->config = $config; $this->configWriter = $configWriter; $this->fileManager = $fileManager; $this->metadata = $metadata; $this->ormMetadataData = $ormMetadataData; $this->hookManager = $hookManager; $this->schemaProxy = $schemaProxy; $this->log = $log; $this->module = $module; } /** * Rebuild the system with metadata, database and cache clearing. */ public function rebuild(?array $entityList = null): void { $this->clearCache(); $this->disableHooks(); $this->checkModules(); $this->populateConfigParameters(); $this->rebuildMetadata(); $this->rebuildDatabase($entityList); $this->rebuildScheduledJobs(); $this->enableHooks(); } /** * Clear a cache. */ public function clearCache(): void { $this->module->clearCache(); $result = $this->fileManager->removeInDir($this->cachePath); if ($result != true) { throw new Error("Error while clearing cache"); } $this->updateCacheTimestamp(); } /** * Rebuild database. */ public function rebuildDatabase(?array $entityList = null): void { $schema = $this->schemaProxy; try { $result = $schema->rebuild($entityList); } catch (Throwable $e) { $result = false; $this->log->error( "Failed to rebuild database schema. Details: ". $e->getMessage() . " at " . $e->getFile() . ":" . $e->getLine() ); } if ($result != true) { throw new Error("Error while rebuilding database. See log file for details."); } $databaseType = strtolower($schema->getDatabaseHelper()->getDatabaseType()); if ( !$this->config->get('actualDatabaseType') || $this->config->get('actualDatabaseType') !== $databaseType ) { $this->configWriter->set('actualDatabaseType', $databaseType); } $databaseVersion = $schema->getDatabaseHelper()->getDatabaseVersion(); if ( !$this->config->get('actualDatabaseVersion') || $this->config->get('actualDatabaseVersion') !== $databaseVersion ) { $this->configWriter->set('actualDatabaseVersion', $databaseVersion); } $this->configWriter->updateCacheTimestamp(); $this->configWriter->save(); } /** * Rebuild metadata. */ public function rebuildMetadata(): void { $metadata = $this->metadata; $metadata->init(true); $ormData = $this->ormMetadataData->getData(true); $this->entityManager->getMetadata()->updateData(); $this->updateCacheTimestamp(); if (empty($ormData)) { throw new Error("Error while rebuilding metadata. See log file for details."); } } /** * Rebuild scheduled jobs. Create system jobs. */ public function rebuildScheduledJobs(): void { $jobDefs = array_merge( $this->metadata->get(['entityDefs', 'ScheduledJob', 'jobs'], []), // for bc $this->metadata->get(['app', 'scheduledJobs'], []) ); $systemJobNameList = []; foreach ($jobDefs as $jobName => $defs) { if (!$jobName) { continue; } if (empty($defs['isSystem']) || empty($defs['scheduling'])) { continue; } $systemJobNameList[] = $jobName; $sj = $this->entityManager ->getRDBRepository('ScheduledJob') ->where([ 'job' => $jobName, 'status' => 'Active', 'scheduling' => $defs['scheduling'], ]) ->findOne(); if ($sj) { continue; } $existingJob = $this->entityManager ->getRDBRepository('ScheduledJob') ->where([ 'job' => $jobName, ]) ->findOne(); if ($existingJob) { $this->entityManager->removeEntity($existingJob); } $name = $jobName; if (!empty($defs['name'])) { $name = $defs['name']; } $this->entityManager->createEntity('ScheduledJob', [ 'job' => $jobName, 'status' => 'Active', 'scheduling' => $defs['scheduling'], 'isInternal' => true, 'name' => $name, ]); } $internalScheduledJobList = $this->entityManager ->getRDBRepository('ScheduledJob') ->where([ 'isInternal' => true, ]) ->find(); foreach ($internalScheduledJobList as $scheduledJob) { $jobName = $scheduledJob->get('job'); if (!in_array($jobName, $systemJobNameList)) { $this->entityManager ->getRDBRepository('ScheduledJob') ->deleteFromDb($scheduledJob->id); } } } /** * Update cache timestamp. */ public function updateCacheTimestamp(): void { $this->configWriter->updateCacheTimestamp(); $this->configWriter->save(); } protected function populateConfigParameters(): void { $this->setFullTextConfigParameters(); $this->setCryptKeyConfigParameter(); $this->configWriter->save(); } protected function setFullTextConfigParameters(): void { $platform = $this->config->get('database.platform') ?? null; $driver = $this->config->get('database.driver') ?? ''; if ($platform !== 'Mysql' && strpos($driver, 'mysql') === false) { return; } $fullTextSearchMinLength = null; $sql = "SHOW VARIABLES LIKE 'ft_min_word_len'"; $row = $this->entityManager ->getSqlExecutor() ->execute($sql) ->fetch(); if ($row && isset($row['Value'])) { $fullTextSearchMinLength = intval($row['Value']); } $this->configWriter->set('fullTextSearchMinLength', $fullTextSearchMinLength); } protected function setCryptKeyConfigParameter(): void { if ($this->config->get('cryptKey')) { return; } $cryptKey = Util::generateSecretKey(); $this->configWriter->set('cryptKey', $cryptKey); } protected function disableHooks(): void { $this->hookManager->disable(); } protected function enableHooks(): void { $this->hookManager->enable(); } private function checkModules(): void { $moduleNameList = $this->module->getList(); if (count(array_unique($moduleNameList)) !== count($moduleNameList)) { throw new Error( "There is a same module in both `custom` and `internal` directories. " . "Should be only in one location." ); } } }