Passed
Push — master ( de702b...3e9331 )
by Pauli
02:18
created

ApiController::artistToApi()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 8
nc 2
nop 3
dl 0
loc 11
ccs 0
cts 8
cp 0
crap 6
rs 10
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * ownCloud - Music app
5
 *
6
 * This file is licensed under the Affero General Public License version 3 or
7
 * later. See the COPYING file.
8
 *
9
 * @author Morris Jobke <[email protected]>
10
 * @author Pauli Järvinen <[email protected]>
11
 * @copyright Morris Jobke 2013, 2014
12
 * @copyright Pauli Järvinen 2017 - 2020
13
 */
14
15
namespace OCA\Music\Controller;
16
17
use \OCP\AppFramework\Controller;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Controller was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use \OCP\AppFramework\Http;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Http was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use \OCP\AppFramework\Http\DataDisplayResponse;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Http\DataDisplayResponse was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use \OCP\AppFramework\Http\JSONResponse;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Http\JSONResponse was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use \OCP\AppFramework\Http\RedirectResponse;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Http\RedirectResponse was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
use \OCP\Files\Folder;
0 ignored issues
show
Bug introduced by
The type OCP\Files\Folder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use \OCP\IL10N;
0 ignored issues
show
Bug introduced by
The type OCP\IL10N was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
use \OCP\IRequest;
0 ignored issues
show
Bug introduced by
The type OCP\IRequest was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
use \OCP\IURLGenerator;
0 ignored issues
show
Bug introduced by
The type OCP\IURLGenerator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
27
use \OCA\Music\AppFramework\Core\Logger;
28
use \OCA\Music\BusinessLayer\AlbumBusinessLayer;
29
use \OCA\Music\BusinessLayer\ArtistBusinessLayer;
30
use \OCA\Music\BusinessLayer\TrackBusinessLayer;
31
use \OCA\Music\Db\Album;
32
use \OCA\Music\Db\Artist;
33
use \OCA\Music\Db\Maintenance;
34
use \OCA\Music\Db\Track;
35
use \OCA\Music\Http\ErrorResponse;
36
use \OCA\Music\Http\FileResponse;
37
use \OCA\Music\Utility\CollectionHelper;
38
use \OCA\Music\Utility\CoverHelper;
39
use \OCA\Music\Utility\DetailsHelper;
40
use \OCA\Music\Utility\Scanner;
41
use OCA\Music\BusinessLayer\GenreBusinessLayer;
42
43
class ApiController extends Controller {
44
45
	/** @var IL10N */
46
	private $l10n;
47
	/** @var TrackBusinessLayer */
48
	private $trackBusinessLayer;
49
	/** @var ArtistBusinessLayer */
50
	private $artistBusinessLayer;
51
	/** @var AlbumBusinessLayer */
52
	private $albumBusinessLayer;
53
	/** @var GenreBusinessLayer */
54
	private $genreBusinessLayer;
55
	/** @var Scanner */
56
	private $scanner;
57
	/** @var CollectionHelper */
58
	private $collectionHelper;
59
	/** @var CoverHelper */
60
	private $coverHelper;
61
	/** @var DetailsHelper */
62
	private $detailsHelper;
63
	/** @var Maintenance */
64
	private $maintenance;
65
	/** @var string */
66
	private $userId;
67
	/** @var IURLGenerator */
68
	private $urlGenerator;
69
	/** @var Folder */
70
	private $userFolder;
71
	/** @var Logger */
72
	private $logger;
73
74 16
	public function __construct($appname,
75
								IRequest $request,
76
								IURLGenerator $urlGenerator,
77
								TrackBusinessLayer $trackbusinesslayer,
78
								ArtistBusinessLayer $artistbusinesslayer,
79
								AlbumBusinessLayer $albumbusinesslayer,
80
								GenreBusinessLayer $genreBusinessLayer,
81
								Scanner $scanner,
82
								CollectionHelper $collectionHelper,
83
								CoverHelper $coverHelper,
84
								DetailsHelper $detailsHelper,
85
								Maintenance $maintenance,
86
								$userId,
87
								IL10N $l10n,
88
								/*Folder*/ $userFolder, // no type-hint as this may sometimes be null
89
								Logger $logger) {
90 16
		parent::__construct($appname, $request);
91 16
		$this->l10n = $l10n;
92 16
		$this->trackBusinessLayer = $trackbusinesslayer;
93 16
		$this->artistBusinessLayer = $artistbusinesslayer;
94 16
		$this->albumBusinessLayer = $albumbusinesslayer;
95 16
		$this->genreBusinessLayer = $genreBusinessLayer;
96 16
		$this->scanner = $scanner;
97 16
		$this->collectionHelper = $collectionHelper;
98 16
		$this->coverHelper = $coverHelper;
99 16
		$this->detailsHelper = $detailsHelper;
100 16
		$this->maintenance = $maintenance;
101 16
		$this->userId = $userId;
102 16
		$this->urlGenerator = $urlGenerator;
103 16
		$this->userFolder = $userFolder;
104 16
		$this->logger = $logger;
105 16
	}
106
107
	/**
108
	 * Extracts the id from an unique slug (id-slug)
109
	 * @param string $slug the slug
110
	 * @return integer the id
111
	 */
112 2
	protected static function getIdFromSlug($slug) {
113 2
		$split = \explode('-', $slug, 2);
114
115 2
		return (int)$split[0];
116
	}
117
118
	/**
119
	 * @NoAdminRequired
120
	 * @NoCSRFRequired
121
	 */
122
	public function prepareCollection() {
123
		$hash = $this->collectionHelper->getCachedJsonHash();
124
		if ($hash === null) {
125
			// build the collection but ignore the data for now
126
			$this->collectionHelper->getJson();
127
			$hash = $this->collectionHelper->getCachedJsonHash();
128
		}
129
		return new JSONResponse(['hash' => $hash]);
130
	}
131
132
	/**
133
	 * @NoAdminRequired
134
	 * @NoCSRFRequired
135
	 */
136
	public function collection() {
137
138
		$collectionJson = $this->collectionHelper->getJson();
139
		$response = new DataDisplayResponse($collectionJson);
140
		$response->addHeader('Content-Type', 'application/json; charset=utf-8');
141
142
		// Instruct the client to cache the result in case it requested the collection with
143
		// the correct hash. The hash could be incorrect if the collection would have changed
144
		// between calls to prepareCollection() and colletion().
145
		$requestHash = $this->request->getParam('hash');
146
		$actualHash = $this->collectionHelper->getCachedJsonHash();
147
		if (!empty($actualHash) && $requestHash === $actualHash) {
148
			self::setClientCaching($response, 90); // cache for 3 months
149
		}
150
151
		return $response;
152
	}
153
154
	/**
155
	 * @NoAdminRequired
156
	 * @NoCSRFRequired
157
	 */
158
	public function folders() {
159
		$folders = $this->trackBusinessLayer->findAllFolders($this->userId, $this->userFolder);
160
		return new JSONResponse($folders);
161
	}
162
163
	/**
164
	 * @NoAdminRequired
165
	 * @NoCSRFRequired
166
	 */
167
	public function genres() {
168
		$genres = $this->genreBusinessLayer->findAllWithTrackIds($this->userId);
169
		$unscanned =  $this->trackBusinessLayer->findFilesWithoutScannedGenre($this->userId);
170
		return new JSONResponse([
171
			'genres' => \array_map(function($g) {return $g->toApi();}, $genres),
172
			'unscanned' => $unscanned
173
		]);
174
	}
175
176
	/**
177
	 * @NoAdminRequired
178
	 * @NoCSRFRequired
179
	 */
180
	public function artists($fulltree, $albums) {
181
		$fulltree = \filter_var($fulltree, FILTER_VALIDATE_BOOLEAN);
182
		$includeAlbums = \filter_var($albums, FILTER_VALIDATE_BOOLEAN);
183
		/** @var Artist[] $artists */
184
		$artists = $this->artistBusinessLayer->findAll($this->userId);
185
186
		$artists = \array_map(function($a) use ($fulltree, $includeAlbums) {
187
			return $this->artistToApi($a, $includeAlbums || $fulltree, $fulltree);
188
		}, $artists);
189
190
		return new JSONResponse($artists);
191
	}
192
193
	/**
194
	 * @NoAdminRequired
195
	 * @NoCSRFRequired
196
	 */
197
	public function artist($artistIdOrSlug, $fulltree) {
198
		$fulltree = \filter_var($fulltree, FILTER_VALIDATE_BOOLEAN);
199
		$artistId = $this->getIdFromSlug($artistIdOrSlug);
200
		/** @var Artist $artist */
201
		$artist = $this->artistBusinessLayer->find($artistId, $this->userId);
202
		$artist = $this->artistToApi($artist, $fulltree, $fulltree);
203
		return new JSONResponse($artist);
204
	}
205
206
	/**
207
	 * Return given artist in Shia API format
208
	 * @param Artist $artist
209
	 * @param boolean $includeAlbums
210
	 * @param boolean $includeTracks (ignored if $includeAlbums==false)
211
	 * @return array
212
	 */
213
	private function artistToApi($artist, $includeAlbums, $includeTracks) {
214
		$artistInApi = $artist->toAPI($this->urlGenerator, $this->l10n);
215
		if ($includeAlbums) {
216
			$artistId = $artist->getId();
217
			$albums = $this->albumBusinessLayer->findAllByArtist($artistId, $this->userId);
218
219
			$artistInApi['albums'] = \array_map(function($a) use ($includeTracks) {
220
				return $this->albumToApi($a, $includeTracks, false);
221
			}, $albums);
222
		}
223
		return $artistInApi;
224
	}
225
226
	/**
227
	 * @NoAdminRequired
228
	 * @NoCSRFRequired
229
	 */
230 1
	public function albums($artist, $fulltree) {
231 1
		$fulltree = \filter_var($fulltree, FILTER_VALIDATE_BOOLEAN);
232 1
		if ($artist) {
233
			$albums = $this->albumBusinessLayer->findAllByArtist($artist, $this->userId);
234
		} else {
235 1
			$albums = $this->albumBusinessLayer->findAll($this->userId);
236
		}
237
238
		$albums = \array_map(function($a) use ($fulltree) {
239 1
			return $this->albumToApi($a, $fulltree, $fulltree);
240 1
		}, $albums);
241
242 1
		return new JSONResponse($albums);
243
	}
244
245
	/**
246
	 * @NoAdminRequired
247
	 * @NoCSRFRequired
248
	 */
249 1
	public function album($albumIdOrSlug, $fulltree) {
250 1
		$fulltree = \filter_var($fulltree, FILTER_VALIDATE_BOOLEAN);
251 1
		$albumId = $this->getIdFromSlug($albumIdOrSlug);
252 1
		$album = $this->albumBusinessLayer->find($albumId, $this->userId);
253 1
		$album = $this->albumToApi($album, $fulltree, $fulltree);
254 1
		return new JSONResponse($album);
255
	}
256
257
	/**
258
	 * Return given album in the Shiva API format
259
	 * @param Album $album
260
	 * @param boolean $includeTracks
261
	 * @param boolean $includeAlbums
262
	 * @return array
263
	 */
264 2
	private function albumToApi($album, $includeTracks, $includeArtists) {
265 2
		$albumInApi = $album->toAPI($this->urlGenerator, $this->l10n);
266
267 2
		if ($includeTracks) {
268
			$albumId = $album->getId();
269
			$tracks = $this->trackBusinessLayer->findAllByAlbum($albumId, $this->userId);
270
			$albumInApi['tracks'] = \array_map(function($t) {
271
				return $t->toAPI($this->urlGenerator);
272
			}, $tracks);
273
		}
274
275 2
		if ($includeArtists) {
276
			$artistIds = $album->getArtistIds();
277
			$artists = $this->artistBusinessLayer->findById($artistIds, $this->userId);
278
			$albumInApi['artists'] = \array_map(function($a) {
279
				return $a->toAPI($this->urlGenerator, $this->l10n);
280
			}, $artists);
281
		}
282
283 2
		return $albumInApi;
284
	}
285
286
	/**
287
	 * @NoAdminRequired
288
	 * @NoCSRFRequired
289
	 */
290 3
	public function tracks($artist, $album, $fulltree) {
291 3
		$fulltree = \filter_var($fulltree, FILTER_VALIDATE_BOOLEAN);
292 3
		if ($artist) {
293 1
			$tracks = $this->trackBusinessLayer->findAllByArtist($artist, $this->userId);
294 2
		} elseif ($album) {
295 1
			$tracks = $this->trackBusinessLayer->findAllByAlbum($album, $this->userId);
296
		} else {
297 1
			$tracks = $this->trackBusinessLayer->findAll($this->userId);
298
		}
299 3
		foreach ($tracks as &$track) {
300 3
			$artistId = $track->getArtistId();
301 3
			$albumId = $track->getAlbumId();
302 3
			$track = $track->toAPI($this->urlGenerator);
303 3
			if ($fulltree) {
304
				/** @var Artist $artist */
305
				$artist = $this->artistBusinessLayer->find($artistId, $this->userId);
306
				$track['artist'] = $artist->toAPI($this->urlGenerator, $this->l10n);
307
				$album = $this->albumBusinessLayer->find($albumId, $this->userId);
308 3
				$track['album'] = $album->toAPI($this->urlGenerator, $this->l10n);
309
			}
310
		}
311 3
		return new JSONResponse($tracks);
312
	}
313
314
	/**
315
	 * @NoAdminRequired
316
	 * @NoCSRFRequired
317
	 */
318 1
	public function track($trackIdOrSlug) {
319 1
		$trackId = $this->getIdFromSlug($trackIdOrSlug);
320
		/** @var Track $track */
321 1
		$track = $this->trackBusinessLayer->find($trackId, $this->userId);
322 1
		return new JSONResponse($track->toAPI($this->urlGenerator));
323
	}
324
325
	/**
326
	 * @NoAdminRequired
327
	 * @NoCSRFRequired
328
	 */
329 1
	public function trackByFileId($fileId) {
330 1
		$track = $this->trackBusinessLayer->findByFileId($fileId, $this->userId);
331 1
		if ($track !== null) {
332 1
			$track->setAlbum($this->albumBusinessLayer->find($track->getAlbumId(), $this->userId));
333 1
			$track->setArtist($this->artistBusinessLayer->find($track->getArtistId(), $this->userId));
334 1
			return new JSONResponse($track->toCollection($this->l10n));
335
		} else {
336
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
337
		}
338
	}
339
340
	/**
341
	 * @NoAdminRequired
342
	 * @NoCSRFRequired
343
	 */
344
	public function getScanState() {
345
		return new JSONResponse([
346
			'unscannedFiles' => $this->scanner->getUnscannedMusicFileIds($this->userId),
347
			'scannedCount' => $this->trackBusinessLayer->count($this->userId)
348
		]);
349
	}
350
351
	/**
352
	 * @NoAdminRequired
353
	 * @UseSession to keep the session reserved while execution in progress
354
	 */
355
	public function scan($files, $finalize) {
356
		// extract the parameters
357
		$fileIds = \array_map('intval', \explode(',', $files));
358
		$finalize = \filter_var($finalize, FILTER_VALIDATE_BOOLEAN);
359
360
		$filesScanned = $this->scanner->scanFiles($this->userId, $this->userFolder, $fileIds);
361
362
		$coversUpdated = false;
363
		if ($finalize) {
364
			$coversUpdated = $this->scanner->findAlbumCovers($this->userId)
365
							|| $this->scanner->findArtistCovers($this->userId);
366
			$totalCount = $this->trackBusinessLayer->count($this->userId);
367
			$this->logger->log("Scanning finished, user $this->userId has $totalCount scanned tracks in total", 'info');
368
		}
369
370
		return new JSONResponse([
371
			'filesScanned' => $filesScanned,
372
			'coversUpdated' => $coversUpdated
373
		]);
374
	}
375
376
	/**
377
	 * @NoAdminRequired
378
	 * @UseSession to keep the session reserved while execution in progress
379
	 */
380
	public function resetScanned() {
381
		$this->maintenance->resetDb($this->userId);
382
		return new JSONResponse(['success' => true]);
383
	}
384
385
	/**
386
	 * @NoAdminRequired
387
	 * @NoCSRFRequired
388
	 */
389
	public function download($fileId) {
390
		$track = $this->trackBusinessLayer->findByFileId($fileId, $this->userId);
391
		if ($track === null) {
392
			return new ErrorResponse(Http::STATUS_NOT_FOUND, 'track not found');
393
		}
394
395
		$nodes = $this->userFolder->getById($track->getFileId());
396
		if (\count($nodes) > 0) {
397
			// get the first valid node
398
			$node = $nodes[0];
399
400
			$mime = $node->getMimeType();
401
			$content = $node->getContent();
402
			return new FileResponse(['mimetype' => $mime, 'content' => $content]);
403
		}
404
405
		return new ErrorResponse(Http::STATUS_NOT_FOUND, 'file not found');
406
	}
407
408
	/**
409
	 * @NoAdminRequired
410
	 * @NoCSRFRequired
411
	 */
412
	public function filePath($fileId) {
413
		$nodes = $this->userFolder->getById($fileId);
414
		if (\count($nodes) == 0) {
415
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
416
		} else {
417
			$node = $nodes[0];
418
			$path = $this->userFolder->getRelativePath($node->getPath());
419
			// URL encode each part of the file path
420
			$path = \join('/', \array_map('rawurlencode', \explode('/', $path)));
421
			return new JSONResponse(['path' => $path]);
422
		}
423
	}
424
425
	/**
426
	 * @NoAdminRequired
427
	 * @NoCSRFRequired
428
	 */
429
	public function fileInfo($fileId) {
430
		$info = $this->scanner->getFileInfo($fileId, $this->userId, $this->userFolder);
431
		if ($info) {
432
			return new JSONResponse($info);
433
		} else {
434
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
435
		}
436
	}
437
438
	/**
439
	 * @NoAdminRequired
440
	 * @NoCSRFRequired
441
	 */
442
	public function fileDetails($fileId) {
443
		$details = $this->detailsHelper->getDetails($fileId, $this->userFolder);
444
		if ($details) {
445
			return new JSONResponse($details);
446
		} else {
447
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
448
		}
449
	}
450
451
	/**
452
	 * @NoAdminRequired
453
	 * @NoCSRFRequired
454
	 */
455
	public function albumCover($albumIdOrSlug) {
456
		$albumId = $this->getIdFromSlug($albumIdOrSlug);
457
		$album = $this->albumBusinessLayer->find($albumId, $this->userId);
458
		return $this->cover($album);
459
	}
460
461
	/**
462
	 * @NoAdminRequired
463
	 * @NoCSRFRequired
464
	 */
465
	public function artistCover($artistIdOrSlug) {
466
		$artistId = $this->getIdFromSlug($artistIdOrSlug);
467
		$artist = $this->artistBusinessLayer->find($artistId, $this->userId);
468
		return $this->cover($artist);
469
	}
470
471
	private function cover($entity) {
472
		$coverAndHash = $this->coverHelper->getCoverAndHash($entity, $this->userId, $this->userFolder);
473
474
		if ($coverAndHash['hash'] !== null) {
475
			// Cover is in cache. Return a redirection response so that the client
476
			// will fetch the content through a cacheable route.
477
			$link = $this->urlGenerator->linkToRoute('music.api.cachedCover', ['hash' => $coverAndHash['hash']]);
478
			return new RedirectResponse($link);
479
		} else if ($coverAndHash['data'] !== null) {
480
			return new FileResponse($coverAndHash['data']);
481
		} else {
482
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
483
		}
484
	}
485
486
	/**
487
	 * @NoAdminRequired
488
	 * @NoCSRFRequired
489
	 */
490
	public function cachedCover($hash) {
491
		$coverData = $this->coverHelper->getCoverFromCache($hash, $this->userId);
492
493
		if ($coverData !== null) {
494
			$response =  new FileResponse($coverData);
495
			// instruct also the client-side to cache the result, this is safe
496
			// as the resource URI contains the image hash
497
			self::setClientCaching($response);
498
			return $response;
499
		} else {
500
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
501
		}
502
	}
503
504
	private static function setClientCaching(&$httpResponse, $days=365) {
505
		$httpResponse->cacheFor($days * 24 * 60 * 60);
506
		$httpResponse->addHeader('Pragma', 'cache');
507
	}
508
}
509