Passed
Push — master ( 7b8fea...bb5769 )
by Pauli
10:49
created

Random   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 85
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 30
dl 0
loc 85
rs 10
c 1
b 0
f 0
wmc 12

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A getIndices() 0 17 4
A decodeIndices() 0 5 2
A encodeIndices() 0 2 1
A secure() 0 2 1
A pickItems() 0 13 3
1
<?php declare(strict_types=1);
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 Pauli Järvinen <[email protected]>
10
 * @copyright Pauli Järvinen 2020
11
 */
12
13
namespace OCA\Music\Utility;
14
15
use \OCA\Music\AppFramework\Core\Logger;
16
use \OCA\Music\Db\Cache;
17
18
class Random {
19
	private $cache;
20
	private $logger;
21
22
	public function __construct(Cache $cache, Logger $logger) {
23
		$this->cache = $cache;
24
		$this->logger = $logger;
25
	}
26
27
	/**
28
	 * Create cryptographicaly secure random string
29
	 */
30
	public static function secure(int $length) : string {
31
		return \bin2hex(\random_bytes($length));
32
	}
33
34
	/**
35
	 * Get desired number of random items from the given array
36
	 *
37
	 * @param array $itemArray
38
	 * @param int $count
39
	 * @return array
40
	 */
41
	public static function pickItems(array $itemArray, int $count) : array {
42
		$count = \min($count, \count($itemArray)); // can't return more than all items
43
44
		if ($count == 0) {
45
			return [];
46
		} else {
47
			$indices = \array_rand($itemArray, $count);
48
			if ($count == 1) { // return type is not array when randomizing a single index
49
				$indices = [$indices];
50
			}
51
			\shuffle($indices);
52
53
			return Util::arrayMultiGet($itemArray, $indices);
54
		}
55
	}
56
57
	/**
58
	 * Get desired number of random array indices. This function supports paging
59
	 * so that all the indices can be browsed through page-by-page, without getting
60
	 * the same index more than once. This requires persistence and identifying the
61
	 * logical array in question. The array is identified by the user ID and a free
62
	 * text identifier supplied by the caller.
63
	 *
64
	 * For a single logical array, the indices are shuffled every time when the
65
	 * page 0 is requested. Also, if the size of the array in question has changed
66
	 * since the previous call, then the indices are reshuffled.
67
	 *
68
	 * @param int $arrSize
69
	 * @param int $offset
70
	 * @param int $count
71
	 * @param string $userId
72
	 * @param string $arrId
73
	 * @return int[]
74
	 */
75
	public function getIndices(int $arrSize, int $offset, int $count, string $userId, string $arrId) : array {
76
		$cacheKey = 'random_indices_' . $arrId;
77
78
		$indices = self::decodeIndices($this->cache->get($userId, $cacheKey));
79
80
		// reshuffle if necessary
81
		if ($offset == 0 || \count($indices) != $arrSize) {
82
			if ($arrSize > 0) {
83
				$indices = \range(0, $arrSize - 1);
84
			} else {
85
				$indices = [];
86
			}
87
			\shuffle($indices);
88
			$this->cache->set($userId, $cacheKey, self::encodeIndices($indices));
89
		}
90
91
		return \array_slice($indices, $offset, $count);
92
	}
93
94
	private static function encodeIndices($indices) {
95
		return \implode(',', $indices);
96
	}
97
98
	private static function decodeIndices($buffer) {
99
		if (empty($buffer)) {
100
			return [];
101
		} else {
102
			return \explode(',', $buffer);
103
		}
104
	}
105
}
106