Passed
Push — master ( dca246...fba64a )
by Morris
12:43 queued 12s
created
lib/private/legacy/OC_App.php 2 patches
Indentation   +1066 added lines, -1066 removed lines patch added patch discarded remove patch
@@ -65,1070 +65,1070 @@
 block discarded – undo
65 65
  * upgrading and removing apps.
66 66
  */
67 67
 class OC_App {
68
-	private static $adminForms = [];
69
-	private static $personalForms = [];
70
-	private static $appTypes = [];
71
-	private static $loadedApps = [];
72
-	private static $altLogin = [];
73
-	private static $alreadyRegistered = [];
74
-	public const supportedApp = 300;
75
-	public const officialApp = 200;
76
-
77
-	/**
78
-	 * clean the appId
79
-	 *
80
-	 * @param string $app AppId that needs to be cleaned
81
-	 * @return string
82
-	 */
83
-	public static function cleanAppId(string $app): string {
84
-		return str_replace(['\0', '/', '\\', '..'], '', $app);
85
-	}
86
-
87
-	/**
88
-	 * Check if an app is loaded
89
-	 *
90
-	 * @param string $app
91
-	 * @return bool
92
-	 */
93
-	public static function isAppLoaded(string $app): bool {
94
-		return in_array($app, self::$loadedApps, true);
95
-	}
96
-
97
-	/**
98
-	 * loads all apps
99
-	 *
100
-	 * @param string[] $types
101
-	 * @return bool
102
-	 *
103
-	 * This function walks through the ownCloud directory and loads all apps
104
-	 * it can find. A directory contains an app if the file /appinfo/info.xml
105
-	 * exists.
106
-	 *
107
-	 * if $types is set to non-empty array, only apps of those types will be loaded
108
-	 */
109
-	public static function loadApps(array $types = []): bool {
110
-		if ((bool) \OC::$server->getSystemConfig()->getValue('maintenance', false)) {
111
-			return false;
112
-		}
113
-		// Load the enabled apps here
114
-		$apps = self::getEnabledApps();
115
-
116
-		// Add each apps' folder as allowed class path
117
-		foreach ($apps as $app) {
118
-			$path = self::getAppPath($app);
119
-			if ($path !== false) {
120
-				self::registerAutoloading($app, $path);
121
-			}
122
-		}
123
-
124
-		// prevent app.php from printing output
125
-		ob_start();
126
-		foreach ($apps as $app) {
127
-			if (($types === [] or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
128
-				self::loadApp($app);
129
-			}
130
-		}
131
-		ob_end_clean();
132
-
133
-		return true;
134
-	}
135
-
136
-	/**
137
-	 * load a single app
138
-	 *
139
-	 * @param string $app
140
-	 * @throws Exception
141
-	 */
142
-	public static function loadApp(string $app) {
143
-		self::$loadedApps[] = $app;
144
-		$appPath = self::getAppPath($app);
145
-		if ($appPath === false) {
146
-			return;
147
-		}
148
-
149
-		// in case someone calls loadApp() directly
150
-		self::registerAutoloading($app, $appPath);
151
-
152
-		/** @var \OC\AppFramework\Bootstrap\Coordinator $coordinator */
153
-		$coordinator = \OC::$server->query(\OC\AppFramework\Bootstrap\Coordinator::class);
154
-		$isBootable = $coordinator->isBootable($app);
155
-
156
-		$hasAppPhpFile = is_file($appPath . '/appinfo/app.php');
157
-
158
-		if ($isBootable && $hasAppPhpFile) {
159
-			\OC::$server->getLogger()->error('/appinfo/app.php is not loaded when \OCP\AppFramework\Bootstrap\IBootstrap on the application class is used. Migrate everything from app.php to the Application class.', [
160
-				'app' => $app,
161
-			]);
162
-		} elseif ($hasAppPhpFile) {
163
-			\OC::$server->getLogger()->debug('/appinfo/app.php is deprecated, use \OCP\AppFramework\Bootstrap\IBootstrap on the application class instead.', [
164
-				'app' => $app,
165
-			]);
166
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
167
-			try {
168
-				self::requireAppFile($app);
169
-			} catch (Throwable $ex) {
170
-				if ($ex instanceof ServerNotAvailableException) {
171
-					throw $ex;
172
-				}
173
-				if (!\OC::$server->getAppManager()->isShipped($app) && !self::isType($app, ['authentication'])) {
174
-					\OC::$server->getLogger()->logException($ex, [
175
-						'message' => "App $app threw an error during app.php load and will be disabled: " . $ex->getMessage(),
176
-					]);
177
-
178
-					// Only disable apps which are not shipped and that are not authentication apps
179
-					\OC::$server->getAppManager()->disableApp($app, true);
180
-				} else {
181
-					\OC::$server->getLogger()->logException($ex, [
182
-						'message' => "App $app threw an error during app.php load: " . $ex->getMessage(),
183
-					]);
184
-				}
185
-			}
186
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
187
-		}
188
-		$coordinator->bootApp($app);
189
-
190
-		$info = self::getAppInfo($app);
191
-		if (!empty($info['activity']['filters'])) {
192
-			foreach ($info['activity']['filters'] as $filter) {
193
-				\OC::$server->getActivityManager()->registerFilter($filter);
194
-			}
195
-		}
196
-		if (!empty($info['activity']['settings'])) {
197
-			foreach ($info['activity']['settings'] as $setting) {
198
-				\OC::$server->getActivityManager()->registerSetting($setting);
199
-			}
200
-		}
201
-		if (!empty($info['activity']['providers'])) {
202
-			foreach ($info['activity']['providers'] as $provider) {
203
-				\OC::$server->getActivityManager()->registerProvider($provider);
204
-			}
205
-		}
206
-
207
-		if (!empty($info['settings']['admin'])) {
208
-			foreach ($info['settings']['admin'] as $setting) {
209
-				\OC::$server->getSettingsManager()->registerSetting('admin', $setting);
210
-			}
211
-		}
212
-		if (!empty($info['settings']['admin-section'])) {
213
-			foreach ($info['settings']['admin-section'] as $section) {
214
-				\OC::$server->getSettingsManager()->registerSection('admin', $section);
215
-			}
216
-		}
217
-		if (!empty($info['settings']['personal'])) {
218
-			foreach ($info['settings']['personal'] as $setting) {
219
-				\OC::$server->getSettingsManager()->registerSetting('personal', $setting);
220
-			}
221
-		}
222
-		if (!empty($info['settings']['personal-section'])) {
223
-			foreach ($info['settings']['personal-section'] as $section) {
224
-				\OC::$server->getSettingsManager()->registerSection('personal', $section);
225
-			}
226
-		}
227
-
228
-		if (!empty($info['collaboration']['plugins'])) {
229
-			// deal with one or many plugin entries
230
-			$plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
231
-				[$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
232
-			foreach ($plugins as $plugin) {
233
-				if ($plugin['@attributes']['type'] === 'collaborator-search') {
234
-					$pluginInfo = [
235
-						'shareType' => $plugin['@attributes']['share-type'],
236
-						'class' => $plugin['@value'],
237
-					];
238
-					\OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo);
239
-				} elseif ($plugin['@attributes']['type'] === 'autocomplete-sort') {
240
-					\OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']);
241
-				}
242
-			}
243
-		}
244
-	}
245
-
246
-	/**
247
-	 * @internal
248
-	 * @param string $app
249
-	 * @param string $path
250
-	 * @param bool $force
251
-	 */
252
-	public static function registerAutoloading(string $app, string $path, bool $force = false) {
253
-		$key = $app . '-' . $path;
254
-		if (!$force && isset(self::$alreadyRegistered[$key])) {
255
-			return;
256
-		}
257
-
258
-		self::$alreadyRegistered[$key] = true;
259
-
260
-		// Register on PSR-4 composer autoloader
261
-		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
262
-		\OC::$server->registerNamespace($app, $appNamespace);
263
-
264
-		if (file_exists($path . '/composer/autoload.php')) {
265
-			require_once $path . '/composer/autoload.php';
266
-		} else {
267
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
268
-			// Register on legacy autoloader
269
-			\OC::$loader->addValidRoot($path);
270
-		}
271
-
272
-		// Register Test namespace only when testing
273
-		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
274
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
275
-		}
276
-	}
277
-
278
-	/**
279
-	 * Load app.php from the given app
280
-	 *
281
-	 * @param string $app app name
282
-	 * @throws Error
283
-	 */
284
-	private static function requireAppFile(string $app) {
285
-		// encapsulated here to avoid variable scope conflicts
286
-		require_once $app . '/appinfo/app.php';
287
-	}
288
-
289
-	/**
290
-	 * check if an app is of a specific type
291
-	 *
292
-	 * @param string $app
293
-	 * @param array $types
294
-	 * @return bool
295
-	 */
296
-	public static function isType(string $app, array $types): bool {
297
-		$appTypes = self::getAppTypes($app);
298
-		foreach ($types as $type) {
299
-			if (array_search($type, $appTypes) !== false) {
300
-				return true;
301
-			}
302
-		}
303
-		return false;
304
-	}
305
-
306
-	/**
307
-	 * get the types of an app
308
-	 *
309
-	 * @param string $app
310
-	 * @return array
311
-	 */
312
-	private static function getAppTypes(string $app): array {
313
-		//load the cache
314
-		if (count(self::$appTypes) == 0) {
315
-			self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
316
-		}
317
-
318
-		if (isset(self::$appTypes[$app])) {
319
-			return explode(',', self::$appTypes[$app]);
320
-		}
321
-
322
-		return [];
323
-	}
324
-
325
-	/**
326
-	 * read app types from info.xml and cache them in the database
327
-	 */
328
-	public static function setAppTypes(string $app) {
329
-		$appManager = \OC::$server->getAppManager();
330
-		$appData = $appManager->getAppInfo($app);
331
-		if (!is_array($appData)) {
332
-			return;
333
-		}
334
-
335
-		if (isset($appData['types'])) {
336
-			$appTypes = implode(',', $appData['types']);
337
-		} else {
338
-			$appTypes = '';
339
-			$appData['types'] = [];
340
-		}
341
-
342
-		$config = \OC::$server->getConfig();
343
-		$config->setAppValue($app, 'types', $appTypes);
344
-
345
-		if ($appManager->hasProtectedAppType($appData['types'])) {
346
-			$enabled = $config->getAppValue($app, 'enabled', 'yes');
347
-			if ($enabled !== 'yes' && $enabled !== 'no') {
348
-				$config->setAppValue($app, 'enabled', 'yes');
349
-			}
350
-		}
351
-	}
352
-
353
-	/**
354
-	 * Returns apps enabled for the current user.
355
-	 *
356
-	 * @param bool $forceRefresh whether to refresh the cache
357
-	 * @param bool $all whether to return apps for all users, not only the
358
-	 * currently logged in one
359
-	 * @return string[]
360
-	 */
361
-	public static function getEnabledApps(bool $forceRefresh = false, bool $all = false): array {
362
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
363
-			return [];
364
-		}
365
-		// in incognito mode or when logged out, $user will be false,
366
-		// which is also the case during an upgrade
367
-		$appManager = \OC::$server->getAppManager();
368
-		if ($all) {
369
-			$user = null;
370
-		} else {
371
-			$user = \OC::$server->getUserSession()->getUser();
372
-		}
373
-
374
-		if (is_null($user)) {
375
-			$apps = $appManager->getInstalledApps();
376
-		} else {
377
-			$apps = $appManager->getEnabledAppsForUser($user);
378
-		}
379
-		$apps = array_filter($apps, function ($app) {
380
-			return $app !== 'files';//we add this manually
381
-		});
382
-		sort($apps);
383
-		array_unshift($apps, 'files');
384
-		return $apps;
385
-	}
386
-
387
-	/**
388
-	 * checks whether or not an app is enabled
389
-	 *
390
-	 * @param string $app app
391
-	 * @return bool
392
-	 * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
393
-	 *
394
-	 * This function checks whether or not an app is enabled.
395
-	 */
396
-	public static function isEnabled(string $app): bool {
397
-		return \OC::$server->getAppManager()->isEnabledForUser($app);
398
-	}
399
-
400
-	/**
401
-	 * enables an app
402
-	 *
403
-	 * @param string $appId
404
-	 * @param array $groups (optional) when set, only these groups will have access to the app
405
-	 * @throws \Exception
406
-	 * @return void
407
-	 *
408
-	 * This function set an app as enabled in appconfig.
409
-	 */
410
-	public function enable(string $appId,
411
-						   array $groups = []) {
412
-
413
-		// Check if app is already downloaded
414
-		/** @var Installer $installer */
415
-		$installer = \OC::$server->query(Installer::class);
416
-		$isDownloaded = $installer->isDownloaded($appId);
417
-
418
-		if (!$isDownloaded) {
419
-			$installer->downloadApp($appId);
420
-		}
421
-
422
-		$installer->installApp($appId);
423
-
424
-		$appManager = \OC::$server->getAppManager();
425
-		if ($groups !== []) {
426
-			$groupManager = \OC::$server->getGroupManager();
427
-			$groupsList = [];
428
-			foreach ($groups as $group) {
429
-				$groupItem = $groupManager->get($group);
430
-				if ($groupItem instanceof \OCP\IGroup) {
431
-					$groupsList[] = $groupManager->get($group);
432
-				}
433
-			}
434
-			$appManager->enableAppForGroups($appId, $groupsList);
435
-		} else {
436
-			$appManager->enableApp($appId);
437
-		}
438
-	}
439
-
440
-	/**
441
-	 * Get the path where to install apps
442
-	 *
443
-	 * @return string|false
444
-	 */
445
-	public static function getInstallPath() {
446
-		if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
447
-			return false;
448
-		}
449
-
450
-		foreach (OC::$APPSROOTS as $dir) {
451
-			if (isset($dir['writable']) && $dir['writable'] === true) {
452
-				return $dir['path'];
453
-			}
454
-		}
455
-
456
-		\OCP\Util::writeLog('core', 'No application directories are marked as writable.', ILogger::ERROR);
457
-		return null;
458
-	}
459
-
460
-
461
-	/**
462
-	 * search for an app in all app-directories
463
-	 *
464
-	 * @param string $appId
465
-	 * @return false|string
466
-	 */
467
-	public static function findAppInDirectories(string $appId) {
468
-		$sanitizedAppId = self::cleanAppId($appId);
469
-		if ($sanitizedAppId !== $appId) {
470
-			return false;
471
-		}
472
-		static $app_dir = [];
473
-
474
-		if (isset($app_dir[$appId])) {
475
-			return $app_dir[$appId];
476
-		}
477
-
478
-		$possibleApps = [];
479
-		foreach (OC::$APPSROOTS as $dir) {
480
-			if (file_exists($dir['path'] . '/' . $appId)) {
481
-				$possibleApps[] = $dir;
482
-			}
483
-		}
484
-
485
-		if (empty($possibleApps)) {
486
-			return false;
487
-		} elseif (count($possibleApps) === 1) {
488
-			$dir = array_shift($possibleApps);
489
-			$app_dir[$appId] = $dir;
490
-			return $dir;
491
-		} else {
492
-			$versionToLoad = [];
493
-			foreach ($possibleApps as $possibleApp) {
494
-				$version = self::getAppVersionByPath($possibleApp['path'] . '/' . $appId);
495
-				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
496
-					$versionToLoad = [
497
-						'dir' => $possibleApp,
498
-						'version' => $version,
499
-					];
500
-				}
501
-			}
502
-			$app_dir[$appId] = $versionToLoad['dir'];
503
-			return $versionToLoad['dir'];
504
-			//TODO - write test
505
-		}
506
-	}
507
-
508
-	/**
509
-	 * Get the directory for the given app.
510
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
511
-	 *
512
-	 * @param string $appId
513
-	 * @return string|false
514
-	 * @deprecated 11.0.0 use \OC::$server->getAppManager()->getAppPath()
515
-	 */
516
-	public static function getAppPath(string $appId) {
517
-		if ($appId === null || trim($appId) === '') {
518
-			return false;
519
-		}
520
-
521
-		if (($dir = self::findAppInDirectories($appId)) != false) {
522
-			return $dir['path'] . '/' . $appId;
523
-		}
524
-		return false;
525
-	}
526
-
527
-	/**
528
-	 * Get the path for the given app on the access
529
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
530
-	 *
531
-	 * @param string $appId
532
-	 * @return string|false
533
-	 * @deprecated 18.0.0 use \OC::$server->getAppManager()->getAppWebPath()
534
-	 */
535
-	public static function getAppWebPath(string $appId) {
536
-		if (($dir = self::findAppInDirectories($appId)) != false) {
537
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
538
-		}
539
-		return false;
540
-	}
541
-
542
-	/**
543
-	 * get the last version of the app from appinfo/info.xml
544
-	 *
545
-	 * @param string $appId
546
-	 * @param bool $useCache
547
-	 * @return string
548
-	 * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion()
549
-	 */
550
-	public static function getAppVersion(string $appId, bool $useCache = true): string {
551
-		return \OC::$server->getAppManager()->getAppVersion($appId, $useCache);
552
-	}
553
-
554
-	/**
555
-	 * get app's version based on it's path
556
-	 *
557
-	 * @param string $path
558
-	 * @return string
559
-	 */
560
-	public static function getAppVersionByPath(string $path): string {
561
-		$infoFile = $path . '/appinfo/info.xml';
562
-		$appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
563
-		return isset($appData['version']) ? $appData['version'] : '';
564
-	}
565
-
566
-
567
-	/**
568
-	 * Read all app metadata from the info.xml file
569
-	 *
570
-	 * @param string $appId id of the app or the path of the info.xml file
571
-	 * @param bool $path
572
-	 * @param string $lang
573
-	 * @return array|null
574
-	 * @note all data is read from info.xml, not just pre-defined fields
575
-	 * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppInfo()
576
-	 */
577
-	public static function getAppInfo(string $appId, bool $path = false, string $lang = null) {
578
-		return \OC::$server->getAppManager()->getAppInfo($appId, $path, $lang);
579
-	}
580
-
581
-	/**
582
-	 * Returns the navigation
583
-	 *
584
-	 * @return array
585
-	 * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll()
586
-	 *
587
-	 * This function returns an array containing all entries added. The
588
-	 * entries are sorted by the key 'order' ascending. Additional to the keys
589
-	 * given for each app the following keys exist:
590
-	 *   - active: boolean, signals if the user is on this navigation entry
591
-	 */
592
-	public static function getNavigation(): array {
593
-		return OC::$server->getNavigationManager()->getAll();
594
-	}
595
-
596
-	/**
597
-	 * Returns the Settings Navigation
598
-	 *
599
-	 * @return string[]
600
-	 * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll('settings')
601
-	 *
602
-	 * This function returns an array containing all settings pages added. The
603
-	 * entries are sorted by the key 'order' ascending.
604
-	 */
605
-	public static function getSettingsNavigation(): array {
606
-		return OC::$server->getNavigationManager()->getAll('settings');
607
-	}
608
-
609
-	/**
610
-	 * get the id of loaded app
611
-	 *
612
-	 * @return string
613
-	 */
614
-	public static function getCurrentApp(): string {
615
-		$request = \OC::$server->getRequest();
616
-		$script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
617
-		$topFolder = substr($script, 0, strpos($script, '/') ?: 0);
618
-		if (empty($topFolder)) {
619
-			$path_info = $request->getPathInfo();
620
-			if ($path_info) {
621
-				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
622
-			}
623
-		}
624
-		if ($topFolder == 'apps') {
625
-			$length = strlen($topFolder);
626
-			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1) ?: '';
627
-		} else {
628
-			return $topFolder;
629
-		}
630
-	}
631
-
632
-	/**
633
-	 * @param string $type
634
-	 * @return array
635
-	 */
636
-	public static function getForms(string $type): array {
637
-		$forms = [];
638
-		switch ($type) {
639
-			case 'admin':
640
-				$source = self::$adminForms;
641
-				break;
642
-			case 'personal':
643
-				$source = self::$personalForms;
644
-				break;
645
-			default:
646
-				return [];
647
-		}
648
-		foreach ($source as $form) {
649
-			$forms[] = include $form;
650
-		}
651
-		return $forms;
652
-	}
653
-
654
-	/**
655
-	 * register an admin form to be shown
656
-	 *
657
-	 * @param string $app
658
-	 * @param string $page
659
-	 */
660
-	public static function registerAdmin(string $app, string $page) {
661
-		self::$adminForms[] = $app . '/' . $page . '.php';
662
-	}
663
-
664
-	/**
665
-	 * register a personal form to be shown
666
-	 * @param string $app
667
-	 * @param string $page
668
-	 */
669
-	public static function registerPersonal(string $app, string $page) {
670
-		self::$personalForms[] = $app . '/' . $page . '.php';
671
-	}
672
-
673
-	/**
674
-	 * @param array $entry
675
-	 */
676
-	public static function registerLogIn(array $entry) {
677
-		self::$altLogin[] = $entry;
678
-	}
679
-
680
-	/**
681
-	 * @return array
682
-	 */
683
-	public static function getAlternativeLogIns(): array {
684
-		return self::$altLogin;
685
-	}
686
-
687
-	/**
688
-	 * get a list of all apps in the apps folder
689
-	 *
690
-	 * @return string[] an array of app names (string IDs)
691
-	 * @todo: change the name of this method to getInstalledApps, which is more accurate
692
-	 */
693
-	public static function getAllApps(): array {
694
-		$apps = [];
695
-
696
-		foreach (OC::$APPSROOTS as $apps_dir) {
697
-			if (!is_readable($apps_dir['path'])) {
698
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], ILogger::WARN);
699
-				continue;
700
-			}
701
-			$dh = opendir($apps_dir['path']);
702
-
703
-			if (is_resource($dh)) {
704
-				while (($file = readdir($dh)) !== false) {
705
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
706
-						$apps[] = $file;
707
-					}
708
-				}
709
-			}
710
-		}
711
-
712
-		$apps = array_unique($apps);
713
-
714
-		return $apps;
715
-	}
716
-
717
-	/**
718
-	 * List all apps, this is used in apps.php
719
-	 *
720
-	 * @return array
721
-	 */
722
-	public function listAllApps(): array {
723
-		$installedApps = OC_App::getAllApps();
724
-
725
-		$appManager = \OC::$server->getAppManager();
726
-		//we don't want to show configuration for these
727
-		$blacklist = $appManager->getAlwaysEnabledApps();
728
-		$appList = [];
729
-		$langCode = \OC::$server->getL10N('core')->getLanguageCode();
730
-		$urlGenerator = \OC::$server->getURLGenerator();
731
-		/** @var \OCP\Support\Subscription\IRegistry $subscriptionRegistry */
732
-		$subscriptionRegistry = \OC::$server->query(\OCP\Support\Subscription\IRegistry::class);
733
-		$supportedApps = $subscriptionRegistry->delegateGetSupportedApps();
734
-
735
-		foreach ($installedApps as $app) {
736
-			if (array_search($app, $blacklist) === false) {
737
-				$info = OC_App::getAppInfo($app, false, $langCode);
738
-				if (!is_array($info)) {
739
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', ILogger::ERROR);
740
-					continue;
741
-				}
742
-
743
-				if (!isset($info['name'])) {
744
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', ILogger::ERROR);
745
-					continue;
746
-				}
747
-
748
-				$enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'no');
749
-				$info['groups'] = null;
750
-				if ($enabled === 'yes') {
751
-					$active = true;
752
-				} elseif ($enabled === 'no') {
753
-					$active = false;
754
-				} else {
755
-					$active = true;
756
-					$info['groups'] = $enabled;
757
-				}
758
-
759
-				$info['active'] = $active;
760
-
761
-				if ($appManager->isShipped($app)) {
762
-					$info['internal'] = true;
763
-					$info['level'] = self::officialApp;
764
-					$info['removable'] = false;
765
-				} else {
766
-					$info['internal'] = false;
767
-					$info['removable'] = true;
768
-				}
769
-
770
-				if (in_array($app, $supportedApps)) {
771
-					$info['level'] = self::supportedApp;
772
-				}
773
-
774
-				$appPath = self::getAppPath($app);
775
-				if ($appPath !== false) {
776
-					$appIcon = $appPath . '/img/' . $app . '.svg';
777
-					if (file_exists($appIcon)) {
778
-						$info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
779
-						$info['previewAsIcon'] = true;
780
-					} else {
781
-						$appIcon = $appPath . '/img/app.svg';
782
-						if (file_exists($appIcon)) {
783
-							$info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
784
-							$info['previewAsIcon'] = true;
785
-						}
786
-					}
787
-				}
788
-				// fix documentation
789
-				if (isset($info['documentation']) && is_array($info['documentation'])) {
790
-					foreach ($info['documentation'] as $key => $url) {
791
-						// If it is not an absolute URL we assume it is a key
792
-						// i.e. admin-ldap will get converted to go.php?to=admin-ldap
793
-						if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
794
-							$url = $urlGenerator->linkToDocs($url);
795
-						}
796
-
797
-						$info['documentation'][$key] = $url;
798
-					}
799
-				}
800
-
801
-				$info['version'] = OC_App::getAppVersion($app);
802
-				$appList[] = $info;
803
-			}
804
-		}
805
-
806
-		return $appList;
807
-	}
808
-
809
-	public static function shouldUpgrade(string $app): bool {
810
-		$versions = self::getAppVersions();
811
-		$currentVersion = OC_App::getAppVersion($app);
812
-		if ($currentVersion && isset($versions[$app])) {
813
-			$installedVersion = $versions[$app];
814
-			if (!version_compare($currentVersion, $installedVersion, '=')) {
815
-				return true;
816
-			}
817
-		}
818
-		return false;
819
-	}
820
-
821
-	/**
822
-	 * Adjust the number of version parts of $version1 to match
823
-	 * the number of version parts of $version2.
824
-	 *
825
-	 * @param string $version1 version to adjust
826
-	 * @param string $version2 version to take the number of parts from
827
-	 * @return string shortened $version1
828
-	 */
829
-	private static function adjustVersionParts(string $version1, string $version2): string {
830
-		$version1 = explode('.', $version1);
831
-		$version2 = explode('.', $version2);
832
-		// reduce $version1 to match the number of parts in $version2
833
-		while (count($version1) > count($version2)) {
834
-			array_pop($version1);
835
-		}
836
-		// if $version1 does not have enough parts, add some
837
-		while (count($version1) < count($version2)) {
838
-			$version1[] = '0';
839
-		}
840
-		return implode('.', $version1);
841
-	}
842
-
843
-	/**
844
-	 * Check whether the current ownCloud version matches the given
845
-	 * application's version requirements.
846
-	 *
847
-	 * The comparison is made based on the number of parts that the
848
-	 * app info version has. For example for ownCloud 6.0.3 if the
849
-	 * app info version is expecting version 6.0, the comparison is
850
-	 * made on the first two parts of the ownCloud version.
851
-	 * This means that it's possible to specify "requiremin" => 6
852
-	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
853
-	 *
854
-	 * @param string $ocVersion ownCloud version to check against
855
-	 * @param array $appInfo app info (from xml)
856
-	 *
857
-	 * @return boolean true if compatible, otherwise false
858
-	 */
859
-	public static function isAppCompatible(string $ocVersion, array $appInfo, bool $ignoreMax = false): bool {
860
-		$requireMin = '';
861
-		$requireMax = '';
862
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
863
-			$requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
864
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
865
-			$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
866
-		} elseif (isset($appInfo['requiremin'])) {
867
-			$requireMin = $appInfo['requiremin'];
868
-		} elseif (isset($appInfo['require'])) {
869
-			$requireMin = $appInfo['require'];
870
-		}
871
-
872
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
873
-			$requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
874
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
875
-			$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
876
-		} elseif (isset($appInfo['requiremax'])) {
877
-			$requireMax = $appInfo['requiremax'];
878
-		}
879
-
880
-		if (!empty($requireMin)
881
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
882
-		) {
883
-			return false;
884
-		}
885
-
886
-		if (!$ignoreMax && !empty($requireMax)
887
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
888
-		) {
889
-			return false;
890
-		}
891
-
892
-		return true;
893
-	}
894
-
895
-	/**
896
-	 * get the installed version of all apps
897
-	 */
898
-	public static function getAppVersions() {
899
-		static $versions;
900
-
901
-		if (!$versions) {
902
-			$appConfig = \OC::$server->getAppConfig();
903
-			$versions = $appConfig->getValues(false, 'installed_version');
904
-		}
905
-		return $versions;
906
-	}
907
-
908
-	/**
909
-	 * update the database for the app and call the update script
910
-	 *
911
-	 * @param string $appId
912
-	 * @return bool
913
-	 */
914
-	public static function updateApp(string $appId): bool {
915
-		$appPath = self::getAppPath($appId);
916
-		if ($appPath === false) {
917
-			return false;
918
-		}
919
-
920
-		\OC::$server->getAppManager()->clearAppsCache();
921
-		$appData = self::getAppInfo($appId);
922
-
923
-		self::registerAutoloading($appId, $appPath, true);
924
-		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
925
-
926
-		if (file_exists($appPath . '/appinfo/database.xml')) {
927
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
928
-		} else {
929
-			$ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
930
-			$ms->migrate();
931
-		}
932
-
933
-		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
934
-		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
935
-		// update appversion in app manager
936
-		\OC::$server->getAppManager()->clearAppsCache();
937
-		\OC::$server->getAppManager()->getAppVersion($appId, false);
938
-
939
-		// run upgrade code
940
-		if (file_exists($appPath . '/appinfo/update.php')) {
941
-			self::loadApp($appId);
942
-			include $appPath . '/appinfo/update.php';
943
-		}
944
-		self::setupBackgroundJobs($appData['background-jobs']);
945
-
946
-		//set remote/public handlers
947
-		if (array_key_exists('ocsid', $appData)) {
948
-			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
949
-		} elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
950
-			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
951
-		}
952
-		foreach ($appData['remote'] as $name => $path) {
953
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
954
-		}
955
-		foreach ($appData['public'] as $name => $path) {
956
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
957
-		}
958
-
959
-		self::setAppTypes($appId);
960
-
961
-		$version = \OC_App::getAppVersion($appId);
962
-		\OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
963
-
964
-		\OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
965
-			ManagerEvent::EVENT_APP_UPDATE, $appId
966
-		));
967
-
968
-		return true;
969
-	}
970
-
971
-	/**
972
-	 * @param string $appId
973
-	 * @param string[] $steps
974
-	 * @throws \OC\NeedsUpdateException
975
-	 */
976
-	public static function executeRepairSteps(string $appId, array $steps) {
977
-		if (empty($steps)) {
978
-			return;
979
-		}
980
-		// load the app
981
-		self::loadApp($appId);
982
-
983
-		$dispatcher = OC::$server->getEventDispatcher();
984
-
985
-		// load the steps
986
-		$r = new Repair([], $dispatcher);
987
-		foreach ($steps as $step) {
988
-			try {
989
-				$r->addStep($step);
990
-			} catch (Exception $ex) {
991
-				$r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
992
-				\OC::$server->getLogger()->logException($ex);
993
-			}
994
-		}
995
-		// run the steps
996
-		$r->run();
997
-	}
998
-
999
-	public static function setupBackgroundJobs(array $jobs) {
1000
-		$queue = \OC::$server->getJobList();
1001
-		foreach ($jobs as $job) {
1002
-			$queue->add($job);
1003
-		}
1004
-	}
1005
-
1006
-	/**
1007
-	 * @param string $appId
1008
-	 * @param string[] $steps
1009
-	 */
1010
-	private static function setupLiveMigrations(string $appId, array $steps) {
1011
-		$queue = \OC::$server->getJobList();
1012
-		foreach ($steps as $step) {
1013
-			$queue->add('OC\Migration\BackgroundRepair', [
1014
-				'app' => $appId,
1015
-				'step' => $step]);
1016
-		}
1017
-	}
1018
-
1019
-	/**
1020
-	 * @param string $appId
1021
-	 * @return \OC\Files\View|false
1022
-	 */
1023
-	public static function getStorage(string $appId) {
1024
-		if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
1025
-			if (\OC::$server->getUserSession()->isLoggedIn()) {
1026
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1027
-				if (!$view->file_exists($appId)) {
1028
-					$view->mkdir($appId);
1029
-				}
1030
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1031
-			} else {
1032
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', ILogger::ERROR);
1033
-				return false;
1034
-			}
1035
-		} else {
1036
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', ILogger::ERROR);
1037
-			return false;
1038
-		}
1039
-	}
1040
-
1041
-	protected static function findBestL10NOption(array $options, string $lang): string {
1042
-		// only a single option
1043
-		if (isset($options['@value'])) {
1044
-			return $options['@value'];
1045
-		}
1046
-
1047
-		$fallback = $similarLangFallback = $englishFallback = false;
1048
-
1049
-		$lang = strtolower($lang);
1050
-		$similarLang = $lang;
1051
-		if (strpos($similarLang, '_')) {
1052
-			// For "de_DE" we want to find "de" and the other way around
1053
-			$similarLang = substr($lang, 0, strpos($lang, '_'));
1054
-		}
1055
-
1056
-		foreach ($options as $option) {
1057
-			if (is_array($option)) {
1058
-				if ($fallback === false) {
1059
-					$fallback = $option['@value'];
1060
-				}
1061
-
1062
-				if (!isset($option['@attributes']['lang'])) {
1063
-					continue;
1064
-				}
1065
-
1066
-				$attributeLang = strtolower($option['@attributes']['lang']);
1067
-				if ($attributeLang === $lang) {
1068
-					return $option['@value'];
1069
-				}
1070
-
1071
-				if ($attributeLang === $similarLang) {
1072
-					$similarLangFallback = $option['@value'];
1073
-				} elseif (strpos($attributeLang, $similarLang . '_') === 0) {
1074
-					if ($similarLangFallback === false) {
1075
-						$similarLangFallback =  $option['@value'];
1076
-					}
1077
-				}
1078
-			} else {
1079
-				$englishFallback = $option;
1080
-			}
1081
-		}
1082
-
1083
-		if ($similarLangFallback !== false) {
1084
-			return $similarLangFallback;
1085
-		} elseif ($englishFallback !== false) {
1086
-			return $englishFallback;
1087
-		}
1088
-		return (string) $fallback;
1089
-	}
1090
-
1091
-	/**
1092
-	 * parses the app data array and enhanced the 'description' value
1093
-	 *
1094
-	 * @param array $data the app data
1095
-	 * @param string $lang
1096
-	 * @return array improved app data
1097
-	 */
1098
-	public static function parseAppInfo(array $data, $lang = null): array {
1099
-		if ($lang && isset($data['name']) && is_array($data['name'])) {
1100
-			$data['name'] = self::findBestL10NOption($data['name'], $lang);
1101
-		}
1102
-		if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1103
-			$data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1104
-		}
1105
-		if ($lang && isset($data['description']) && is_array($data['description'])) {
1106
-			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1107
-		} elseif (isset($data['description']) && is_string($data['description'])) {
1108
-			$data['description'] = trim($data['description']);
1109
-		} else {
1110
-			$data['description'] = '';
1111
-		}
1112
-
1113
-		return $data;
1114
-	}
1115
-
1116
-	/**
1117
-	 * @param \OCP\IConfig $config
1118
-	 * @param \OCP\IL10N $l
1119
-	 * @param array $info
1120
-	 * @throws \Exception
1121
-	 */
1122
-	public static function checkAppDependencies(\OCP\IConfig $config, \OCP\IL10N $l, array $info, bool $ignoreMax) {
1123
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1124
-		$missing = $dependencyAnalyzer->analyze($info, $ignoreMax);
1125
-		if (!empty($missing)) {
1126
-			$missingMsg = implode(PHP_EOL, $missing);
1127
-			throw new \Exception(
1128
-				$l->t('App "%1$s" cannot be installed because the following dependencies are not fulfilled: %2$s',
1129
-					[$info['name'], $missingMsg]
1130
-				)
1131
-			);
1132
-		}
1133
-	}
68
+    private static $adminForms = [];
69
+    private static $personalForms = [];
70
+    private static $appTypes = [];
71
+    private static $loadedApps = [];
72
+    private static $altLogin = [];
73
+    private static $alreadyRegistered = [];
74
+    public const supportedApp = 300;
75
+    public const officialApp = 200;
76
+
77
+    /**
78
+     * clean the appId
79
+     *
80
+     * @param string $app AppId that needs to be cleaned
81
+     * @return string
82
+     */
83
+    public static function cleanAppId(string $app): string {
84
+        return str_replace(['\0', '/', '\\', '..'], '', $app);
85
+    }
86
+
87
+    /**
88
+     * Check if an app is loaded
89
+     *
90
+     * @param string $app
91
+     * @return bool
92
+     */
93
+    public static function isAppLoaded(string $app): bool {
94
+        return in_array($app, self::$loadedApps, true);
95
+    }
96
+
97
+    /**
98
+     * loads all apps
99
+     *
100
+     * @param string[] $types
101
+     * @return bool
102
+     *
103
+     * This function walks through the ownCloud directory and loads all apps
104
+     * it can find. A directory contains an app if the file /appinfo/info.xml
105
+     * exists.
106
+     *
107
+     * if $types is set to non-empty array, only apps of those types will be loaded
108
+     */
109
+    public static function loadApps(array $types = []): bool {
110
+        if ((bool) \OC::$server->getSystemConfig()->getValue('maintenance', false)) {
111
+            return false;
112
+        }
113
+        // Load the enabled apps here
114
+        $apps = self::getEnabledApps();
115
+
116
+        // Add each apps' folder as allowed class path
117
+        foreach ($apps as $app) {
118
+            $path = self::getAppPath($app);
119
+            if ($path !== false) {
120
+                self::registerAutoloading($app, $path);
121
+            }
122
+        }
123
+
124
+        // prevent app.php from printing output
125
+        ob_start();
126
+        foreach ($apps as $app) {
127
+            if (($types === [] or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
128
+                self::loadApp($app);
129
+            }
130
+        }
131
+        ob_end_clean();
132
+
133
+        return true;
134
+    }
135
+
136
+    /**
137
+     * load a single app
138
+     *
139
+     * @param string $app
140
+     * @throws Exception
141
+     */
142
+    public static function loadApp(string $app) {
143
+        self::$loadedApps[] = $app;
144
+        $appPath = self::getAppPath($app);
145
+        if ($appPath === false) {
146
+            return;
147
+        }
148
+
149
+        // in case someone calls loadApp() directly
150
+        self::registerAutoloading($app, $appPath);
151
+
152
+        /** @var \OC\AppFramework\Bootstrap\Coordinator $coordinator */
153
+        $coordinator = \OC::$server->query(\OC\AppFramework\Bootstrap\Coordinator::class);
154
+        $isBootable = $coordinator->isBootable($app);
155
+
156
+        $hasAppPhpFile = is_file($appPath . '/appinfo/app.php');
157
+
158
+        if ($isBootable && $hasAppPhpFile) {
159
+            \OC::$server->getLogger()->error('/appinfo/app.php is not loaded when \OCP\AppFramework\Bootstrap\IBootstrap on the application class is used. Migrate everything from app.php to the Application class.', [
160
+                'app' => $app,
161
+            ]);
162
+        } elseif ($hasAppPhpFile) {
163
+            \OC::$server->getLogger()->debug('/appinfo/app.php is deprecated, use \OCP\AppFramework\Bootstrap\IBootstrap on the application class instead.', [
164
+                'app' => $app,
165
+            ]);
166
+            \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
167
+            try {
168
+                self::requireAppFile($app);
169
+            } catch (Throwable $ex) {
170
+                if ($ex instanceof ServerNotAvailableException) {
171
+                    throw $ex;
172
+                }
173
+                if (!\OC::$server->getAppManager()->isShipped($app) && !self::isType($app, ['authentication'])) {
174
+                    \OC::$server->getLogger()->logException($ex, [
175
+                        'message' => "App $app threw an error during app.php load and will be disabled: " . $ex->getMessage(),
176
+                    ]);
177
+
178
+                    // Only disable apps which are not shipped and that are not authentication apps
179
+                    \OC::$server->getAppManager()->disableApp($app, true);
180
+                } else {
181
+                    \OC::$server->getLogger()->logException($ex, [
182
+                        'message' => "App $app threw an error during app.php load: " . $ex->getMessage(),
183
+                    ]);
184
+                }
185
+            }
186
+            \OC::$server->getEventLogger()->end('load_app_' . $app);
187
+        }
188
+        $coordinator->bootApp($app);
189
+
190
+        $info = self::getAppInfo($app);
191
+        if (!empty($info['activity']['filters'])) {
192
+            foreach ($info['activity']['filters'] as $filter) {
193
+                \OC::$server->getActivityManager()->registerFilter($filter);
194
+            }
195
+        }
196
+        if (!empty($info['activity']['settings'])) {
197
+            foreach ($info['activity']['settings'] as $setting) {
198
+                \OC::$server->getActivityManager()->registerSetting($setting);
199
+            }
200
+        }
201
+        if (!empty($info['activity']['providers'])) {
202
+            foreach ($info['activity']['providers'] as $provider) {
203
+                \OC::$server->getActivityManager()->registerProvider($provider);
204
+            }
205
+        }
206
+
207
+        if (!empty($info['settings']['admin'])) {
208
+            foreach ($info['settings']['admin'] as $setting) {
209
+                \OC::$server->getSettingsManager()->registerSetting('admin', $setting);
210
+            }
211
+        }
212
+        if (!empty($info['settings']['admin-section'])) {
213
+            foreach ($info['settings']['admin-section'] as $section) {
214
+                \OC::$server->getSettingsManager()->registerSection('admin', $section);
215
+            }
216
+        }
217
+        if (!empty($info['settings']['personal'])) {
218
+            foreach ($info['settings']['personal'] as $setting) {
219
+                \OC::$server->getSettingsManager()->registerSetting('personal', $setting);
220
+            }
221
+        }
222
+        if (!empty($info['settings']['personal-section'])) {
223
+            foreach ($info['settings']['personal-section'] as $section) {
224
+                \OC::$server->getSettingsManager()->registerSection('personal', $section);
225
+            }
226
+        }
227
+
228
+        if (!empty($info['collaboration']['plugins'])) {
229
+            // deal with one or many plugin entries
230
+            $plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
231
+                [$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
232
+            foreach ($plugins as $plugin) {
233
+                if ($plugin['@attributes']['type'] === 'collaborator-search') {
234
+                    $pluginInfo = [
235
+                        'shareType' => $plugin['@attributes']['share-type'],
236
+                        'class' => $plugin['@value'],
237
+                    ];
238
+                    \OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo);
239
+                } elseif ($plugin['@attributes']['type'] === 'autocomplete-sort') {
240
+                    \OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']);
241
+                }
242
+            }
243
+        }
244
+    }
245
+
246
+    /**
247
+     * @internal
248
+     * @param string $app
249
+     * @param string $path
250
+     * @param bool $force
251
+     */
252
+    public static function registerAutoloading(string $app, string $path, bool $force = false) {
253
+        $key = $app . '-' . $path;
254
+        if (!$force && isset(self::$alreadyRegistered[$key])) {
255
+            return;
256
+        }
257
+
258
+        self::$alreadyRegistered[$key] = true;
259
+
260
+        // Register on PSR-4 composer autoloader
261
+        $appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
262
+        \OC::$server->registerNamespace($app, $appNamespace);
263
+
264
+        if (file_exists($path . '/composer/autoload.php')) {
265
+            require_once $path . '/composer/autoload.php';
266
+        } else {
267
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
268
+            // Register on legacy autoloader
269
+            \OC::$loader->addValidRoot($path);
270
+        }
271
+
272
+        // Register Test namespace only when testing
273
+        if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
274
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
275
+        }
276
+    }
277
+
278
+    /**
279
+     * Load app.php from the given app
280
+     *
281
+     * @param string $app app name
282
+     * @throws Error
283
+     */
284
+    private static function requireAppFile(string $app) {
285
+        // encapsulated here to avoid variable scope conflicts
286
+        require_once $app . '/appinfo/app.php';
287
+    }
288
+
289
+    /**
290
+     * check if an app is of a specific type
291
+     *
292
+     * @param string $app
293
+     * @param array $types
294
+     * @return bool
295
+     */
296
+    public static function isType(string $app, array $types): bool {
297
+        $appTypes = self::getAppTypes($app);
298
+        foreach ($types as $type) {
299
+            if (array_search($type, $appTypes) !== false) {
300
+                return true;
301
+            }
302
+        }
303
+        return false;
304
+    }
305
+
306
+    /**
307
+     * get the types of an app
308
+     *
309
+     * @param string $app
310
+     * @return array
311
+     */
312
+    private static function getAppTypes(string $app): array {
313
+        //load the cache
314
+        if (count(self::$appTypes) == 0) {
315
+            self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
316
+        }
317
+
318
+        if (isset(self::$appTypes[$app])) {
319
+            return explode(',', self::$appTypes[$app]);
320
+        }
321
+
322
+        return [];
323
+    }
324
+
325
+    /**
326
+     * read app types from info.xml and cache them in the database
327
+     */
328
+    public static function setAppTypes(string $app) {
329
+        $appManager = \OC::$server->getAppManager();
330
+        $appData = $appManager->getAppInfo($app);
331
+        if (!is_array($appData)) {
332
+            return;
333
+        }
334
+
335
+        if (isset($appData['types'])) {
336
+            $appTypes = implode(',', $appData['types']);
337
+        } else {
338
+            $appTypes = '';
339
+            $appData['types'] = [];
340
+        }
341
+
342
+        $config = \OC::$server->getConfig();
343
+        $config->setAppValue($app, 'types', $appTypes);
344
+
345
+        if ($appManager->hasProtectedAppType($appData['types'])) {
346
+            $enabled = $config->getAppValue($app, 'enabled', 'yes');
347
+            if ($enabled !== 'yes' && $enabled !== 'no') {
348
+                $config->setAppValue($app, 'enabled', 'yes');
349
+            }
350
+        }
351
+    }
352
+
353
+    /**
354
+     * Returns apps enabled for the current user.
355
+     *
356
+     * @param bool $forceRefresh whether to refresh the cache
357
+     * @param bool $all whether to return apps for all users, not only the
358
+     * currently logged in one
359
+     * @return string[]
360
+     */
361
+    public static function getEnabledApps(bool $forceRefresh = false, bool $all = false): array {
362
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
363
+            return [];
364
+        }
365
+        // in incognito mode or when logged out, $user will be false,
366
+        // which is also the case during an upgrade
367
+        $appManager = \OC::$server->getAppManager();
368
+        if ($all) {
369
+            $user = null;
370
+        } else {
371
+            $user = \OC::$server->getUserSession()->getUser();
372
+        }
373
+
374
+        if (is_null($user)) {
375
+            $apps = $appManager->getInstalledApps();
376
+        } else {
377
+            $apps = $appManager->getEnabledAppsForUser($user);
378
+        }
379
+        $apps = array_filter($apps, function ($app) {
380
+            return $app !== 'files';//we add this manually
381
+        });
382
+        sort($apps);
383
+        array_unshift($apps, 'files');
384
+        return $apps;
385
+    }
386
+
387
+    /**
388
+     * checks whether or not an app is enabled
389
+     *
390
+     * @param string $app app
391
+     * @return bool
392
+     * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
393
+     *
394
+     * This function checks whether or not an app is enabled.
395
+     */
396
+    public static function isEnabled(string $app): bool {
397
+        return \OC::$server->getAppManager()->isEnabledForUser($app);
398
+    }
399
+
400
+    /**
401
+     * enables an app
402
+     *
403
+     * @param string $appId
404
+     * @param array $groups (optional) when set, only these groups will have access to the app
405
+     * @throws \Exception
406
+     * @return void
407
+     *
408
+     * This function set an app as enabled in appconfig.
409
+     */
410
+    public function enable(string $appId,
411
+                            array $groups = []) {
412
+
413
+        // Check if app is already downloaded
414
+        /** @var Installer $installer */
415
+        $installer = \OC::$server->query(Installer::class);
416
+        $isDownloaded = $installer->isDownloaded($appId);
417
+
418
+        if (!$isDownloaded) {
419
+            $installer->downloadApp($appId);
420
+        }
421
+
422
+        $installer->installApp($appId);
423
+
424
+        $appManager = \OC::$server->getAppManager();
425
+        if ($groups !== []) {
426
+            $groupManager = \OC::$server->getGroupManager();
427
+            $groupsList = [];
428
+            foreach ($groups as $group) {
429
+                $groupItem = $groupManager->get($group);
430
+                if ($groupItem instanceof \OCP\IGroup) {
431
+                    $groupsList[] = $groupManager->get($group);
432
+                }
433
+            }
434
+            $appManager->enableAppForGroups($appId, $groupsList);
435
+        } else {
436
+            $appManager->enableApp($appId);
437
+        }
438
+    }
439
+
440
+    /**
441
+     * Get the path where to install apps
442
+     *
443
+     * @return string|false
444
+     */
445
+    public static function getInstallPath() {
446
+        if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
447
+            return false;
448
+        }
449
+
450
+        foreach (OC::$APPSROOTS as $dir) {
451
+            if (isset($dir['writable']) && $dir['writable'] === true) {
452
+                return $dir['path'];
453
+            }
454
+        }
455
+
456
+        \OCP\Util::writeLog('core', 'No application directories are marked as writable.', ILogger::ERROR);
457
+        return null;
458
+    }
459
+
460
+
461
+    /**
462
+     * search for an app in all app-directories
463
+     *
464
+     * @param string $appId
465
+     * @return false|string
466
+     */
467
+    public static function findAppInDirectories(string $appId) {
468
+        $sanitizedAppId = self::cleanAppId($appId);
469
+        if ($sanitizedAppId !== $appId) {
470
+            return false;
471
+        }
472
+        static $app_dir = [];
473
+
474
+        if (isset($app_dir[$appId])) {
475
+            return $app_dir[$appId];
476
+        }
477
+
478
+        $possibleApps = [];
479
+        foreach (OC::$APPSROOTS as $dir) {
480
+            if (file_exists($dir['path'] . '/' . $appId)) {
481
+                $possibleApps[] = $dir;
482
+            }
483
+        }
484
+
485
+        if (empty($possibleApps)) {
486
+            return false;
487
+        } elseif (count($possibleApps) === 1) {
488
+            $dir = array_shift($possibleApps);
489
+            $app_dir[$appId] = $dir;
490
+            return $dir;
491
+        } else {
492
+            $versionToLoad = [];
493
+            foreach ($possibleApps as $possibleApp) {
494
+                $version = self::getAppVersionByPath($possibleApp['path'] . '/' . $appId);
495
+                if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
496
+                    $versionToLoad = [
497
+                        'dir' => $possibleApp,
498
+                        'version' => $version,
499
+                    ];
500
+                }
501
+            }
502
+            $app_dir[$appId] = $versionToLoad['dir'];
503
+            return $versionToLoad['dir'];
504
+            //TODO - write test
505
+        }
506
+    }
507
+
508
+    /**
509
+     * Get the directory for the given app.
510
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
511
+     *
512
+     * @param string $appId
513
+     * @return string|false
514
+     * @deprecated 11.0.0 use \OC::$server->getAppManager()->getAppPath()
515
+     */
516
+    public static function getAppPath(string $appId) {
517
+        if ($appId === null || trim($appId) === '') {
518
+            return false;
519
+        }
520
+
521
+        if (($dir = self::findAppInDirectories($appId)) != false) {
522
+            return $dir['path'] . '/' . $appId;
523
+        }
524
+        return false;
525
+    }
526
+
527
+    /**
528
+     * Get the path for the given app on the access
529
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
530
+     *
531
+     * @param string $appId
532
+     * @return string|false
533
+     * @deprecated 18.0.0 use \OC::$server->getAppManager()->getAppWebPath()
534
+     */
535
+    public static function getAppWebPath(string $appId) {
536
+        if (($dir = self::findAppInDirectories($appId)) != false) {
537
+            return OC::$WEBROOT . $dir['url'] . '/' . $appId;
538
+        }
539
+        return false;
540
+    }
541
+
542
+    /**
543
+     * get the last version of the app from appinfo/info.xml
544
+     *
545
+     * @param string $appId
546
+     * @param bool $useCache
547
+     * @return string
548
+     * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion()
549
+     */
550
+    public static function getAppVersion(string $appId, bool $useCache = true): string {
551
+        return \OC::$server->getAppManager()->getAppVersion($appId, $useCache);
552
+    }
553
+
554
+    /**
555
+     * get app's version based on it's path
556
+     *
557
+     * @param string $path
558
+     * @return string
559
+     */
560
+    public static function getAppVersionByPath(string $path): string {
561
+        $infoFile = $path . '/appinfo/info.xml';
562
+        $appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
563
+        return isset($appData['version']) ? $appData['version'] : '';
564
+    }
565
+
566
+
567
+    /**
568
+     * Read all app metadata from the info.xml file
569
+     *
570
+     * @param string $appId id of the app or the path of the info.xml file
571
+     * @param bool $path
572
+     * @param string $lang
573
+     * @return array|null
574
+     * @note all data is read from info.xml, not just pre-defined fields
575
+     * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppInfo()
576
+     */
577
+    public static function getAppInfo(string $appId, bool $path = false, string $lang = null) {
578
+        return \OC::$server->getAppManager()->getAppInfo($appId, $path, $lang);
579
+    }
580
+
581
+    /**
582
+     * Returns the navigation
583
+     *
584
+     * @return array
585
+     * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll()
586
+     *
587
+     * This function returns an array containing all entries added. The
588
+     * entries are sorted by the key 'order' ascending. Additional to the keys
589
+     * given for each app the following keys exist:
590
+     *   - active: boolean, signals if the user is on this navigation entry
591
+     */
592
+    public static function getNavigation(): array {
593
+        return OC::$server->getNavigationManager()->getAll();
594
+    }
595
+
596
+    /**
597
+     * Returns the Settings Navigation
598
+     *
599
+     * @return string[]
600
+     * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll('settings')
601
+     *
602
+     * This function returns an array containing all settings pages added. The
603
+     * entries are sorted by the key 'order' ascending.
604
+     */
605
+    public static function getSettingsNavigation(): array {
606
+        return OC::$server->getNavigationManager()->getAll('settings');
607
+    }
608
+
609
+    /**
610
+     * get the id of loaded app
611
+     *
612
+     * @return string
613
+     */
614
+    public static function getCurrentApp(): string {
615
+        $request = \OC::$server->getRequest();
616
+        $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
617
+        $topFolder = substr($script, 0, strpos($script, '/') ?: 0);
618
+        if (empty($topFolder)) {
619
+            $path_info = $request->getPathInfo();
620
+            if ($path_info) {
621
+                $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
622
+            }
623
+        }
624
+        if ($topFolder == 'apps') {
625
+            $length = strlen($topFolder);
626
+            return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1) ?: '';
627
+        } else {
628
+            return $topFolder;
629
+        }
630
+    }
631
+
632
+    /**
633
+     * @param string $type
634
+     * @return array
635
+     */
636
+    public static function getForms(string $type): array {
637
+        $forms = [];
638
+        switch ($type) {
639
+            case 'admin':
640
+                $source = self::$adminForms;
641
+                break;
642
+            case 'personal':
643
+                $source = self::$personalForms;
644
+                break;
645
+            default:
646
+                return [];
647
+        }
648
+        foreach ($source as $form) {
649
+            $forms[] = include $form;
650
+        }
651
+        return $forms;
652
+    }
653
+
654
+    /**
655
+     * register an admin form to be shown
656
+     *
657
+     * @param string $app
658
+     * @param string $page
659
+     */
660
+    public static function registerAdmin(string $app, string $page) {
661
+        self::$adminForms[] = $app . '/' . $page . '.php';
662
+    }
663
+
664
+    /**
665
+     * register a personal form to be shown
666
+     * @param string $app
667
+     * @param string $page
668
+     */
669
+    public static function registerPersonal(string $app, string $page) {
670
+        self::$personalForms[] = $app . '/' . $page . '.php';
671
+    }
672
+
673
+    /**
674
+     * @param array $entry
675
+     */
676
+    public static function registerLogIn(array $entry) {
677
+        self::$altLogin[] = $entry;
678
+    }
679
+
680
+    /**
681
+     * @return array
682
+     */
683
+    public static function getAlternativeLogIns(): array {
684
+        return self::$altLogin;
685
+    }
686
+
687
+    /**
688
+     * get a list of all apps in the apps folder
689
+     *
690
+     * @return string[] an array of app names (string IDs)
691
+     * @todo: change the name of this method to getInstalledApps, which is more accurate
692
+     */
693
+    public static function getAllApps(): array {
694
+        $apps = [];
695
+
696
+        foreach (OC::$APPSROOTS as $apps_dir) {
697
+            if (!is_readable($apps_dir['path'])) {
698
+                \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], ILogger::WARN);
699
+                continue;
700
+            }
701
+            $dh = opendir($apps_dir['path']);
702
+
703
+            if (is_resource($dh)) {
704
+                while (($file = readdir($dh)) !== false) {
705
+                    if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
706
+                        $apps[] = $file;
707
+                    }
708
+                }
709
+            }
710
+        }
711
+
712
+        $apps = array_unique($apps);
713
+
714
+        return $apps;
715
+    }
716
+
717
+    /**
718
+     * List all apps, this is used in apps.php
719
+     *
720
+     * @return array
721
+     */
722
+    public function listAllApps(): array {
723
+        $installedApps = OC_App::getAllApps();
724
+
725
+        $appManager = \OC::$server->getAppManager();
726
+        //we don't want to show configuration for these
727
+        $blacklist = $appManager->getAlwaysEnabledApps();
728
+        $appList = [];
729
+        $langCode = \OC::$server->getL10N('core')->getLanguageCode();
730
+        $urlGenerator = \OC::$server->getURLGenerator();
731
+        /** @var \OCP\Support\Subscription\IRegistry $subscriptionRegistry */
732
+        $subscriptionRegistry = \OC::$server->query(\OCP\Support\Subscription\IRegistry::class);
733
+        $supportedApps = $subscriptionRegistry->delegateGetSupportedApps();
734
+
735
+        foreach ($installedApps as $app) {
736
+            if (array_search($app, $blacklist) === false) {
737
+                $info = OC_App::getAppInfo($app, false, $langCode);
738
+                if (!is_array($info)) {
739
+                    \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', ILogger::ERROR);
740
+                    continue;
741
+                }
742
+
743
+                if (!isset($info['name'])) {
744
+                    \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', ILogger::ERROR);
745
+                    continue;
746
+                }
747
+
748
+                $enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'no');
749
+                $info['groups'] = null;
750
+                if ($enabled === 'yes') {
751
+                    $active = true;
752
+                } elseif ($enabled === 'no') {
753
+                    $active = false;
754
+                } else {
755
+                    $active = true;
756
+                    $info['groups'] = $enabled;
757
+                }
758
+
759
+                $info['active'] = $active;
760
+
761
+                if ($appManager->isShipped($app)) {
762
+                    $info['internal'] = true;
763
+                    $info['level'] = self::officialApp;
764
+                    $info['removable'] = false;
765
+                } else {
766
+                    $info['internal'] = false;
767
+                    $info['removable'] = true;
768
+                }
769
+
770
+                if (in_array($app, $supportedApps)) {
771
+                    $info['level'] = self::supportedApp;
772
+                }
773
+
774
+                $appPath = self::getAppPath($app);
775
+                if ($appPath !== false) {
776
+                    $appIcon = $appPath . '/img/' . $app . '.svg';
777
+                    if (file_exists($appIcon)) {
778
+                        $info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
779
+                        $info['previewAsIcon'] = true;
780
+                    } else {
781
+                        $appIcon = $appPath . '/img/app.svg';
782
+                        if (file_exists($appIcon)) {
783
+                            $info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
784
+                            $info['previewAsIcon'] = true;
785
+                        }
786
+                    }
787
+                }
788
+                // fix documentation
789
+                if (isset($info['documentation']) && is_array($info['documentation'])) {
790
+                    foreach ($info['documentation'] as $key => $url) {
791
+                        // If it is not an absolute URL we assume it is a key
792
+                        // i.e. admin-ldap will get converted to go.php?to=admin-ldap
793
+                        if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
794
+                            $url = $urlGenerator->linkToDocs($url);
795
+                        }
796
+
797
+                        $info['documentation'][$key] = $url;
798
+                    }
799
+                }
800
+
801
+                $info['version'] = OC_App::getAppVersion($app);
802
+                $appList[] = $info;
803
+            }
804
+        }
805
+
806
+        return $appList;
807
+    }
808
+
809
+    public static function shouldUpgrade(string $app): bool {
810
+        $versions = self::getAppVersions();
811
+        $currentVersion = OC_App::getAppVersion($app);
812
+        if ($currentVersion && isset($versions[$app])) {
813
+            $installedVersion = $versions[$app];
814
+            if (!version_compare($currentVersion, $installedVersion, '=')) {
815
+                return true;
816
+            }
817
+        }
818
+        return false;
819
+    }
820
+
821
+    /**
822
+     * Adjust the number of version parts of $version1 to match
823
+     * the number of version parts of $version2.
824
+     *
825
+     * @param string $version1 version to adjust
826
+     * @param string $version2 version to take the number of parts from
827
+     * @return string shortened $version1
828
+     */
829
+    private static function adjustVersionParts(string $version1, string $version2): string {
830
+        $version1 = explode('.', $version1);
831
+        $version2 = explode('.', $version2);
832
+        // reduce $version1 to match the number of parts in $version2
833
+        while (count($version1) > count($version2)) {
834
+            array_pop($version1);
835
+        }
836
+        // if $version1 does not have enough parts, add some
837
+        while (count($version1) < count($version2)) {
838
+            $version1[] = '0';
839
+        }
840
+        return implode('.', $version1);
841
+    }
842
+
843
+    /**
844
+     * Check whether the current ownCloud version matches the given
845
+     * application's version requirements.
846
+     *
847
+     * The comparison is made based on the number of parts that the
848
+     * app info version has. For example for ownCloud 6.0.3 if the
849
+     * app info version is expecting version 6.0, the comparison is
850
+     * made on the first two parts of the ownCloud version.
851
+     * This means that it's possible to specify "requiremin" => 6
852
+     * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
853
+     *
854
+     * @param string $ocVersion ownCloud version to check against
855
+     * @param array $appInfo app info (from xml)
856
+     *
857
+     * @return boolean true if compatible, otherwise false
858
+     */
859
+    public static function isAppCompatible(string $ocVersion, array $appInfo, bool $ignoreMax = false): bool {
860
+        $requireMin = '';
861
+        $requireMax = '';
862
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
863
+            $requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
864
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
865
+            $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
866
+        } elseif (isset($appInfo['requiremin'])) {
867
+            $requireMin = $appInfo['requiremin'];
868
+        } elseif (isset($appInfo['require'])) {
869
+            $requireMin = $appInfo['require'];
870
+        }
871
+
872
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
873
+            $requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
874
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
875
+            $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
876
+        } elseif (isset($appInfo['requiremax'])) {
877
+            $requireMax = $appInfo['requiremax'];
878
+        }
879
+
880
+        if (!empty($requireMin)
881
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
882
+        ) {
883
+            return false;
884
+        }
885
+
886
+        if (!$ignoreMax && !empty($requireMax)
887
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
888
+        ) {
889
+            return false;
890
+        }
891
+
892
+        return true;
893
+    }
894
+
895
+    /**
896
+     * get the installed version of all apps
897
+     */
898
+    public static function getAppVersions() {
899
+        static $versions;
900
+
901
+        if (!$versions) {
902
+            $appConfig = \OC::$server->getAppConfig();
903
+            $versions = $appConfig->getValues(false, 'installed_version');
904
+        }
905
+        return $versions;
906
+    }
907
+
908
+    /**
909
+     * update the database for the app and call the update script
910
+     *
911
+     * @param string $appId
912
+     * @return bool
913
+     */
914
+    public static function updateApp(string $appId): bool {
915
+        $appPath = self::getAppPath($appId);
916
+        if ($appPath === false) {
917
+            return false;
918
+        }
919
+
920
+        \OC::$server->getAppManager()->clearAppsCache();
921
+        $appData = self::getAppInfo($appId);
922
+
923
+        self::registerAutoloading($appId, $appPath, true);
924
+        self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
925
+
926
+        if (file_exists($appPath . '/appinfo/database.xml')) {
927
+            OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
928
+        } else {
929
+            $ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
930
+            $ms->migrate();
931
+        }
932
+
933
+        self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
934
+        self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
935
+        // update appversion in app manager
936
+        \OC::$server->getAppManager()->clearAppsCache();
937
+        \OC::$server->getAppManager()->getAppVersion($appId, false);
938
+
939
+        // run upgrade code
940
+        if (file_exists($appPath . '/appinfo/update.php')) {
941
+            self::loadApp($appId);
942
+            include $appPath . '/appinfo/update.php';
943
+        }
944
+        self::setupBackgroundJobs($appData['background-jobs']);
945
+
946
+        //set remote/public handlers
947
+        if (array_key_exists('ocsid', $appData)) {
948
+            \OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
949
+        } elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
950
+            \OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
951
+        }
952
+        foreach ($appData['remote'] as $name => $path) {
953
+            \OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
954
+        }
955
+        foreach ($appData['public'] as $name => $path) {
956
+            \OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
957
+        }
958
+
959
+        self::setAppTypes($appId);
960
+
961
+        $version = \OC_App::getAppVersion($appId);
962
+        \OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
963
+
964
+        \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
965
+            ManagerEvent::EVENT_APP_UPDATE, $appId
966
+        ));
967
+
968
+        return true;
969
+    }
970
+
971
+    /**
972
+     * @param string $appId
973
+     * @param string[] $steps
974
+     * @throws \OC\NeedsUpdateException
975
+     */
976
+    public static function executeRepairSteps(string $appId, array $steps) {
977
+        if (empty($steps)) {
978
+            return;
979
+        }
980
+        // load the app
981
+        self::loadApp($appId);
982
+
983
+        $dispatcher = OC::$server->getEventDispatcher();
984
+
985
+        // load the steps
986
+        $r = new Repair([], $dispatcher);
987
+        foreach ($steps as $step) {
988
+            try {
989
+                $r->addStep($step);
990
+            } catch (Exception $ex) {
991
+                $r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
992
+                \OC::$server->getLogger()->logException($ex);
993
+            }
994
+        }
995
+        // run the steps
996
+        $r->run();
997
+    }
998
+
999
+    public static function setupBackgroundJobs(array $jobs) {
1000
+        $queue = \OC::$server->getJobList();
1001
+        foreach ($jobs as $job) {
1002
+            $queue->add($job);
1003
+        }
1004
+    }
1005
+
1006
+    /**
1007
+     * @param string $appId
1008
+     * @param string[] $steps
1009
+     */
1010
+    private static function setupLiveMigrations(string $appId, array $steps) {
1011
+        $queue = \OC::$server->getJobList();
1012
+        foreach ($steps as $step) {
1013
+            $queue->add('OC\Migration\BackgroundRepair', [
1014
+                'app' => $appId,
1015
+                'step' => $step]);
1016
+        }
1017
+    }
1018
+
1019
+    /**
1020
+     * @param string $appId
1021
+     * @return \OC\Files\View|false
1022
+     */
1023
+    public static function getStorage(string $appId) {
1024
+        if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
1025
+            if (\OC::$server->getUserSession()->isLoggedIn()) {
1026
+                $view = new \OC\Files\View('/' . OC_User::getUser());
1027
+                if (!$view->file_exists($appId)) {
1028
+                    $view->mkdir($appId);
1029
+                }
1030
+                return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1031
+            } else {
1032
+                \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', ILogger::ERROR);
1033
+                return false;
1034
+            }
1035
+        } else {
1036
+            \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', ILogger::ERROR);
1037
+            return false;
1038
+        }
1039
+    }
1040
+
1041
+    protected static function findBestL10NOption(array $options, string $lang): string {
1042
+        // only a single option
1043
+        if (isset($options['@value'])) {
1044
+            return $options['@value'];
1045
+        }
1046
+
1047
+        $fallback = $similarLangFallback = $englishFallback = false;
1048
+
1049
+        $lang = strtolower($lang);
1050
+        $similarLang = $lang;
1051
+        if (strpos($similarLang, '_')) {
1052
+            // For "de_DE" we want to find "de" and the other way around
1053
+            $similarLang = substr($lang, 0, strpos($lang, '_'));
1054
+        }
1055
+
1056
+        foreach ($options as $option) {
1057
+            if (is_array($option)) {
1058
+                if ($fallback === false) {
1059
+                    $fallback = $option['@value'];
1060
+                }
1061
+
1062
+                if (!isset($option['@attributes']['lang'])) {
1063
+                    continue;
1064
+                }
1065
+
1066
+                $attributeLang = strtolower($option['@attributes']['lang']);
1067
+                if ($attributeLang === $lang) {
1068
+                    return $option['@value'];
1069
+                }
1070
+
1071
+                if ($attributeLang === $similarLang) {
1072
+                    $similarLangFallback = $option['@value'];
1073
+                } elseif (strpos($attributeLang, $similarLang . '_') === 0) {
1074
+                    if ($similarLangFallback === false) {
1075
+                        $similarLangFallback =  $option['@value'];
1076
+                    }
1077
+                }
1078
+            } else {
1079
+                $englishFallback = $option;
1080
+            }
1081
+        }
1082
+
1083
+        if ($similarLangFallback !== false) {
1084
+            return $similarLangFallback;
1085
+        } elseif ($englishFallback !== false) {
1086
+            return $englishFallback;
1087
+        }
1088
+        return (string) $fallback;
1089
+    }
1090
+
1091
+    /**
1092
+     * parses the app data array and enhanced the 'description' value
1093
+     *
1094
+     * @param array $data the app data
1095
+     * @param string $lang
1096
+     * @return array improved app data
1097
+     */
1098
+    public static function parseAppInfo(array $data, $lang = null): array {
1099
+        if ($lang && isset($data['name']) && is_array($data['name'])) {
1100
+            $data['name'] = self::findBestL10NOption($data['name'], $lang);
1101
+        }
1102
+        if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1103
+            $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1104
+        }
1105
+        if ($lang && isset($data['description']) && is_array($data['description'])) {
1106
+            $data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1107
+        } elseif (isset($data['description']) && is_string($data['description'])) {
1108
+            $data['description'] = trim($data['description']);
1109
+        } else {
1110
+            $data['description'] = '';
1111
+        }
1112
+
1113
+        return $data;
1114
+    }
1115
+
1116
+    /**
1117
+     * @param \OCP\IConfig $config
1118
+     * @param \OCP\IL10N $l
1119
+     * @param array $info
1120
+     * @throws \Exception
1121
+     */
1122
+    public static function checkAppDependencies(\OCP\IConfig $config, \OCP\IL10N $l, array $info, bool $ignoreMax) {
1123
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1124
+        $missing = $dependencyAnalyzer->analyze($info, $ignoreMax);
1125
+        if (!empty($missing)) {
1126
+            $missingMsg = implode(PHP_EOL, $missing);
1127
+            throw new \Exception(
1128
+                $l->t('App "%1$s" cannot be installed because the following dependencies are not fulfilled: %2$s',
1129
+                    [$info['name'], $missingMsg]
1130
+                )
1131
+            );
1132
+        }
1133
+    }
1134 1134
 }
