Completed
Push — master ( d82ef7...8f6acb )
by Morris
53:16 queued 33:45
created

ImageManager::delete()   B

Complexity

Conditions 5
Paths 25

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 11
nc 25
nop 1
dl 0
loc 15
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016 Julius Härtl <[email protected]>
4
 *
5
 * @author Julius Haertl <[email protected]>
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License as
11
 * published by the Free Software Foundation, either version 3 of the
12
 * License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 */
23
24
25
namespace OCA\Theming;
26
27
use OCP\Files\SimpleFS\ISimpleFile;
28
use OCP\Files\SimpleFS\ISimpleFolder;
29
use OCP\ICacheFactory;
30
use OCP\IConfig;
31
use OCP\Files\IAppData;
32
use OCP\Files\NotFoundException;
33
use OCP\Files\NotPermittedException;
34
use OCP\ILogger;
35
use OCP\IURLGenerator;
36
37
class ImageManager {
38
39
	/** @var IConfig */
40
	private $config;
41
	/** @var IAppData */
42
	private $appData;
43
	/** @var IURLGenerator */
44
	private $urlGenerator;
45
	/** @var array */
46
	private $supportedImageKeys = ['background', 'logo', 'logoheader', 'favicon'];
47
	/** @var ICacheFactory */
48
	private $cacheFactory;
49
	/** @var ILogger */
50
	private $logger;
51
52
	/**
53
	 * ImageManager constructor.
54
	 *
55
	 * @param IConfig $config
56
	 * @param IAppData $appData
57
	 * @param IURLGenerator $urlGenerator
58
	 * @param ICacheFactory $cacheFactory
59
	 * @param ILogger $logger
60
	 */
61 View Code Duplication
	public function __construct(IConfig $config,
62
								IAppData $appData,
63
								IURLGenerator $urlGenerator,
64
								ICacheFactory $cacheFactory,
65
								ILogger $logger
66
	) {
67
		$this->config = $config;
68
		$this->appData = $appData;
69
		$this->urlGenerator = $urlGenerator;
70
		$this->cacheFactory = $cacheFactory;
71
		$this->logger = $logger;
72
	}
73
74
	public function getImageUrl(string $key, bool $useSvg = true): string {
75
		$cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0');
76
		try {
77
			$image = $this->getImage($key, $useSvg);
0 ignored issues
show
Unused Code introduced by
$image is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
78
			return $this->urlGenerator->linkToRoute('theming.Theming.getImage', [ 'key' => $key ]) . '?v=' . $cacheBusterCounter;
79
		} catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
80
		}
81
82
		switch ($key) {
83
			case 'logo':
84
			case 'logoheader':
85
			case 'favicon':
86
				return $this->urlGenerator->imagePath('core', 'logo.png') . '?v=' . $cacheBusterCounter;
87
			case 'background':
88
				return $this->urlGenerator->imagePath('core', 'background.png') . '?v=' . $cacheBusterCounter;
89
		}
90
	}
91
92
	public function getImageUrlAbsolute(string $key, bool $useSvg = true): string {
93
		return $this->urlGenerator->getAbsoluteURL($this->getImageUrl($key, $useSvg));
94
	}
95
96
	/**
97
	 * @param string $key
98
	 * @param bool $useSvg
99
	 * @return ISimpleFile
100
	 * @throws NotFoundException
101
	 * @throws NotPermittedException
102
	 */
