Passed
Push — master ( bf2355...650ffc )
by Morris
21:54 queued 10:47
created

Coordinator::runRegistration()   B

Complexity

Conditions 8
Paths 7

Size

Total Lines 55
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 28
nc 7
nop 0
dl 0
loc 55
rs 8.4444
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A Coordinator::runLazyRegistration() 0 2 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @copyright 2020 Christoph Wurst <[email protected]>
7
 *
8
 * @author Christoph Wurst <[email protected]>
9
 * @author Julius Härtl <[email protected]>
10
 * @author Morris Jobke <[email protected]>
11
 * @author Robin Appelman <[email protected]>
12
 *
13
 * @license GNU AGPL version 3 or any later version
14
 *
15
 * This program is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License as
17
 * published by the Free Software Foundation, either version 3 of the
18
 * License, or (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License
26
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27
 *
28
 */
29
30
namespace OC\AppFramework\Bootstrap;
31
32
use OC\Support\CrashReport\Registry;
33
use OC_App;
34
use OCP\AppFramework\App;
35
use OCP\AppFramework\Bootstrap\IBootstrap;
36
use OCP\AppFramework\QueryException;
37
use OCP\Dashboard\IManager;
38
use OCP\EventDispatcher\IEventDispatcher;
39
use OCP\ILogger;
40
use OCP\IServerContainer;
41
use Throwable;
42
use function class_exists;
43
use function class_implements;
44
use function in_array;
45
46
class Coordinator {
47
48
	/** @var IServerContainer */
49
	private $serverContainer;
50
51
	/** @var Registry */
52
	private $registry;
53
54
	/** @var IManager */
55
	private $dashboardManager;
56
57
	/** @var IEventDispatcher */
58
	private $eventDispatcher;
59
60
	/** @var ILogger */
61
	private $logger;
62
63
	/** @var RegistrationContext|null */
64
	private $registrationContext;
65
66
	/** @var string[] */
67
	private $bootedApps = [];
68
69
	public function __construct(IServerContainer $container,
70
								Registry $registry,
71
								IManager $dashboardManager,
72
								IEventDispatcher $eventListener,
73
								ILogger $logger) {
74
		$this->serverContainer = $container;
75
		$this->registry = $registry;
76
		$this->dashboardManager = $dashboardManager;
77
		$this->eventDispatcher = $eventListener;
78
		$this->logger = $logger;
79
	}
80
81
	public function runInitialRegistration(): void {
82
		$this->registerApps(OC_App::getEnabledApps());
83
	}
84
85
	public function runLazyRegistration(string $appId): void {
86
		$this->registerApps([$appId]);
87
	}
88
89
	/**
90
	 * @param string[] $appIds
91
	 */
92
	private function registerApps(array $appIds): void {
93
		if ($this->registrationContext === null) {
94
			$this->registrationContext = new RegistrationContext($this->logger);
95
		}
96
		$apps = [];
97
		foreach ($appIds as $appId) {
98
			/*
99
			 * First, we have to enable the app's autoloader
100
			 *
101
			 * @todo use $this->appManager->getAppPath($appId) here
102
			 */
103
			$path = OC_App::getAppPath($appId);
104
			if ($path === false) {
105
				// Ignore
106
				continue;
107
			}
108
			OC_App::registerAutoloading($appId, $path);
109
110
			/*
111
			 * Next we check if there is an application class and it implements
112
			 * the \OCP\AppFramework\Bootstrap\IBootstrap interface
113
			 */
114
			$appNameSpace = App::buildAppNamespace($appId);
115
			$applicationClassName = $appNameSpace . '\\AppInfo\\Application';
116
			if (class_exists($applicationClassName) && in_array(IBootstrap::class, class_implements($applicationClassName), true)) {
117
				try {
118
					/** @var IBootstrap|App $application */
119
					$apps[$appId] = $application = $this->serverContainer->query($applicationClassName);
120
				} catch (QueryException $e) {
121
					// Weird, but ok
122
					continue;
123
				}
124
				try {
125
					$application->register($this->registrationContext->for($appId));
0 ignored issues
show
Bug introduced by
The method register() does not exist on OCP\AppFramework\App. Did you maybe mean registerRoutes()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

125
					$application->/** @scrutinizer ignore-call */ 
126
                   register($this->registrationContext->for($appId));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
126
				} catch (Throwable $e) {
127
					$this->logger->logException($e, [
128
						'message' => 'Error during app service registration: ' . $e->getMessage(),
129
						'level' => ILogger::FATAL,
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::FATAL has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

129
						'level' => /** @scrutinizer ignore-deprecated */ ILogger::FATAL,

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
130
					]);
131
				}
132
			}
133
		}
134
135
		/**
136
		 * Now that all register methods have been called, we can delegate the registrations
137
		 * to the actual services
138
		 */
139
		$this->registrationContext->delegateCapabilityRegistrations($apps);
140
		$this->registrationContext->delegateCrashReporterRegistrations($apps, $this->registry);
141
		$this->registrationContext->delegateDashboardPanelRegistrations($apps, $this->dashboardManager);
142
		$this->registrationContext->delegateEventListenerRegistrations($this->eventDispatcher);
143
		$this->registrationContext->delegateContainerRegistrations($apps);
144
		$this->registrationContext->delegateMiddlewareRegistrations($apps);
145
	}
146
147
	public function getRegistrationContext(): ?RegistrationContext {
148
		return $this->registrationContext;
149
	}
150
151
	public function bootApp(string $appId): void {
152
		if (isset($this->bootedApps[$appId])) {
153
			return;
154
		}
155
		$this->bootedApps[$appId] = true;
156
157
		$appNameSpace = App::buildAppNamespace($appId);
158
		$applicationClassName = $appNameSpace . '\\AppInfo\\Application';
159
		if (!class_exists($applicationClassName)) {
160
			// Nothing to boot
161
			return;
162
		}
163
164
		/*
165
		 * Now it is time to fetch an instance of the App class. For classes
166
		 * that implement \OCP\AppFramework\Bootstrap\IBootstrap this means
167
		 * the instance was already created for register, but any other
168
		 * (legacy) code will now do their magic via the constructor.
169
		 */
170
		try {
171
			/** @var App $application */
172
			$application = $this->serverContainer->query($applicationClassName);
173
			if ($application instanceof IBootstrap) {
174
				/** @var BootContext $context */
175
				$context = new BootContext($application->getContainer());
176
				$application->boot($context);
177
			}
178
		} catch (QueryException $e) {
179
			$this->logger->logException($e, [
180
				'message' => "Could not boot $appId" . $e->getMessage(),
181
			]);
182
		} catch (Throwable $e) {
183
			$this->logger->logException($e, [
184
				'message' => "Could not boot $appId" . $e->getMessage(),
185
				'level' => ILogger::FATAL,
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::FATAL has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

185
				'level' => /** @scrutinizer ignore-deprecated */ ILogger::FATAL,

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
186
			]);
187
		}
188
	}
189
190
	public function isBootable(string $appId) {
191
		$appNameSpace = App::buildAppNamespace($appId);
192
		$applicationClassName = $appNameSpace . '\\AppInfo\\Application';
193
		return class_exists($applicationClassName) &&
194
			in_array(IBootstrap::class, class_implements($applicationClassName), true);
195
	}
196
}
197