Passed
Push — master ( 5a8c78...5b0dfd )
by Christoph
12:14 queued 11s
created

PluginManager::createPluginInstance()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 10
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @copyright Copyright (c) 2016, ownCloud GmbH.
7
 *
8
 * @author Julius Härtl <[email protected]>
9
 * @author Roeland Jago Douma <[email protected]>
10
 * @author Vincent Petry <[email protected]>
11
 *
12
 * @license AGPL-3.0
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program. If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
28
namespace OCA\DAV\AppInfo;
29
30
use OC\ServerContainer;
31
use OCA\DAV\CalDAV\Integration\ICalendarProvider;
32
use OCA\DAV\CardDAV\Integration\IAddressBookProvider;
33
use OCP\App\IAppManager;
34
use OCP\AppFramework\QueryException;
35
use function array_map;
36
use function class_exists;
37
use function is_array;
38
39
/**
40
 * Manager for DAV plugins from apps, used to register them
41
 * to the Sabre server.
42
 */
43
class PluginManager {
44
45
	/**
46
	 * @var ServerContainer
47
	 */
48
	private $container;
49
50
	/**
51
	 * @var IAppManager
52
	 */
53
	private $appManager;
54
55
	/**
56
	 * App plugins
57
	 *
58
	 * @var array
59
	 */
60
	private $plugins = null;
61
62
	/**
63
	 * App collections
64
	 *
65
	 * @var array
66
	 */
67
	private $collections = null;
68
69
	/**
70
	 * Address book plugins
71
	 *
72
	 * @var IAddressBookProvider[]|null
73
	 */
74
	private $addressBookPlugins = null;
75
76
	/**
77
	 * Calendar plugins
78
	 *
79
	 * @var array
80
	 */
81
	private $calendarPlugins = null;
82
83
	/**
84
	 * Contstruct a PluginManager
85
	 *
86
	 * @param ServerContainer $container server container for resolving plugin classes
87
	 * @param IAppManager $appManager app manager to loading apps and their info
88
	 */
89
	public function __construct(ServerContainer $container, IAppManager $appManager) {
90
		$this->container = $container;
91
		$this->appManager = $appManager;
92
	}
93
94
	/**
95
	 * Returns an array of app-registered plugins
96
	 *
97
	 * @return array
98
	 */
99
	public function getAppPlugins() {
100
		if (null === $this->plugins) {
101
			$this->populate();
102
		}
103
		return $this->plugins;
104
	}
105
106
	/**
107
	 * Returns an array of app-registered collections
108
	 *
109
	 * @return array
110
	 */
111
	public function getAppCollections() {
112
		if (null === $this->collections) {
113
			$this->populate();
114
		}
115
		return $this->collections;
116
	}
117
118
	/**
119
	 * @return IAddressBookProvider[]
120
	 */
121
	public function getAddressBookPlugins(): array {
122
		if ($this->addressBookPlugins === null) {
123
			$this->populate();
124
		}
125
		return $this->addressBookPlugins;
126
	}
127
128
	/**
129
	 * Returns an array of app-registered calendar plugins
130
	 *
131
	 * @return array
132
	 */
133
	public function getCalendarPlugins():array {
134
		if (null === $this->calendarPlugins) {
135
			$this->populate();
136
		}
137
		return $this->calendarPlugins;
138
	}
139
140
	/**
141
	 * Retrieve plugin and collection list and populate attributes
142
	 */
143
	private function populate() {
144
		$this->plugins = [];
145
		$this->addressBookPlugins = [];
146
		$this->calendarPlugins = [];
147
		$this->collections = [];
148
		foreach ($this->appManager->getInstalledApps() as $app) {
149
			// load plugins and collections from info.xml
150
			$info = $this->appManager->getAppInfo($app);
151
			if (!isset($info['types']) || !in_array('dav', $info['types'], true)) {
152
				continue;
153
			}
154
			$this->loadSabrePluginsFromInfoXml($this->extractPluginList($info));
155
			$this->loadSabreCollectionsFromInfoXml($this->extractCollectionList($info));
156
			$this->loadSabreAddressBookPluginsFromInfoXml($this->extractAddressBookPluginList($info));
157
			$this->loadSabreCalendarPluginsFromInfoXml($this->extractCalendarPluginList($info));
158
		}
159
	}
160
161
	private function extractPluginList(array $array) {
162
		if (isset($array['sabre']) && is_array($array['sabre'])) {
163
			if (isset($array['sabre']['plugins']) && is_array($array['sabre']['plugins'])) {
164
				if (isset($array['sabre']['plugins']['plugin'])) {
165
					$items = $array['sabre']['plugins']['plugin'];
166
					if (!is_array($items)) {
167
						$items = [$items];
168
					}
169
					return $items;
170
				}
171
			}
172
		}
173
		return [];
174
	}
175
176
	private function extractCollectionList(array $array) {
177
		if (isset($array['sabre']) && is_array($array['sabre'])) {
178
			if (isset($array['sabre']['collections']) && is_array($array['sabre']['collections'])) {
179
				if (isset($array['sabre']['collections']['collection'])) {
180
					$items = $array['sabre']['collections']['collection'];
181
					if (!is_array($items)) {
182
						$items = [$items];
183
					}
184
					return $items;
185
				}
186
			}
187
		}
188
		return [];
189
	}
190
191
	/**
192
	 * @param array $array
193
	 *
194
	 * @return string[]
195
	 */
196
	private function extractAddressBookPluginList(array $array): array {
197
		if (!isset($array['sabre']) || !is_array($array['sabre'])) {
198
			return [];
199
		}
200
		if (!isset($array['sabre']['address-book-plugins']) || !is_array($array['sabre']['address-book-plugins'])) {
201
			return [];
202
		}
203
		if (!isset($array['sabre']['address-book-plugins']['plugin'])) {
204
			return [];
205
		}
206
207
		$items = $array['sabre']['address-book-plugins']['plugin'];
208
		if (!is_array($items)) {
209
			$items = [$items];
210
		}
211
		return $items;
212
	}
213
214
	private function extractCalendarPluginList(array $array):array {
215
		if (isset($array['sabre']) && is_array($array['sabre'])) {
216
			if (isset($array['sabre']['calendar-plugins']) && is_array($array['sabre']['calendar-plugins'])) {
217
				if (isset($array['sabre']['calendar-plugins']['plugin'])) {
218
					$items = $array['sabre']['calendar-plugins']['plugin'];
219
					if (!is_array($items)) {
220
						$items = [$items];
221
					}
222
					return $items;
223
				}
224
			}
225
		}
226
		return [];
227
	}
228
229
	private function loadSabrePluginsFromInfoXml(array $plugins) {
230
		foreach ($plugins as $plugin) {
231
			try {
232
				$this->plugins[] = $this->container->query($plugin);
233
			} catch (QueryException $e) {
234
				if (class_exists($plugin)) {
235
					$this->plugins[] = new $plugin();
236
				} else {
237
					throw new \Exception("Sabre plugin class '$plugin' is unknown and could not be loaded");
238
				}
239
			}
240
		}
241
	}
242
243
	private function loadSabreCollectionsFromInfoXml(array $collections) {
244
		foreach ($collections as $collection) {
245
			try {
246
				$this->collections[] = $this->container->query($collection);
247
			} catch (QueryException $e) {
248
				if (class_exists($collection)) {
249
					$this->collections[] = new $collection();
250
				} else {
251
					throw new \Exception("Sabre collection class '$collection' is unknown and could not be loaded");
252
				}
253
			}
254
		}
255
	}
256
257
	private function createPluginInstance(string $className) {
258
		try {
259
			return $this->container->query($className);
260
		} catch (QueryException $e) {
261
			if (class_exists($className)) {
262
				return new $className();
263
			}
264
		}
265
266
		throw new \Exception("Sabre plugin class '$className' is unknown and could not be loaded");
267
	}
268
269
	/**
270
	 * @param string[] $plugin
271
	 */
272
	private function loadSabreAddressBookPluginsFromInfoXml(array $plugins): void {
273
		$providers = array_map(function(string $className): IAddressBookProvider {
274
			$instance = $this->createPluginInstance($className);
275
			if (!($instance instanceof IAddressBookProvider)) {
276
				throw new \Exception("Sabre address book plugin class '$className' does not implement the \OCA\DAV\CardDAV\Integration\IAddressBookProvider interface");
277
			}
278
			return $instance;
279
		}, $plugins);
280
		foreach ($providers as $provider) {
281
			$this->addressBookPlugins[] = $provider;
282
		}
283
	}
284
285
	private function loadSabreCalendarPluginsFromInfoXml(array $calendarPlugins):void {
286
		foreach ($calendarPlugins as $calendarPlugin) {
287
			try {
288
				$instantiatedCalendarPlugin = $this->container->query($calendarPlugin);
289
			} catch (QueryException $e) {
290
				if (class_exists($calendarPlugin)) {
291
					$instantiatedCalendarPlugin = new $calendarPlugin();
292
				} else {
293
					throw new \Exception("Sabre calendar-plugin class '$calendarPlugin' is unknown and could not be loaded");
294
				}
295
			}
296
297
			if (!($instantiatedCalendarPlugin instanceof ICalendarProvider)) {
298
				throw new \Exception("Sabre calendar-plugin class '$calendarPlugin' does not implement ICalendarProvider interface");
299
			}
300
301
			$this->calendarPlugins[] = $instantiatedCalendarPlugin;
302
		}
303
	}
304
305
}
306