Completed
Pull Request — master (#57)
by
unknown
01:26
created

Util::raiseException()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 4
1
<?php
2
3
namespace TraderInteractive;
4
5
use ErrorException;
6
use Exception;
7
use InvalidArgumentException;
8
use ReflectionClass;
9
use ReflectionException;
10
11
/**
12
 * Static class with various application functions.
13
 */
14
final class Util
15
{
16
    private static $exceptionAliases = ['http' => '\DominionEnterprises\HttpException'];
17
18
    /**
19
     * Returns exception info in array.
20
     *
21
     * @param Exception $e the exception to return info on
22
     *
23
     * @return array like:
24
     * <pre>
25
     * [
26
     *     'type' => 'Exception',
27
     *     'message' => 'a message',
28
     *     'code' => 0,
29
     *     'file' => '/somePath',
30
     *     'line' => 434,
31
     *     'trace' => 'a stack trace',
32
     * ]
33
     * </pre>
34
     */
35
    public static function getExceptionInfo(Exception $e) : array
36
    {
37
        return [
38
            'type' => get_class($e),
39
            'message' => $e->getMessage(),
40
            'code' => $e->getCode(),
41
            'file' => $e->getFile(),
42
            'line' => $e->getLine(),
43
            'trace' => $e->getTraceAsString(),
44
        ];
45
    }
46
47
    /**
48
     * Ensures that $valueToEnsure is equal to $valueToCheck or it throws
49
     *
50
     * Can be used like: $result = ensure(true, is_string('boo'))
51
     * Or like: $result = ensure(true, is_string('boo'), 'the message')
52
     * Or like: $result = ensure(true, is_string('boo'), 'MyException', ['the message', 2])
53
     * Or like: $result = ensure(true, is_string('boo'), new MyException('the message', 2))
54
     *
55
     * @param mixed                 $valueToEnsure the value to throw on if $valueToCheck equals it
56
     * @param mixed                 $valueToCheck  the value to check against $valueToEnsure
57
     * @param null|string|Exception $exception     null, a fully qualified exception class name, string for an Exception
58
     *                                             message, or an Exception.  The fully qualified exception class name
59
     *                                             could also be an alias in getExceptionAliases()
60
     * @param array|null            $exceptionArgs arguments to pass to a new instance of $exception. If using this
61
     *                                             parameter make sure these arguments match the constructor for an
62
     *                                             exception of type $exception.
63
     *
64
     * @return mixed returns $valueToCheck
65
     *
66
     * @throws Exception if $valueToEnsure !== $valueToCheck
67
     * @throws InvalidArgumentException if $exception was not null, a string, or an Exception
68
     */
69 View Code Duplication
    public static function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
70
    {
71
        if ($valueToEnsure !== $valueToCheck) {
72
            throw self::buildException(
73
                $exception ?: "'{$valueToEnsure}' did not equal '{$valueToCheck}'",
74
                $exceptionArgs
75
            );
76
        }
77
78
        return $valueToCheck;
79
    }
80
81
    /**
82
     * Ensures that $valueToThrowOn is not equal to $valueToCheck or it throws
83
     *
84
     * Can be used like: $curl = ensureNot(false, curl_init('boo'))
85
     * Or like: $curl = ensureNot(false, curl_init('boo'), 'bad message')
86
     * Or like: $curl = ensureNot(false, curl_init('boo'), 'MyException', ['bad message', 2])
87
     * Or like: $curl = ensureNot(false, curl_init('boo'), new MyException('bad message', 2))
88
     *
89
     * @param mixed                 $valueToThrowOn the value to throw on if $valueToCheck equals it
90
     * @param mixed                 $valueToCheck   the value to check against $valueToThrowOn
91
     * @param null|string|Exception $exception      null, a fully qualified exception class name, string for an
92
     *                                              Exception message, or an Exception.  The fully qualified exception
93
     *                                              class name could also be an alias in getExceptionAliases()
94
     * @param array|null            $exceptionArgs  arguments to pass to a new instance of $exception. If using this
95
     *                                              parameter make sure these arguments match the constructor for an
96
     *                                              exception of type $exception.
97
     *
98
     * @return mixed returns $valueToCheck
99
     *
100
     * @throws Exception if $valueToThrowOn === $valueToCheck
101
     * @throws InvalidArgumentException if $exception was not null, a string, or an Exception
102
     */
103 View Code Duplication
    public static function ensureNot($valueToThrowOn, $valueToCheck, $exception = null, array $exceptionArgs = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
104
    {
105
        if ($valueToThrowOn === $valueToCheck) {
106
            throw self::buildException($exception ?: "'{$valueToThrowOn}' equals '{$valueToCheck}'", $exceptionArgs);
107
        }
108
109
        return $valueToCheck;
110
    }
111
112
    /**
113
     * Helper method to return exception created from ensure[Not] call input.
114
     *
115
     * @param mixed      $exception     Null, a fully qualified exception class name, string for an Exception message,
116
     *                                  or an Exception.  The fully qualified exception class name could also be an
117
     *                                  alias in getExceptionAliases()
118
     * @param array|null $exceptionArgs Arguments to pass to a new instance of $exception. If using this parameter make
119
     *                                  sure these arguments match the constructor for an exception of type $exception.
120
     *
121
     * @return Exception|mixed|object
122
     * @throws ReflectionException
123
     */
124
    private static function buildException($exception, array $exceptionArgs = null)
125
    {
126
        if ($exception instanceof Exception) {
127
            return $exception;
128
        }
129
130
        if (!is_string($exception)) {
131
            throw new InvalidArgumentException('$exception was not null, a string, or an Exception');
132
        }
133
134
        if (empty($exceptionArgs)) {
135
            return new Exception($exception);
136
        }
137
138
        if (array_key_exists($exception, self::$exceptionAliases)) {
139
            $exception = self::$exceptionAliases[$exception];
140
        }
141
142
        return (new ReflectionClass($exception))->newInstanceArgs($exceptionArgs);
143
    }
144
145
    /**
146
     * Throws a new ErrorException based on the error information provided. To be
147
     * used as a callback for @see set_error_handler()
148
     *
149
     * @param int    $level   The level of the exception.
150
     * @param string $message The message the exception will give.
151
     * @param string $file    The file that the error occurred in.
152
     * @param string $line    The line that the exception occurred upon.
153
     *
154
     * @return bool false
155
     *
156
     * @throws ErrorException
157
     */
158
    public static function raiseException(int $level, string $message, string $file = null, string $line = null) : bool
159
    {
160
        if (error_reporting() === 0) {
161
            return false;
162
        }
163
164
        throw new ErrorException($message, 0, $level, $file, $line);
165
    }
166
167
    /**
168
     * Throws an exception if specified variables are not of given types.
169
     *
170
     * @param array $typesToVariables like ['string' => [$var1, $var2], 'int' => [$var1, $var2]] or
171
     *                                ['string' => $var1, 'integer' => [1, $var2]]. Supported types are the suffixes
172
     *                                of the is_* functions such as string for is_string and int for is_int
173
     * @param bool  $failOnWhitespace whether to fail strings if they are whitespace
174
     * @param bool  $allowNulls       whether to allow null values to pass through
175
     *
176
     * @return void
177
     *
178
     * @throws InvalidArgumentException if a key in $typesToVariables was not a string
179
     * @throws InvalidArgumentException if a key in $typesToVariables did not have an is_ function
180
     * @throws InvalidArgumentException if a variable is not of correct type
181
     * @throws InvalidArgumentException if a variable is whitespace and $failOnWhitespace is set
182
     */
183
    public static function throwIfNotType(
184
        array $typesToVariables,
185
        bool $failOnWhitespace = false,
186
        bool $allowNulls = false
187
    ) {
188
        foreach ($typesToVariables as $type => $variablesOrVariable) {
189
            self::handleTypesToVariables($failOnWhitespace, $allowNulls, $variablesOrVariable, $type);
190
        }
191
    }
192
193
    /**
194
     * Return the exception aliases.
195
     *
196
     * @return array array where keys are aliases and values are strings to a fully qualified exception class names.
197
     */
198
    public static function getExceptionAliases() : array
199
    {
200
        return self::$exceptionAliases;
201
    }
202
203
    /**
204
     * Set the exception aliases.
205
     *
206
     * @param array $aliases array where keys are aliases and values are strings to a fully qualified exception class
207
     *                       names.
208
     */
209
    public static function setExceptionAliases(array $aliases)
210
    {
211
        self::$exceptionAliases = $aliases;
212
    }
213
214
    private static function handleBoolCase(bool $allowNulls, array $variables)
215
    {
216
        foreach ($variables as $i => $variable) {
217
            //using the continue here not negative checks to make use of short cutting optimization.
218
            if ($variable === false || $variable === true || ($allowNulls && $variable === null)) {
219
                continue;
220
            }
221
222
            throw new InvalidArgumentException("variable at position '{$i}' was not a boolean");
223
        }
224
    }
225
226
    private static function handleNullCase(array $variables)
227
    {
228
        foreach ($variables as $i => $variable) {
229
            if ($variable !== null) {
230
                throw new InvalidArgumentException("variable at position '{$i}' was not null");
231
            }
232
        }
233
    }
234
235
    private static function handleStringCase(bool $failOnWhitespace, bool $allowNulls, array $variables, string $type)
236
    {
237
        foreach ($variables as $i => $variable) {
238
            if (is_string($variable)) {
239
                if ($failOnWhitespace && trim($variable) === '') {
240
                    throw new InvalidArgumentException("variable at position '{$i}' was whitespace");
241
                }
242
243
                continue;
244
            }
245
246
            if ($allowNulls && $variable === null) {
247
                continue;
248
            }
249
250
            throw new InvalidArgumentException("variable at position '{$i}' was not a '{$type}'");
251
        }
252
    }
253
254
    private static function handleDefaultCase(bool $allowNulls, string $type, array $variables)
255
    {
256
        $isFunction = "is_{$type}";
257
        foreach ($variables as $i => $variable) {
258
            if ($isFunction($variable) || ($allowNulls && $variable === null)) {
259
                continue;
260
            }
261
262
            throw new InvalidArgumentException("variable at position '{$i}' was not a '{$type}'");
263
        }
264
    }
265
266
    private static function handleTypesToVariables(
267
        bool $failOnWhitespace,
268
        bool $allowNulls,
269
        $variablesOrVariable,
270
        $type
271
    ) {
272
        $variables = [$variablesOrVariable];
273
        if (is_array($variablesOrVariable)) {
274
            $variables = $variablesOrVariable;
275
        }
276
277
        //cast ok since an integer won't match any of the cases.
278
        //the similar code in the cases is an optimization for those type where faster checks can be made.
279
        $typeString = (string)$type;
280
        if ($typeString === 'bool') {
281
            self::handleBoolCase($allowNulls, $variables);
282
            return;
283
        }
284
285
        if ($typeString === 'null') {
286
            self::handleNullCase($variables);
287
            return;
288
        }
289
290
        if ($typeString === 'string') {
291
            self::handleStringCase($failOnWhitespace, $allowNulls, $variables, $type);
292
            return;
293
        }
294
295
        $defaults = [
296
            'array',
297
            'callable',
298
            'double',
299
            'float',
300
            'int',
301
            'integer',
302
            'long',
303
            'numeric',
304
            'object',
305
            'real',
306
            'resource',
307
            'scalar',
308
        ];
309
        if (in_array($typeString, $defaults)) {
310
            self::handleDefaultCase($allowNulls, $type, $variables);
311
            return;
312
        }
313
314
        throw new InvalidArgumentException('a type was not one of the is_ functions');
315
    }
316
}
317