Please login to merge, or discard this patch.
Spacing   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -153,7 +153,7 @@  discard block
 block discarded – undo
153 153
 		$coordinator = \OC::$server->query(\OC\AppFramework\Bootstrap\Coordinator::class);
154 154
 		$isBootable = $coordinator->isBootable($app);
155 155
 
156
-		$hasAppPhpFile = is_file($appPath . '/appinfo/app.php');
156
+		$hasAppPhpFile = is_file($appPath.'/appinfo/app.php');
157 157
 
158 158
 		if ($isBootable && $hasAppPhpFile) {
159 159
 			\OC::$server->getLogger()->error('/appinfo/app.php is not loaded when \OCP\AppFramework\Bootstrap\IBootstrap on the application class is used. Migrate everything from app.php to the Application class.', [
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
 			\OC::$server->getLogger()->debug('/appinfo/app.php is deprecated, use \OCP\AppFramework\Bootstrap\IBootstrap on the application class instead.', [
164 164
 				'app' => $app,
165 165
 			]);
166
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
166
+			\OC::$server->getEventLogger()->start('load_app_'.$app, 'Load app: '.$app);
167 167
 			try {
168 168
 				self::requireAppFile($app);
169 169
 			} catch (Throwable $ex) {
@@ -172,18 +172,18 @@  discard block
 block discarded – undo
172 172
 				}
173 173
 				if (!\OC::$server->getAppManager()->isShipped($app) && !self::isType($app, ['authentication'])) {
174 174
 					\OC::$server->getLogger()->logException($ex, [
175
-						'message' => "App $app threw an error during app.php load and will be disabled: " . $ex->getMessage(),
175
+						'message' => "App $app threw an error during app.php load and will be disabled: ".$ex->getMessage(),
176 176
 					]);
177 177
 
178 178
 					// Only disable apps which are not shipped and that are not authentication apps
179 179
 					\OC::$server->getAppManager()->disableApp($app, true);
180 180
 				} else {
181 181
 					\OC::$server->getLogger()->logException($ex, [
182
-						'message' => "App $app threw an error during app.php load: " . $ex->getMessage(),
182
+						'message' => "App $app threw an error during app.php load: ".$ex->getMessage(),
183 183
 					]);
184 184
 				}
185 185
 			}
186
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
186
+			\OC::$server->getEventLogger()->end('load_app_'.$app);
187 187
 		}
188 188
 		$coordinator->bootApp($app);
189 189
 
@@ -250,7 +250,7 @@  discard block
 block discarded – undo
250 250
 	 * @param bool $force
251 251
 	 */
252 252
 	public static function registerAutoloading(string $app, string $path, bool $force = false) {
253
-		$key = $app . '-' . $path;
253
+		$key = $app.'-'.$path;
254 254
 		if (!$force && isset(self::$alreadyRegistered[$key])) {
255 255
 			return;
256 256
 		}
@@ -261,17 +261,17 @@  discard block
 block discarded – undo
261 261
 		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
262 262
 		\OC::$server->registerNamespace($app, $appNamespace);
263 263
 
264
-		if (file_exists($path . '/composer/autoload.php')) {
265
-			require_once $path . '/composer/autoload.php';
264
+		if (file_exists($path.'/composer/autoload.php')) {
265
+			require_once $path.'/composer/autoload.php';
266 266
 		} else {
267
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
267
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\', $path.'/lib/', true);
268 268
 			// Register on legacy autoloader
269 269
 			\OC::$loader->addValidRoot($path);
270 270
 		}
271 271
 
272 272
 		// Register Test namespace only when testing
273 273
 		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
274
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
274
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\Tests\\', $path.'/tests/', true);
275 275
 		}
276 276
 	}
277 277
 
@@ -283,7 +283,7 @@  discard block
 block discarded – undo
283 283
 	 */
284 284
 	private static function requireAppFile(string $app) {
285 285
 		// encapsulated here to avoid variable scope conflicts
286
-		require_once $app . '/appinfo/app.php';
286
+		require_once $app.'/appinfo/app.php';
287 287
 	}
288 288
 
289 289
 	/**
@@ -376,8 +376,8 @@  discard block
 block discarded – undo
376 376
 		} else {
377 377
 			$apps = $appManager->getEnabledAppsForUser($user);
378 378
 		}
379
-		$apps = array_filter($apps, function ($app) {
380
-			return $app !== 'files';//we add this manually
379
+		$apps = array_filter($apps, function($app) {
380
+			return $app !== 'files'; //we add this manually
381 381
 		});
382 382
 		sort($apps);
383 383
 		array_unshift($apps, 'files');
@@ -477,7 +477,7 @@  discard block
 block discarded – undo
477 477
 
478 478
 		$possibleApps = [];
479 479
 		foreach (OC::$APPSROOTS as $dir) {
480
-			if (file_exists($dir['path'] . '/' . $appId)) {
480
+			if (file_exists($dir['path'].'/'.$appId)) {
481 481
 				$possibleApps[] = $dir;
482 482
 			}
483 483
 		}
@@ -491,7 +491,7 @@  discard block
 block discarded – undo
491 491
 		} else {
492 492
 			$versionToLoad = [];
493 493
 			foreach ($possibleApps as $possibleApp) {
494
-				$version = self::getAppVersionByPath($possibleApp['path'] . '/' . $appId);
494
+				$version = self::getAppVersionByPath($possibleApp['path'].'/'.$appId);
495 495
 				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
496 496
 					$versionToLoad = [
497 497
 						'dir' => $possibleApp,
@@ -519,7 +519,7 @@  discard block
 block discarded – undo
519 519
 		}
520 520
 
521 521
 		if (($dir = self::findAppInDirectories($appId)) != false) {
522
-			return $dir['path'] . '/' . $appId;
522
+			return $dir['path'].'/'.$appId;
523 523
 		}
524 524
 		return false;
525 525
 	}
@@ -534,7 +534,7 @@  discard block
 block discarded – undo
534 534
 	 */
535 535
 	public static function getAppWebPath(string $appId) {
536 536
 		if (($dir = self::findAppInDirectories($appId)) != false) {
537
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
537
+			return OC::$WEBROOT.$dir['url'].'/'.$appId;
538 538
 		}
539 539
 		return false;
540 540
 	}
@@ -558,7 +558,7 @@  discard block
 block discarded – undo
558 558
 	 * @return string
559 559
 	 */
560 560
 	public static function getAppVersionByPath(string $path): string {
561
-		$infoFile = $path . '/appinfo/info.xml';
561
+		$infoFile = $path.'/appinfo/info.xml';
562 562
 		$appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
563 563
 		return isset($appData['version']) ? $appData['version'] : '';
564 564
 	}
@@ -658,7 +658,7 @@  discard block
 block discarded – undo
658 658
 	 * @param string $page
659 659
 	 */
660 660
 	public static function registerAdmin(string $app, string $page) {
661
-		self::$adminForms[] = $app . '/' . $page . '.php';
661
+		self::$adminForms[] = $app.'/'.$page.'.php';
662 662
 	}
663 663
 
664 664
 	/**
@@ -667,7 +667,7 @@  discard block
 block discarded – undo
667 667
 	 * @param string $page
668 668
 	 */
669 669
 	public static function registerPersonal(string $app, string $page) {
670
-		self::$personalForms[] = $app . '/' . $page . '.php';
670
+		self::$personalForms[] = $app.'/'.$page.'.php';
671 671
 	}
672 672
 
673 673
 	/**
@@ -695,14 +695,14 @@  discard block
 block discarded – undo
695 695
 
696 696
 		foreach (OC::$APPSROOTS as $apps_dir) {
697 697
 			if (!is_readable($apps_dir['path'])) {
698
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], ILogger::WARN);
698
+				\OCP\Util::writeLog('core', 'unable to read app folder : '.$apps_dir['path'], ILogger::WARN);
699 699
 				continue;
700 700
 			}
701 701
 			$dh = opendir($apps_dir['path']);
702 702
 
703 703
 			if (is_resource($dh)) {
704 704
 				while (($file = readdir($dh)) !== false) {
705
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
705
+					if ($file[0] != '.' and is_dir($apps_dir['path'].'/'.$file) and is_file($apps_dir['path'].'/'.$file.'/appinfo/info.xml')) {
706 706
 						$apps[] = $file;
707 707
 					}
708 708
 				}
@@ -736,12 +736,12 @@  discard block
 block discarded – undo
736 736
 			if (array_search($app, $blacklist) === false) {
737 737
 				$info = OC_App::getAppInfo($app, false, $langCode);
738 738
 				if (!is_array($info)) {
739
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', ILogger::ERROR);
739
+					\OCP\Util::writeLog('core', 'Could not read app info file for app "'.$app.'"', ILogger::ERROR);
740 740
 					continue;
741 741
 				}
742 742
 
743 743
 				if (!isset($info['name'])) {
744
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', ILogger::ERROR);
744
+					\OCP\Util::writeLog('core', 'App id "'.$app.'" has no name in appinfo', ILogger::ERROR);
745 745
 					continue;
746 746
 				}
747 747
 
@@ -773,12 +773,12 @@  discard block
 block discarded – undo
773 773
 
774 774
 				$appPath = self::getAppPath($app);
775 775
 				if ($appPath !== false) {
776
-					$appIcon = $appPath . '/img/' . $app . '.svg';
776
+					$appIcon = $appPath.'/img/'.$app.'.svg';
777 777
 					if (file_exists($appIcon)) {
778
-						$info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
778
+						$info['preview'] = $urlGenerator->imagePath($app, $app.'.svg');
779 779
 						$info['previewAsIcon'] = true;
780 780
 					} else {
781
-						$appIcon = $appPath . '/img/app.svg';
781
+						$appIcon = $appPath.'/img/app.svg';
782 782
 						if (file_exists($appIcon)) {
783 783
 							$info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
784 784
 							$info['previewAsIcon'] = true;
@@ -923,8 +923,8 @@  discard block
 block discarded – undo
923 923
 		self::registerAutoloading($appId, $appPath, true);
924 924
 		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
925 925
 
926
-		if (file_exists($appPath . '/appinfo/database.xml')) {
927
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
926
+		if (file_exists($appPath.'/appinfo/database.xml')) {
927
+			OC_DB::updateDbFromStructure($appPath.'/appinfo/database.xml');
928 928
 		} else {
929 929
 			$ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
930 930
 			$ms->migrate();
@@ -937,9 +937,9 @@  discard block
 block discarded – undo
937 937
 		\OC::$server->getAppManager()->getAppVersion($appId, false);
938 938
 
939 939
 		// run upgrade code
940
-		if (file_exists($appPath . '/appinfo/update.php')) {
940
+		if (file_exists($appPath.'/appinfo/update.php')) {
941 941
 			self::loadApp($appId);
942
-			include $appPath . '/appinfo/update.php';
942
+			include $appPath.'/appinfo/update.php';
943 943
 		}
944 944
 		self::setupBackgroundJobs($appData['background-jobs']);
945 945
 
@@ -950,10 +950,10 @@  discard block
 block discarded – undo
950 950
 			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
951 951
 		}
952 952
 		foreach ($appData['remote'] as $name => $path) {
953
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
953
+			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $appId.'/'.$path);
954 954
 		}
955 955
 		foreach ($appData['public'] as $name => $path) {
956
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
956
+			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $appId.'/'.$path);
957 957
 		}
958 958
 
959 959
 		self::setAppTypes($appId);
@@ -1023,17 +1023,17 @@  discard block
 block discarded – undo
1023 1023
 	public static function getStorage(string $appId) {
1024 1024
 		if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
1025 1025
 			if (\OC::$server->getUserSession()->isLoggedIn()) {
1026
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1026
+				$view = new \OC\Files\View('/'.OC_User::getUser());
1027 1027
 				if (!$view->file_exists($appId)) {
1028 1028
 					$view->mkdir($appId);
1029 1029
 				}
1030
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1030
+				return new \OC\Files\View('/'.OC_User::getUser().'/'.$appId);
1031 1031
 			} else {
1032
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', ILogger::ERROR);
1032
+				\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.', user not logged in', ILogger::ERROR);
1033 1033
 				return false;
1034 1034
 			}
1035 1035
 		} else {
1036
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', ILogger::ERROR);
1036
+			\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.' not enabled', ILogger::ERROR);
1037 1037
 			return false;
1038 1038
 		}
1039 1039
 	}
@@ -1070,9 +1070,9 @@  discard block
 block discarded – undo
1070 1070
 
1071 1071
 				if ($attributeLang === $similarLang) {
1072 1072
 					$similarLangFallback = $option['@value'];
1073
-				} elseif (strpos($attributeLang, $similarLang . '_') === 0) {
1073
+				} elseif (strpos($attributeLang, $similarLang.'_') === 0) {
1074 1074
 					if ($similarLangFallback === false) {
1075
-						$similarLangFallback =  $option['@value'];
1075
+						$similarLangFallback = $option['@value'];
1076 1076
 					}
1077 1077
 				}
1078 1078
 			} else {
Please login to merge, or discard this patch.
lib/private/AppFramework/Bootstrap/Coordinator.php 2 patches
Indentation   +113 added lines, -113 removed lines patch added patch discarded remove patch
@@ -41,129 +41,129 @@
 block discarded – undo
41 41
 
42 42
 class Coordinator {
43 43
 
44
-	/** @var IServerContainer */
45
-	private $serverContainer;
46
-
47
-	/** @var Registry */
48
-	private $registry;
49
-
50
-	/** @var IEventDispatcher */
51
-	private $eventDispatcher;
52
-
53
-	/** @var ILogger */
54
-	private $logger;
55
-
56
-	/** @var RegistrationContext|null */
57
-	private $registrationContext;
58
-
59
-	public function __construct(IServerContainer $container,
60
-								Registry $registry,
61
-								IEventDispatcher $eventListener,
62
-								ILogger $logger) {
63
-		$this->serverContainer = $container;
64
-		$this->registry = $registry;
65
-		$this->eventDispatcher = $eventListener;
66
-		$this->logger = $logger;
67
-	}
68
-
69
-	public function runRegistration(): void {
70
-		if ($this->registrationContext !== null) {
71
-			throw new RuntimeException('Registration has already been run');
72
-		}
73
-
74
-		$this->registrationContext = new RegistrationContext($this->logger);
75
-		$apps = [];
76
-		foreach (OC_App::getEnabledApps() as $appId) {
77
-			/*
44
+    /** @var IServerContainer */
45
+    private $serverContainer;
46
+
47
+    /** @var Registry */
48
+    private $registry;
49
+
50
+    /** @var IEventDispatcher */
51
+    private $eventDispatcher;
52
+
53
+    /** @var ILogger */
54
+    private $logger;
55
+
56
+    /** @var RegistrationContext|null */
57
+    private $registrationContext;
58
+
59
+    public function __construct(IServerContainer $container,
60
+                                Registry $registry,
61
+                                IEventDispatcher $eventListener,
62
+                                ILogger $logger) {
63
+        $this->serverContainer = $container;
64
+        $this->registry = $registry;
65
+        $this->eventDispatcher = $eventListener;
66
+        $this->logger = $logger;
67
+    }
68
+
69
+    public function runRegistration(): void {
70
+        if ($this->registrationContext !== null) {
71
+            throw new RuntimeException('Registration has already been run');
72
+        }
73
+
74
+        $this->registrationContext = new RegistrationContext($this->logger);
75
+        $apps = [];
76
+        foreach (OC_App::getEnabledApps() as $appId) {
77
+            /*
78 78
 			 * First, we have to enable the app's autoloader
79 79
 			 *
80 80
 			 * @todo use $this->appManager->getAppPath($appId) here
81 81
 			 */
82
-			$path = OC_App::getAppPath($appId);
83
-			if ($path === false) {
84
-				// Ignore
85
-				continue;
86
-			}
87
-			OC_App::registerAutoloading($appId, $path);
88
-
89
-			/*
82
+            $path = OC_App::getAppPath($appId);
83
+            if ($path === false) {
84
+                // Ignore
85
+                continue;
86
+            }
87
+            OC_App::registerAutoloading($appId, $path);
88
+
89
+            /*
90 90
 			 * Next we check if there is an application class and it implements
91 91
 			 * the \OCP\AppFramework\Bootstrap\IBootstrap interface
92 92
 			 */
93
-			$appNameSpace = App::buildAppNamespace($appId);
94
-			$applicationClassName = $appNameSpace . '\\AppInfo\\Application';
95
-			if (class_exists($applicationClassName) && in_array(IBootstrap::class, class_implements($applicationClassName), true)) {
96
-				try {
97
-					/** @var IBootstrap|App $application */
98
-					$apps[$appId] = $application = $this->serverContainer->query($applicationClassName);
99
-				} catch (QueryException $e) {
100
-					// Weird, but ok
101
-					continue;
102
-				}
103
-				try {
104
-					$application->register($this->registrationContext->for($appId));
105
-				} catch (Throwable $e) {
106
-					$this->logger->logException($e, [
107
-						'message' => 'Error during app service registration: ' . $e->getMessage(),
108
-						'level' => ILogger::FATAL,
109
-					]);
110
-				}
111
-			}
112
-		}
113
-
114
-		/**
115
-		 * Now that all register methods have been called, we can delegate the registrations
116
-		 * to the actual services
117
-		 */
118
-		$this->registrationContext->delegateCapabilityRegistrations($apps);
119
-		$this->registrationContext->delegateCrashReporterRegistrations($apps, $this->registry);
120
-		$this->registrationContext->delegateEventListenerRegistrations($this->eventDispatcher);
121
-		$this->registrationContext->delegateContainerRegistrations($apps);
122
-		$this->registrationContext->delegateMiddlewareRegistrations($apps);
123
-	}
124
-
125
-	public function getRegistrationContext(): ?RegistrationContext {
126
-		return $this->registrationContext;
127
-	}
128
-
129
-	public function bootApp(string $appId): void {
130
-		$appNameSpace = App::buildAppNamespace($appId);
131
-		$applicationClassName = $appNameSpace . '\\AppInfo\\Application';
132
-		if (!class_exists($applicationClassName)) {
133
-			// Nothing to boot
134
-			return;
135
-		}
136
-
137
-		/*
93
+            $appNameSpace = App::buildAppNamespace($appId);
94
+            $applicationClassName = $appNameSpace . '\\AppInfo\\Application';
95
+            if (class_exists($applicationClassName) && in_array(IBootstrap::class, class_implements($applicationClassName), true)) {
96
+                try {
97
+                    /** @var IBootstrap|App $application */
98
+                    $apps[$appId] = $application = $this->serverContainer->query($applicationClassName);
99
+                } catch (QueryException $e) {
100
+                    // Weird, but ok
101
+                    continue;
102
+                }
103
+                try {
104
+                    $application->register($this->registrationContext->for($appId));
105
+                } catch (Throwable $e) {
106
+                    $this->logger->logException($e, [
107
+                        'message' => 'Error during app service registration: ' . $e->getMessage(),
108
+                        'level' => ILogger::FATAL,
109
+                    ]);
110
+                }
111
+            }
112
+        }
113
+
114
+        /**
115
+         * Now that all register methods have been called, we can delegate the registrations
116
+         * to the actual services
117
+         */
118
+        $this->registrationContext->delegateCapabilityRegistrations($apps);
119
+        $this->registrationContext->delegateCrashReporterRegistrations($apps, $this->registry);
120
+        $this->registrationContext->delegateEventListenerRegistrations($this->eventDispatcher);
121
+        $this->registrationContext->delegateContainerRegistrations($apps);
122
+        $this->registrationContext->delegateMiddlewareRegistrations($apps);
123
+    }
124
+
125
+    public function getRegistrationContext(): ?RegistrationContext {
126
+        return $this->registrationContext;
127
+    }
128
+
129
+    public function bootApp(string $appId): void {
130
+        $appNameSpace = App::buildAppNamespace($appId);
131
+        $applicationClassName = $appNameSpace . '\\AppInfo\\Application';
132
+        if (!class_exists($applicationClassName)) {
133
+            // Nothing to boot
134
+            return;
135
+        }
136
+
137
+        /*
138 138
 		 * Now it is time to fetch an instance of the App class. For classes
139 139
 		 * that implement \OCP\AppFramework\Bootstrap\IBootstrap this means
140 140
 		 * the instance was already created for register, but any other
141 141
 		 * (legacy) code will now do their magic via the constructor.
142 142
 		 */
143
-		try {
144
-			/** @var App $application */
145
-			$application = $this->serverContainer->query($applicationClassName);
146
-			if ($application instanceof IBootstrap) {
147
-				/** @var BootContext $context */
148
-				$context = new BootContext($application->getContainer());
149
-				$application->boot($context);
150
-			}
151
-		} catch (QueryException $e) {
152
-			$this->logger->logException($e, [
153
-				'message' => "Could not boot $appId" . $e->getMessage(),
154
-			]);
155
-		} catch (Throwable $e) {
156
-			$this->logger->logException($e, [
157
-				'message' => "Could not boot $appId" . $e->getMessage(),
158
-				'level' => ILogger::FATAL,
159
-			]);
160
-		}
161
-	}
162
-
163
-	public function isBootable(string $appId) {
164
-		$appNameSpace = App::buildAppNamespace($appId);
165
-		$applicationClassName = $appNameSpace . '\\AppInfo\\Application';
166
-		return class_exists($applicationClassName) &&
167
-			in_array(IBootstrap::class, class_implements($applicationClassName), true);
168
-	}
143
+        try {
144
+            /** @var App $application */
145
+            $application = $this->serverContainer->query($applicationClassName);
146
+            if ($application instanceof IBootstrap) {
147
+                /** @var BootContext $context */
148
+                $context = new BootContext($application->getContainer());
149
+                $application->boot($context);
150
+            }
151
+        } catch (QueryException $e) {
152
+            $this->logger->logException($e, [
153
+                'message' => "Could not boot $appId" . $e->getMessage(),
154
+            ]);
155
+        } catch (Throwable $e) {
156
+            $this->logger->logException($e, [
157
+                'message' => "Could not boot $appId" . $e->getMessage(),
158
+                'level' => ILogger::FATAL,
159
+            ]);
160
+        }
161
+    }
162
+
163
+    public function isBootable(string $appId) {
164
+        $appNameSpace = App::buildAppNamespace($appId);
165
+        $applicationClassName = $appNameSpace . '\\AppInfo\\Application';
166
+        return class_exists($applicationClassName) &&
167
+            in_array(IBootstrap::class, class_implements($applicationClassName), true);
168
+    }
169 169
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -91,7 +91,7 @@  discard block
 block discarded – undo