103
	public function getImage(string $key, bool $useSvg = true): ISimpleFile {
104
		$pngFile = null;
105
		$logo = $this->config->getAppValue('theming', $key . 'Mime', false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
106
		$folder = $this->appData->getFolder('images');
107
		if ($logo === false || !$folder->fileExists($key)) {
108
			throw new NotFoundException();
109
		}
110
		if (!$useSvg && $this->shouldReplaceIcons()) {
111
			if (!$folder->fileExists($key . '.png')) {
112
				try {
113
					$finalIconFile = new \Imagick();
114
					$finalIconFile->setBackgroundColor('none');
115
					$finalIconFile->readImageBlob($folder->getFile($key)->getContent());
116
					$finalIconFile->setImageFormat('png32');
117
					$pngFile = $folder->newFile($key . '.png');
118
					$pngFile->putContent($finalIconFile->getImageBlob());
119
				} catch (\ImagickException $e) {
120
					$this->logger->info('The image was requested to be no SVG file, but converting it to PNG failed.', $e->getMessage());
0 ignored issues
show
Documentation introduced by
$e->getMessage() is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
121
					$pngFile = null;
122
				}
123
			} else {
124
				$pngFile = $folder->getFile($key . '.png');
125
			}
126
		}
127
		if ($pngFile !== null) {
128
			return $pngFile;
129
		}
130
		return $folder->getFile($key);
131
	}
132
133
	public function getCustomImages(): array {
134
		$images = [];
135
		foreach ($this->supportedImageKeys as $key) {
136
			$images[$key] = [
137
				'mime' => $this->config->getAppValue('theming', $key . 'Mime', ''),
138
				'url' => $this->getImageUrl($key),
139
			];
140
		}
141
		return $images;
142
	}
143
144
	/**
145
	 * Get folder for current theming files
146
	 *
147
	 * @return ISimpleFolder
148
	 * @throws NotPermittedException
149
	 */
150
	public function getCacheFolder(): ISimpleFolder {
151
		$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0');
152
		try {
153
			$folder = $this->appData->getFolder($cacheBusterValue);
154
		} catch (NotFoundException $e) {
155
			$folder = $this->appData->newFolder($cacheBusterValue);
156
			$this->cleanup();
157
		}
158
		return $folder;
159
	}
160
161
	/**
162
	 * Get a file from AppData
163
	 *
164
	 * @param string $filename
165
	 * @throws NotFoundException
166
	 * @return \OCP\Files\SimpleFS\ISimpleFile
167
	 * @throws NotPermittedException
168
	 */
169
	public function getCachedImage(string $filename): ISimpleFile {
170
		$currentFolder = $this->getCacheFolder();
171
		return $currentFolder->getFile($filename);
172
	}
173
174
	/**
175
	 * Store a file for theming in AppData
176
	 *
177
	 * @param string $filename
178
	 * @param string $data
179
	 * @return \OCP\Files\SimpleFS\ISimpleFile
180
	 * @throws NotFoundException
181
	 * @throws NotPermittedException
182
	 */
183
	public function setCachedImage(string $filename, string $data): ISimpleFile {
184
		$currentFolder = $this->getCacheFolder();
185
		if ($currentFolder->fileExists($filename)) {
186
			$file = $currentFolder->getFile($filename);
187
		} else {
188
			$file = $currentFolder->newFile($filename);
189
		}
190
		$file->putContent($data);
191
		return $file;
192
	}
193
194
	public function delete(string $key) {
195
		/* ignore exceptions, since we don't want to fail hard if something goes wrong during cleanup */
196
		try {
197
			$file = $this->appData->getFolder('images')->getFile($key);
198
			$file->delete();
199
		} catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
200
		} catch (NotPermittedException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
201
		}
202
		try {
203
			$file = $this->appData->getFolder('images')->getFile($key . '.png');
204
			$file->delete();
205
		} catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
206
		} catch (NotPermittedException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
207
		}
208
	}
209
210
	/**
211
	 * remove cached files that are not required any longer
212
	 *
213
	 * @throws NotPermittedException
214
	 * @throws NotFoundException
215
	 */
216
	public function cleanup() {
217
		$currentFolder = $this->getCacheFolder();
218
		$folders = $this->appData->getDirectoryListing();
219
		foreach ($folders as $folder) {
220
			if ($folder->getName() !== 'images' && $folder->getName() !== $currentFolder->getName()) {
221
				$folder->delete();
222
			}
223
		}
224
	}
225
226
	/**
227
	 * Check if Imagemagick is enabled and if SVG is supported
228
	 * otherwise we can't render custom icons
229
	 *
230
	 * @return bool
231
	 */
232
	public function shouldReplaceIcons() {
233
		$cache = $this->cacheFactory->createDistributed('theming-' . $this->urlGenerator->getBaseUrl());
234
		if($value = $cache->get('shouldReplaceIcons')) {
235
			return (bool)$value;
236
		}
237
		$value = false;
238
		if(extension_loaded('imagick')) {
239
			if (count(\Imagick::queryFormats('SVG')) >= 1) {
240
				$value = true;
241
			}
242
		}
243
		$cache->set('shouldReplaceIcons', $value);
244
		return $value;
245
	}
246
}
247