app = $app; } public function handle(Request $request, Closure $next) { // We always need an encryption key if not already present $this->generateAppKey(); if ($this->app->runningInConsole()) { // Allow the console to run successfully even if we're not installed return $next($request); } // See if the successful flag has been written to the .env file $isAppInstalled = MiscHelper::getEnvironmentSetting('APP_INSTALLED'); // See if the vendors are out-of-date if ($this->isVendorUpdateRequired()) { return $isAppInstalled ? redirect('/update') : redirect('/install'); } if ($request->is('install/*')) { // Already in the installer // For security reasons, don't allow the installer to be used if it has been previously completed if (boolval($isAppInstalled)) { return redirect(route('home')); } return $next($request); } if ($isAppInstalled) { // See if an update is necessary $this->updateDatabaseIfRequired(); // App is configured, continue on return $next($request); } return redirect(route('install.database')); } private function generateAppKey() { // Generate an application key and store to the .env file if (!file_exists(MiscHelper::getEnvironmentFilePath())) { $key = MiscHelper::randomString(32); file_put_contents(MiscHelper::getEnvironmentFilePath(), sprintf('APP_KEY=%s', $key) . PHP_EOL); app('config')->set(['app' => ['key' => $key]]); } } private function isVendorUpdateRequired() { $vendorsVersionFilename = $this->app->basePath('vendor/version.txt'); if (!file_exists($vendorsVersionFilename)) { return true; } return trim(file_get_contents($vendorsVersionFilename)) != trim(config('app.version')); } private function updateDatabaseIfRequired() { $versionNumber = UserConfig::getOrCreateModel('app_version'); $appVersionNumber = config('app.version'); if (is_null($appVersionNumber) || $versionNumber->value != $appVersionNumber) { Log::info('Upgrading database', ['new_version' => $appVersionNumber]); Artisan::call('config:cache'); Artisan::call('cache:clear'); Artisan::call('view:clear'); Artisan::call('migrate', ['--force' => true]); Artisan::call('db:seed', ['--force' => true]); // Run any data migrations relevant to the new version $dataMigrationsFolder = join(DIRECTORY_SEPARATOR, [dirname(dirname(dirname(__DIR__))), 'database', 'data_migrations']); $di = new \RecursiveDirectoryIterator($dataMigrationsFolder, \RecursiveDirectoryIterator::SKIP_DOTS); $updateClasses = []; // First load all data migration classes and examine the version number to decide if we need it or not /** @var \SplFileInfo $fileInfo */ foreach ($di as $fileInfo) { if (!$di->isFile() || $di->getExtension() != 'php') { continue; } $className = substr($fileInfo->getFilename(), 0, strlen($fileInfo->getFilename()) - 4); /** @var DataMigration $upgradeClass */ $upgradeClass = new $className; if (version_compare($versionNumber->value, $upgradeClass->getVersion()) < 0) { $updateClasses[] = $upgradeClass; } } // Now run the migrations foreach ($updateClasses as $upgradeClass) { $upgradeClass->run($versionNumber); } // Save the new version number $versionNumber->value = $appVersionNumber; $versionNumber->save(); // Rebuild the permissions cache $helper = new PermissionsHelper(); $helper->rebuildCache(); } } }