Passed
Push — master ( 909357...3eb748 )
by Blizzz
11:53
created

Manager::getPersonalSections()   B

Complexity

Conditions 7
Paths 12

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 14
c 1
b 0
f 0
nc 12
nop 0
dl 0
loc 27
rs 8.8333
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\IManager;
42
use OCP\Settings\ISection;
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\ISection
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 ISection[]
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 ISection $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
			if (!$section instanceof ISection) {
119
				$this->log->logException(new \InvalidArgumentException('Invalid settings section registered'), ['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

119
				$this->log->logException(new \InvalidArgumentException('Invalid settings section registered'), ['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...
120
				continue;
121
			}
122
123
			$sectionID = $section->getID();
124
125
			if (isset($this->sections[$type][$sectionID])) {
126
				$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

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

178
				$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...
179
				continue;
180
			}
181
182
			if (!$setting instanceof ISettings) {
183
				$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

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