Passed
Pull Request — master (#355)
by Hugo
04:14
created

find()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 3
nop 2
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Digia\GraphQL\Util;
4
5
use Digia\GraphQL\Error\InvariantException;
6
use Digia\GraphQL\Language\Node\NodeInterface;
7
use Digia\GraphQL\Type\Definition\TypeInterface;
8
use React\Promise\PromiseInterface;
9
use function Digia\GraphQL\printNode;
10
11
/**
12
 * @param bool   $condition
13
 * @param string $message
14
 * @throws InvariantException
15
 */
16
function invariant(bool $condition, string $message)
17
{
18
    if (!$condition) {
19
        throw new InvariantException($message);
20
    }
21
}
22
23
/**
24
 * Given `[A, B, C]` returns `'A, B or C'`.
25
 *
26
 * @param array $items
27
 * @return string
28
 */
29
function orList(array $items): string
30
{
31
    static $MAX_LENGTH = 5;
32
33
    $selected = \array_slice($items, 0, $MAX_LENGTH);
34
    $count    = \count($selected);
35
    $index    = 0;
36
37
    return $count === 1
38
        ? $selected[0]
39
        : \array_reduce($selected, function ($list, $item) use ($count, &$index) {
40
            $list .= ($index > 0 && $index < ($count - 1) ? ', ' : '') . ($index === ($count - 1) ? ' or ' : '') .
41
                $item;
42
            $index++;
43
            return $list;
44
        }, '');
45
}
46
47
/**
48
 * Given an invalid input string and a list of valid options, returns a filtered
49
 * list of valid options sorted based on their similarity with the input.
50
 *
51
 * @param string $input
52
 * @param array  $options
53
 * @return array
54
 */
55
function suggestionList(string $input, array $options): array
56
{
57
    $optionsByDistance = [];
58
    $oLength           = \count($options);
59
    $inputThreshold    = \strlen($input) / 2;
60
61
    /** @noinspection ForeachInvariantsInspection */
62
    for ($i = 0; $i < $oLength; $i++) {
63
        // Comparison must be case-insensitive.
64
        $distance  = \levenshtein(\strtolower($input), \strtolower($options[$i]));
65
        $threshold = \max($inputThreshold, \strlen($options[$i]) / 2, 1);
66
        if ($distance <= $threshold) {
67
            $optionsByDistance[$options[$i]] = $distance;
68
        }
69
    }
70
71
    $result = \array_keys($optionsByDistance);
72
73
    \usort($result, function ($a, $b) use ($optionsByDistance) {
74
        return $optionsByDistance[$a] - $optionsByDistance[$b];
75
    });
76
77
    return $result;
78
}
79
80
/**
81
 * Given `[A, B, C]` returns `'"A", "B" or "C"'`.
82
 *
83
 * @param array $items
84
 * @return string
85
 */
86
function quotedOrList(array $items): string
87
{
88
    return orList(\array_map(function ($item) {
89
        return '"' . $item . '"';
90
    }, $items));
91
}
92
93
94
/**
95
 * @param array    $array
96
 * @param callable $fn
97
 * @return bool
98
 */
99
function arrayEvery(array $array, callable $fn): bool
100
{
101
    return \array_reduce($array, function ($result, $value) use ($fn) {
102
        return $result && $fn($value);
103
    }, true);
104
}
105
106
/**
107
 * @param array    $array
108
 * @param callable $fn
109
 * @return mixed
110
 */
111
function arraySome(array $array, callable $fn)
112
{
113
    return \array_reduce($array, function ($result, $value) use ($fn) {
114
        return $result || $fn($value);
115
    });
116
}
117
118
/**
119
 * @param array    $array
120
 * @param callable $predicate
121
 * @return mixed|null
122
 */
123
function find(array $array, callable $predicate)
124
{
125
    foreach ($array as $value) {
126
        if ($predicate($value)) {
127
            return $value;
128
        }
129
    }
130
131
    return null;
132
}
133
134
/**
135
 * @param array    $array
136
 * @param callable $keyFn
137
 * @return array
138
 */
139
function keyMap(array $array, callable $keyFn): array
140
{
141
    return \array_reduce($array, function ($map, $item) use ($keyFn) {
142
        $map[$keyFn($item)] = $item;
143
        return $map;
144
    }, []);
145
}
146
147
/**
148
 * @param array    $array
149
 * @param callable $keyFn
150
 * @param callable $valFn
151
 * @return array
152
 */
153
function keyValueMap(array $array, callable $keyFn, callable $valFn): array
154
{
155
    return \array_reduce($array, function ($map, $item) use ($keyFn, $valFn) {
156
        $map[$keyFn($item)] = $valFn($item);
157
        return $map;
158
    }, []);
159
}
160
161
/**
162
 * @param array $map
163
 * @return PromiseInterface
164
 */
165
function promiseForMap(array $map): PromiseInterface
166
{
167
    $keys             = \array_keys($map);
168
    $promisesOrValues = \array_map(function ($name) use ($map) {
169
        return $map[$name];
170
    }, $keys);
171
172
    return \React\Promise\all($promisesOrValues)->then(function ($values) use ($keys) {
173
        $i = 0;
174
        return \array_reduce($values, function ($resolvedObject, $value) use ($keys, &$i) {
175
            $resolvedObject[$keys[$i++]] = $value;
176
            return $resolvedObject;
177
        }, []);
178
    });
179
}
180
181
/**
182
 * @param array    $values
183
 * @param callable $fn
184
 * @param mixed    $initial
185
 * @return mixed
186
 */
187
function promiseReduce(array $values, callable $fn, $initial = null)
188
{
189
    return \array_reduce($values, function ($previous, $value) use ($fn) {
190
        return $previous instanceof PromiseInterface
191
            ? $previous->then(function ($resolvedValue) use ($fn, $value) {
192
                return $fn($resolvedValue, $value);
193
            })
194
            : $fn($previous, $value);
195
    }, $initial);
196
}
197
198
/**
199
 * @param mixed $value
200
 * @return string
201
 */
202
function toString($value): string
203
{
204
    if ($value instanceof TypeInterface) {
205
        return (string)$value;
206
    }
207
    if ($value instanceof NodeInterface) {
208
        return printNode($value);
209
    }
210
    if (\is_object($value)) {
211
        return 'Object';
212
    }
213
    if (\is_array($value)) {
214
        return 'Array';
215
    }
216
    if (\is_callable($value)) {
217
        return 'Function';
218
    }
219
    if ($value === '') {
220
        return '(empty string)';
221
    }
222
    if ($value === null) {
223
        return 'null';
224
    }
225
    if ($value === true) {
226
        return 'true';
227
    }
228
    if ($value === false) {
229
        return 'false';
230
    }
231
    if (\is_string($value)) {
232
        return "\"{$value}\"";
233
    }
234
    if (\is_scalar($value)) {
235
        return (string)$value;
236
    }
237
    return \gettype($value);
238
}
239