IndexKey::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
rs 9.4285
cc 1
eloc 4
nc 1
nop 3
1
<?php
2
3
/*
4
 * This file is part of the Icybee package.
5
*
6
* (c) Olivier Laviale <[email protected]>
7
*
8
* For the full copyright and license information, please view the LICENSE
9
* file that was distributed with this source code.
10
*/
11
12
namespace Icybee\Modules\Files\Storage;
13
14
use ICanBoogie\Accessor\AccessorTrait;
15
16
/**
17
 * Representation of an index key.
18
 *
19
 * @property-read int $id Record identifier.
20
 * @property-read string $uuid Record v4 UUID.
21
 * @property-read string $hash A hash from {@link Pathname::hash()}
22
 * @property-read string $encoded_id Encoded `$id`.
23
 * @property-read string $encoded_uuid Encoded `uuid`.
24
 */
25
class IndexKey
26
{
27
	use AccessorTrait;
28
29
	const UUID_LENGTH = 36;
30
	const ENCODED_ID_LENGTH = 16;
31
	const ENCODED_UUID_LENGTH = 22;
32
	const HASH_LENGTH = Pathname::HASH_LENGTH;
33
34
	/**
35
	 * @var IndexKey[]
36
	 */
37
	static private $instances = [];
38
39
	/**
40
	 * Creates a {@link IndexKey} instance from a composite key string or array.
41
	 *
42
	 * @param string|array $composite_or_array A composite key string or array.
43
	 *
44
	 * @return static
45
	 */
46
	static public function from($composite_or_array)
47
	{
48
		$composite = $composite_or_array;
49
50
		if (is_array($composite_or_array))
51
		{
52
			list($id, $uuid, $hash) = $composite_or_array;
53
54
			return static::from(self::format_key(self::encode_id($id), self::encode_uuid($uuid), $hash));
55
		}
56
57
		if (isset(self::$instances[$composite]))
58
		{
59
			return self::$instances[$composite];
60
		}
61
62
		list($encoded_id, $encoded_uuid, $hash) = self::parse_key($composite);
0 ignored issues
show
Bug introduced by
It seems like $composite can also be of type array; however, Icybee\Modules\Files\Storage\IndexKey::parse_key() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
63
64
		return self::$instances[$composite] = new static($encoded_id, $encoded_uuid, $hash);
65
	}
66
67
	/**
68
	 * Parse index key string.
69
	 *
70
	 * @param string $key
71
	 *
72
	 * @return array
73
	 */
74
	static private function parse_key($key)
75
	{
76
		$encoded_id = substr($key, 0, self::ENCODED_ID_LENGTH);
77
		$encoded_uuid = substr($key, self::ENCODED_ID_LENGTH + 1, self::ENCODED_UUID_LENGTH);
78
		$hash = substr($key, self::ENCODED_ID_LENGTH + 1 + self::ENCODED_UUID_LENGTH + 1);
79
80
		return [ $encoded_id, $encoded_uuid, $hash ];
81
	}
82
83
	/**
84
	 * Formats a composite key.
85
	 *
86
	 * @param string $encoded_id
87
	 * @param string $encoded_uuid
88
	 * @param string $hash
89
	 *
90
	 * @return string
91
	 */
92
	static private function format_key($encoded_id, $encoded_uuid, $hash)
93
	{
94
		return "{$encoded_id}-{$encoded_uuid}-{$hash}";
95
	}
96
97
	/**
98
	 * Encodes identifier as a key part.
99
	 *
100
	 * @param int $id
101
	 *
102
	 * @return string
103
	 */
104
	static public function encode_id($id)
105
	{
106
		return sprintf('%0' . self::ENCODED_ID_LENGTH . 'x', $id);
107
	}
108
109
	/**
110
	 * Decodes identifier encoded by {@link self::encode_id()}.
111
	 *
112
	 * @param string $encoded_id
113
	 *
114
	 * @return number
115
	 */
116
	static public function decode_id($encoded_id)
117
	{
118
		return hexdec($encoded_id);
119
	}
120
121
	/**
122
	 * Encodes a UUID as a key part.
123
	 *
124
	 * @param $uuid
125
	 *
126
	 * @return string
127
	 */
128
	static public function encode_uuid($uuid)
129
	{
130
		if (preg_match('/[^0-9a-f\-]/', $uuid))
131
		{
132
			throw new \LogicException("Invalid UUID: $uuid.");
133
		}
134
135
		return Base64::encode_unpadded(hex2bin(strtr($uuid, [ '-' => '' ])));
136
	}
137
138
	/**
139
	 * Decodes UUID encoded by {@link self::encode_uuid()}.
140
	 *
141
	 * @param string $encoded_uuid
142
	 *
143
	 * @return string
144
	 */
145
	static public function decode_uuid($encoded_uuid)
146
	{
147
		$data = Base64::decode_unpadded($encoded_uuid);
148
		$data = bin2hex($data);
149
150
		return implode('-', str_split($data, 4));
151
	}
152
153
	/**
154
	 * @var int
155
	 */
156
	private $encoded_id;
157
158
	protected function get_encoded_id()
159
	{
160
		return $this->encoded_id;
161
	}
162
163
	protected function get_id()
164
	{
165
		return self::decode_id($this->encoded_id);
166
	}
167
168
	/**
169
	 * @var string
170
	 */
171
	private $encoded_uuid;
172
173
	protected function get_encoded_uuid()
174
	{
175
		return $this->encoded_uuid;
176
	}
177
178
	protected function get_uuid()
179
	{
180
		return self::decode_uuid($this->encoded_uuid);
181
	}
182
183
	/**
184
	 * @var string
185
	 */
186
	private $hash;
187
188
	protected function get_hash()
189
	{
190
		return $this->hash;
191
	}
192
193
	/**
194
	 * @param string $encoded_id An encoded identifier as returned by {@link self::encode_id()}
195
	 * @param string $encoded_uuid A UUID as encoded by {@link self::encode_uid()}
196
	 * @param string $hash A hash as returned by {@link Pathname::hash()}
197
	 */
198
	private function __construct($encoded_id, $encoded_uuid, $hash)
199
	{
200
		$this->encoded_id = $encoded_id;
0 ignored issues
show
Documentation Bug introduced by
The property $encoded_id was declared of type integer, but $encoded_id is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
201
		$this->encoded_uuid = $encoded_uuid;
202
		$this->hash = $hash;
203
	}
204
205
	/**
206
	 * Returns a formatted composite key.
207
	 *
208
	 * @return string
209
	 */
210
	public function __toString()
211
	{
212
		return self::format_key($this->encoded_id, $this->encoded_uuid, $this->hash);
213
	}
214
}
215