91 91
 			 * the \OCP\AppFramework\Bootstrap\IBootstrap interface
92 92
 			 */
93 93
 			$appNameSpace = App::buildAppNamespace($appId);
94
-			$applicationClassName = $appNameSpace . '\\AppInfo\\Application';
94
+			$applicationClassName = $appNameSpace.'\\AppInfo\\Application';
95 95
 			if (class_exists($applicationClassName) && in_array(IBootstrap::class, class_implements($applicationClassName), true)) {
96 96
 				try {
97 97
 					/** @var IBootstrap|App $application */
@@ -104,7 +104,7 @@  discard block
 block discarded – undo
104 104
 					$application->register($this->registrationContext->for($appId));
105 105
 				} catch (Throwable $e) {
106 106
 					$this->logger->logException($e, [
107
-						'message' => 'Error during app service registration: ' . $e->getMessage(),
107
+						'message' => 'Error during app service registration: '.$e->getMessage(),
108 108
 						'level' => ILogger::FATAL,
109 109
 					]);
110 110
 				}
@@ -128,7 +128,7 @@  discard block
 block discarded – undo
128 128
 
129 129
 	public function bootApp(string $appId): void {
130 130
 		$appNameSpace = App::buildAppNamespace($appId);
131
-		$applicationClassName = $appNameSpace . '\\AppInfo\\Application';
131
+		$applicationClassName = $appNameSpace.'\\AppInfo\\Application';
132 132
 		if (!class_exists($applicationClassName)) {
133 133
 			// Nothing to boot
134 134
 			return;
@@ -150,11 +150,11 @@  discard block
 block discarded – undo
150 150
 			}
151 151
 		} catch (QueryException $e) {
152 152
 			$this->logger->logException($e, [
153
-				'message' => "Could not boot $appId" . $e->getMessage(),
153
+				'message' => "Could not boot $appId".$e->getMessage(),
154 154
 			]);
155 155
 		} catch (Throwable $e) {
156 156
 			$this->logger->logException($e, [
157
-				'message' => "Could not boot $appId" . $e->getMessage(),
157
+				'message' => "Could not boot $appId".$e->getMessage(),
158 158
 				'level' => ILogger::FATAL,
159 159
 			]);
160 160
 		}
@@ -162,7 +162,7 @@  discard block
 block discarded – undo
162 162
 
163 163
 	public function isBootable(string $appId) {
164 164
 		$appNameSpace = App::buildAppNamespace($appId);
165
-		$applicationClassName = $appNameSpace . '\\AppInfo\\Application';
165
+		$applicationClassName = $appNameSpace.'\\AppInfo\\Application';
166 166
 		return class_exists($applicationClassName) &&
167 167
 			in_array(IBootstrap::class, class_implements($applicationClassName), true);
168 168
 	}
Please login to merge, or discard this patch.