Passed
Push — master ( b9de13...5fab33 )
by Morris
52:15 queued 40:14
created

Manager::getAdminSettings()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 20
rs 9.8333
c 0
b 0
f 0
cc 4
nc 6
nop 2
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016 Arthur Schiwon <[email protected]>
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Christoph Wurst <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Julius Härtl <[email protected]>
9
 * @author Lukas Reschke <[email protected]>
10
 * @author Morris Jobke <[email protected]>
11
 * @author Robin Appelman <[email protected]>
12
 * @author Roeland Jago Douma <[email protected]>
13
 * @author sualko <[email protected]>
14
 *
15
 * @license GNU AGPL version 3 or any later version
16
 *
17
 * This program is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Affero General Public License as
19
 * published by the Free Software Foundation, either version 3 of the
20
 * License, or (at your option) any later version.
21
 *
22
 * This program is distributed in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25
 * GNU Affero General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU Affero General Public License
28
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29
 *
30
 */
31
32
namespace OC\Settings;
33
34
use Closure;
35
use OCP\AppFramework\QueryException;
36
use OCP\IL10N;
37
use OCP\ILogger;
38
use OCP\IServerContainer;
39
use OCP\IURLGenerator;
40
use OCP\L10N\IFactory;
41
use OCP\Settings\IIconSection;
42
use OCP\Settings\IManager;
43
use OCP\Settings\ISettings;
44
use OCP\Settings\ISubAdminSettings;
45
46
class Manager implements IManager {
47
48
	/** @var ILogger */
49
	private $log;
50
51
	/** @var IL10N */
52
	private $l;
53
54
	/** @var IFactory */
55
	private $l10nFactory;
56
57
	/** @var IURLGenerator */
58
	private $url;
59
60
	/** @var IServerContainer */
61
	private $container;
62
63
	public function __construct(
64
		ILogger $log,
65
		IFactory $l10nFactory,
66
		IURLGenerator $url,
67
		IServerContainer $container
68
	) {
69
		$this->log = $log;
70
		$this->l10nFactory = $l10nFactory;
71
		$this->url = $url;
72
		$this->container = $container;
73
	}
74
75
	/** @var array */
76
	protected $sectionClasses = [];
77
78
	/** @var array */
79
	protected $sections = [];
80
81
	/**
82
	 * @param string $type 'admin' or 'personal'
83
	 * @param string $section Class must implement OCP\Settings\IIconSection
84
	 *
85
	 * @return void
86
	 */
87
	public function registerSection(string $type, string $section) {
88
		if (!isset($this->sectionClasses[$type])) {
89
			$this->sectionClasses[$type] = [];
90
		}
91
92
		$this->sectionClasses[$type][] = $section;
93
	}
94
95
	/**
96
	 * @param string $type 'admin' or 'personal'
97
	 *
98
	 * @return IIconSection[]
99
	 */
100
	protected function getSections(string $type): array {
101
		if (!isset($this->sections[$type])) {
102
			$this->sections[$type] = [];
103
		}
104
105
		if (!isset($this->sectionClasses[$type])) {
106
			return $this->sections[$type];
107
		}
108
109
		foreach (array_unique($this->sectionClasses[$type]) as $index => $class) {
110
			try {
111
				/** @var IIconSection $section */
112
				$section = \OC::$server->query($class);
113
			} catch (QueryException $e) {
114
				$this->log->logException($e, ['level' => ILogger::INFO]);
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::INFO 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

114
				$this->log->logException($e, ['level' => /** @scrutinizer ignore-deprecated */ ILogger::INFO]);

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...
115
				continue;
116
			}
117
118
			$sectionID = $section->getID();
119
120
			if ($sectionID !== 'connected-accounts' && isset($this->sections[$type][$sectionID])) {
121
				$this->log->logException(new \InvalidArgumentException('Section with the same ID already registered: ' . $sectionID . ', class: ' . $class), ['level' => ILogger::INFO]);
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::INFO 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

121
				$this->log->logException(new \InvalidArgumentException('Section with the same ID already registered: ' . $sectionID . ', class: ' . $class), ['level' => /** @scrutinizer ignore-deprecated */ ILogger::INFO]);

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...
122
				continue;
123
			}
124
125
			$this->sections[$type][$sectionID] = $section;
126
127
			unset($this->sectionClasses[$type][$index]);
128
		}
129
130
		return $this->sections[$type];
131
	}
132
133
	/** @var array */
134
	protected $settingClasses = [];
135
136
	/** @var array */
137
	protected $settings = [];
138
139
	/**
140
	 * @param string $type 'admin' or 'personal'
141
	 * @param string $setting Class must implement OCP\Settings\ISetting
142
	 *
143
	 * @return void
144
	 */
145
	public function registerSetting(string $type, string $setting) {
146
		$this->settingClasses[$setting] = $type;
147
	}
148
149
	/**
150
	 * @param string $type 'admin' or 'personal'
151
	 * @param string $section
152
	 * @param Closure $filter optional filter to apply on all loaded ISettings
153
	 *
154
	 * @return ISettings[]
155
	 */
156
	protected function getSettings(string $type, string $section, Closure $filter = null): array {
157
		if (!isset($this->settings[$type])) {
158
			$this->settings[$type] = [];
159
		}
160
		if (!isset($this->settings[$type][$section])) {
161
			$this->settings[$type][$section] = [];
162
		}
163
164
		foreach ($this->settingClasses as $class => $settingsType) {
165
			if ($type !== $settingsType) {
166
				continue;
167
			}
168
169
			try {
170
				/** @var ISettings $setting */
171
				$setting = $this->container->query($class);
172
			} catch (QueryException $e) {
173
				$this->log->logException($e, ['level' => ILogger::INFO]);
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::INFO 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

173
				$this->log->logException($e, ['level' => /** @scrutinizer ignore-deprecated */ ILogger::INFO]);

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...
174
				continue;
175
			}
176
177
			if (!$setting instanceof ISettings) {
178
				$this->log->logException(new \InvalidArgumentException('Invalid settings setting registered (' . $class . ')'), ['level' => ILogger::INFO]);
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::INFO 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

178
				$this->log->logException(new \InvalidArgumentException('Invalid settings setting registered (' . $class . ')'), ['level' => /** @scrutinizer ignore-deprecated */ ILogger::INFO]);

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...
179
				continue;
180
			}
181
182
			if ($filter !== null && !$filter($setting)) {
183
				continue;
184
			}
185
			if ($setting->getSection() === null) {
186
				continue;
187
			}
188
189
			if (!isset($this->settings[$settingsType][$setting->getSection()])) {
190
				$this->settings[$settingsType][$setting->getSection()] = [];
191
			}
192
			$this->settings[$settingsType][$setting->getSection()][] = $setting;
193
194
			unset($this->settingClasses[$class]);
195
		}
196
197
		return $this->settings[$type][$section];
198
	}
199
200
	/**
201
	 * @inheritdoc
202
	 */
203
	public function getAdminSections(): array {
204
		// built-in sections
205
		$sections = [];
206
207
		$appSections = $this->getSections('admin');
208
209
		foreach ($appSections as $section) {
210
			/** @var IIconSection $section */
211
			if (!isset($sections[$section->getPriority()])) {
212
				$sections[$section->getPriority()] = [];
213
			}
214
215
			$sections[$section->getPriority()][] = $section;
216
		}
217
218
		ksort($sections);
219
220
		return $sections;
221
	}
222
223
	/**
224
	 * @inheritdoc
225
	 */
226
	public function getAdminSettings($section, bool $subAdminOnly = false): array {
227
		if ($subAdminOnly) {
228
			$subAdminSettingsFilter = function (ISettings $settings) {
229
				return $settings instanceof ISubAdminSettings;
230
			};
231
			$appSettings = $this->getSettings('admin', $section, $subAdminSettingsFilter);
232
		} else {
233
			$appSettings = $this->getSettings('admin', $section);
234
		}
235
236
		$settings = [];
237
		foreach ($appSettings as $setting) {
238
			if (!isset($settings[$setting->getPriority()])) {
239
				$settings[$setting->getPriority()] = [];
240
			}
241
			$settings[$setting->getPriority()][] = $setting;
242
		}
243
244
		ksort($settings);
245
		return $settings;
246
	}
247
248
	/**
249
	 * @inheritdoc
250
	 */
251
	public function getPersonalSections(): array {
252
		if ($this->l === null) {
253
			$this->l = $this->l10nFactory->get('lib');
254
		}
255
256
		$sections = [];
257
258
		$legacyForms = \OC_App::getForms('personal');
259
		if ((!empty($legacyForms) && $this->hasLegacyPersonalSettingsToRender($legacyForms))
260
			|| count($this->getPersonalSettings('additional')) > 1) {
261
			$sections[98] = [new Section('additional', $this->l->t('Additional settings'), 0, $this->url->imagePath('core', 'actions/settings-dark.svg'))];
262
		}
263
264
		$appSections = $this->getSections('personal');
265
266
		foreach ($appSections as $section) {
267
			/** @var IIconSection $section */
268
			if (!isset($sections[$section->getPriority()])) {
269
				$sections[$section->getPriority()] = [];
270
			}
271
272
			$sections[$section->getPriority()][] = $section;
273
		}
274
275
		ksort($sections);
276
277
		return $sections;
278
	}
279
280
	/**
281
	 * @param string[] $forms
282
	 *
283
	 * @return bool
284
	 */
285
	private function hasLegacyPersonalSettingsToRender(array $forms): bool {
286
		foreach ($forms as $form) {
287
			if (trim($form) !== '') {
288
				return true;
289
			}
290
		}
291
		return false;
292
	}
293
294
	/**
295
	 * @inheritdoc
296
	 */
297
	public function getPersonalSettings($section): array {
298
		$settings = [];
299
		$appSettings = $this->getSettings('personal', $section);
300
301
		foreach ($appSettings as $setting) {
302
			if (!isset($settings[$setting->getPriority()])) {
303
				$settings[$setting->getPriority()] = [];
304
			}
305
			$settings[$setting->getPriority()][] = $setting;
306
		}
307
308
		ksort($settings);
309
		return $settings;
310
	}
311
}
312