Failed Conditions
Pull Request — master (#47)
by Mateusz
05:47
created

src/Util/TwoDimensionalHashMap.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the puli/manager package.
5
 *
6
 * (c) Bernhard Schussek <[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 Puli\Manager\Util;
13
14
use OutOfBoundsException;
15
16
/**
17
 * An hash-map for values identified by a two-dimensional key.
18
 *
19
 * Every value in the store has a primary key and a secondary key. When adding
20
 * values to the store, both keys need to be defined. When retrieving values
21
 * from the store, you can either get the value for a composite key or all
22
 * values for the primary key indexed by their secondary keys.
23
 *
24
 * @since  1.0
25
 *
26
 * @author Bernhard Schussek <[email protected]>
27
 */
28
class TwoDimensionalHashMap
29
{
30
    /**
31
     * @var array[]
32
     */
33
    private $values = array();
34
35
    /**
36
     * Sets a value in the store.
37
     *
38
     * @param int|string $primaryKey   The primary key.
39
     * @param int|string $secondaryKey The secondary key.
40
     * @param mixed      $value        The value.
41
     */
42 146
    public function set($primaryKey, $secondaryKey, $value)
43
    {
44 146
        if (!isset($this->values[$primaryKey])) {
45 146
            $this->values[$primaryKey] = array();
46
        }
47
48 146
        $this->values[$primaryKey][$secondaryKey] = $value;
49 146
    }
50
51
    /**
52
     * Removes a value from the store.
53
     *
54
     * This method ignores non-existing keys.
55
     *
56
     * @param int|string $primaryKey   The primary key.
57
     * @param int|string $secondaryKey The secondary key.
58
     */
59 31
    public function remove($primaryKey, $secondaryKey)
60
    {
61 31
        unset($this->values[$primaryKey][$secondaryKey]);
62
63 31
        if (isset($this->values[$primaryKey]) && 0 === count($this->values[$primaryKey])) {
64 24
            unset($this->values[$primaryKey]);
65
        }
66 31
    }
67
68
    /**
69
     * Removes all values for the given primary key.
70
     *
71
     * This method ignores non-existing keys.
72
     *
73
     * @param int|string $primaryKey The primary key.
74
     */
75 1
    public function removeAll($primaryKey)
76
    {
77 1
        unset($this->values[$primaryKey]);
78 1
    }
79
80
    /**
81
     * Returns a value from the store.
82
     *
83
     * @param int|string $primaryKey   The primary key.
84
     * @param int|string $secondaryKey The secondary key.
85
     *
86
     * @return mixed The value.
87
     *
88
     * @throws OutOfBoundsException If no value is set for the given keys.
89
     */
90 44
    public function get($primaryKey, $secondaryKey)
91
    {
92 44 View Code Duplication
        if (!isset($this->values[$primaryKey][$secondaryKey])) {
93 1
            throw new OutOfBoundsException(sprintf(
94 1
                'The key ("%s","%s") does not exist.',
95
                $primaryKey,
96
                $secondaryKey
97
            ));
98
        }
99
100 43
        return $this->values[$primaryKey][$secondaryKey];
101
    }
102
103
    /**
104
     * Returns whether the store contains the given key(s).
105
     *
106
     * The secondary key is optional. If you don't pass it, this method returns
107
     * `true` if the store contains the given primary key with any secondary
108
     * key.
109
     *
110
     * @param int|string      $primaryKey   The primary key.
111
     * @param int|string|null $secondaryKey The secondary key.
112
     *
113
     * @return bool Returns `true` if the store contains the given key(s).
114
     */
115 107
    public function contains($primaryKey, $secondaryKey = null)
116
    {
117 107
        if (null !== $secondaryKey) {
118 99
            return isset($this->values[$primaryKey][$secondaryKey]);
119
        }
120
121 86
        return isset($this->values[$primaryKey]);
122
    }
123
124
    /**
125
     * Returns the first value set for the given primary key.
126
     *
127
     * @param int|string $primaryKey The primary key.
128
     *
129
     * @return mixed The value.
130
     *
131
     * @throws OutOfBoundsException If the primary key does not exist.
132
     */
133 49 View Code Duplication
    public function getFirst($primaryKey)
134
    {
135 49
        if (!isset($this->values[$primaryKey])) {
136 1
            throw new OutOfBoundsException(sprintf(
137 1
                'The key "%s" does not exist.',
138
                $primaryKey
139
            ));
140
        }
141
142 48
        return reset($this->values[$primaryKey]);
143
    }
144
145
    /**
146
     * Returns the last value set for the given primary key.
147
     *
148
     * @param int|string $primaryKey The primary key.
149
     *
150
     * @return mixed The value.
151
     *
152
     * @throws OutOfBoundsException If the primary key does not exist.
153
     */
154 2 View Code Duplication
    public function getLast($primaryKey)
155
    {
156 2
        if (!isset($this->values[$primaryKey])) {
157 1
            throw new OutOfBoundsException(sprintf(
158 1
                'The key "%s" does not exist.',
159
                $primaryKey
160
            ));
161
        }
162
163 1
        return end($this->values[$primaryKey]);
164
    }
165
166
    /**
167
     * Returns the number of secondary keys set for the given primary key.
168
     *
169
     * @param int|string $primaryKey The primary key.
170
     *
171
     * @return int The number of secondary keys set for the primary key.
172
     *
173
     * @throws OutOfBoundsException If the primary key does not exist.
174
     */
175 3 View Code Duplication
    public function getCount($primaryKey)
176
    {
177 3
        if (!isset($this->values[$primaryKey])) {
178 1
            throw new OutOfBoundsException(sprintf(
179 1
                'The key "%s" does not exist.',
180
                $primaryKey
181
            ));
182
        }
183
184 2
        return count($this->values[$primaryKey]);
185
    }
186
187
    /**
188
     * Returns all values set for the given primary key.
189
     *
190
     * @param int|string $primaryKey The primary key.
191
     *
192
     * @return array The values indexed by their secondary keys.
193
     *
194
     * @throws OutOfBoundsException If the primary key does not exist.
195
     */
196 78 View Code Duplication
    public function listByPrimaryKey($primaryKey)
197
    {
198 78
        if (!isset($this->values[$primaryKey])) {
199 3
            throw new OutOfBoundsException(sprintf(
200 3
                'The key "%s" does not exist.',
201
                $primaryKey
202
            ));
203
        }
204
205 75
        return $this->values[$primaryKey];
206
    }
207
208
    /**
209
     * Returns all values set for the given secondary key.
210
     *
211
     * @param int|string $secondaryKey The secondary key.
212
     *
213
     * @return array The values indexed by their primary keys.
214
     *
215
     * @throws OutOfBoundsException If the secondary key does not exist.
216
     */
217 13
    public function listBySecondaryKey($secondaryKey)
218
    {
219 13
        $list = array();
220
221 13
        foreach ($this->values as $primaryKey => $valuesBySecondaryKey) {
222 13
            if (isset($valuesBySecondaryKey[$secondaryKey])) {
223 13
                $list[$primaryKey] = $valuesBySecondaryKey[$secondaryKey];
224
            }
225
        }
226
227 13
        if (!$list) {
228
            throw new OutOfBoundsException(sprintf(
229
                'The key "%s" does not exist.',
230
                $secondaryKey
231
            ));
232
        }
233
234 13
        return $list;
235
    }
236
237
    /**
238
     * Returns the secondary keys for the given primary key.
239
     *
240
     * The primary key is optional. If this argument is not provided, all secondary keys will be returned.
241
     *
242
     * @param int|string|null $primaryKey The primary key.
243
     *
244
     * @return int[]|string[] The secondary keys.
245
     *
246
     * @throws OutOfBoundsException If the primary key does not exist.
247
     */
248 31
    public function getSecondaryKeys($primaryKey = null)
249
    {
250 31 View Code Duplication
        if ($primaryKey) {
251 17
            if (!isset($this->values[$primaryKey])) {
252 1
                throw new OutOfBoundsException(sprintf(
253 1
                    'The key "%s" does not exist.',
254
                    $primaryKey
255
                ));
256
            }
257
258 16
            return array_keys($this->values[$primaryKey]);
259
        }
260
261 14
        $allSecondaryKeys = array();
262
263 14
        foreach ($this->values as $primaryKey => $valuesBySecondaryKey) {
264 13
            foreach ($valuesBySecondaryKey as $secondaryKey => $values) {
265 13
                $allSecondaryKeys[$secondaryKey] = true;
266
            }
267
        }
268
269 14
        return array_keys($allSecondaryKeys);
270
    }
271
272
    /**
273
     * Returns all primary keys.
274
     *
275
     * @return int[]|string[] The primary keys.
276
     */
277 88
    public function getPrimaryKeys()
278
    {
279 88
        return array_keys($this->values);
280
    }
281
282
    /**
283
     * Returns the contents of the store as array.
284
     *
285
     * @return array[] A multi-dimensional array containing all values by
286
     *                 their primary and secondary keys.
287
     */
288 54
    public function toArray()
289
    {
290 54
        return $this->values;
291
    }
292
293
    /**
294
     * Returns whether the map is empty.
295
     *
296
     * @return bool Returns `true` if the map is empty and `false` otherwise.
297
     */
298 4
    public function isEmpty()
299
    {
300 4
        return 0 === count($this->values);
301
    }
302
303
    /**
304
     * Sorts the primary keys of the map.
305
     *
306
     * @param int[]|string[]|null $order The keys in the desired order.
307
     */
308 2
    public function sortPrimaryKeys(array $order = null)
309
    {
310 2
        if (!$order) {
311 1
            ksort($this->values);
312
313 1
            return;
314
        }
315
316 1
        $orderedKeys = array_intersect_key(array_flip($order), $this->values);
317
318 1
        $this->values = array_replace($orderedKeys, $this->values);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_replace($orderedKeys, $this->values) of type array is incompatible with the declared type array<integer,array> of property $values.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
319 1
    }
320
321
    /**
322
     * Sorts the secondary keys of a map entry.
323
     *
324
     * @param int|string          $primaryKey The primary key.
325
     * @param int[]|string[]|null $order      The keys in the desired order.
326
     */
327 3
    public function sortSecondaryKeys($primaryKey, array $order = null)
328
    {
329 3
        if (!isset($this->values[$primaryKey])) {
330 1
            throw new OutOfBoundsException(sprintf(
331 1
                'The key "%s" does not exist.',
332
                $primaryKey
333
            ));
334
        }
335
336 2
        if (!$order) {
337 1
            ksort($this->values[$primaryKey]);
338
339 1
            return;
340
        }
341
342 1
        $orderedKeys = array_intersect_key(array_flip($order), $this->values[$primaryKey]);
343
344 1
        $this->values[$primaryKey] = array_replace($orderedKeys, $this->values[$primaryKey]);
345 1
    }
346
}
347