Passed
Pull Request — master (#11)
by Marwan
03:44 queued 01:17
created

Utility::execute()   B

Complexity

Conditions 10
Paths 33

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 10.3638

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 12
c 2
b 0
f 0
dl 0
loc 23
ccs 11
cts 13
cp 0.8462
rs 7.6666
cc 10
nc 33
nop 3
crap 10.3638

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @author Marwan Al-Soltany <[email protected]>
5
 * @copyright Marwan Al-Soltany 2020
6
 * For the full copyright and license information, please view
7
 * the LICENSE file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace MAKS\AmqpAgent\Helper;
13
14
use stdClass;
15
use Exception;
16
use ReflectionObject;
17
use DateTime;
18
use DateTimeZone;
19
20
/**
21
 * A class containing miscellaneous helper functions.
22
 * @since 1.2.0
23
 */
24
final class Utility
25
{
26
    /**
27
     * Returns a DateTime object with the right time zone.
28
     * @param string $time A valid php date/time string.
29
     * @param string|null $timezone A valid php timezone string.
30
     * @return DateTime
31
     * @throws Exception
32
     */
33 4
    public static function time(string $time = 'now', ?string $timezone = null): DateTime
34
    {
35 4
        $timezone = $timezone
36 1
            ? $timezone
37 4
            : date_default_timezone_get();
38
39 4
        $timezoneObject = $timezone
40 4
            ? new DateTimeZone($timezone)
41 4
            : null;
42
43 4
        return new DateTime($time, $timezoneObject);
44
    }
45
46
    /**
47
     * Generates a user-level notice, warning, or an error with styling.
48
     * @param array|string|null $text [optional] The text wished to be styled (when passing an array, if array key is a valid color it will style this array element value with its key).
49
     * @param string $color [optional] Case sensitive ANSI color name in this list [black, red, green, yellow, magenta, cyan, white, default] (when passing array, this parameter will be the fallback).
50
     * @param int $type [optional] Error type (E_USER family). 1024 E_USER_NOTICE, 512 E_USER_WARNING, 256 E_USER_ERROR, 16384 E_USER_DEPRECATED.
51
     * @return bool True if error type is accepted.
52
     */
53 4
    public static function emit($text = null, ?string $color = 'yellow', int $type = E_USER_NOTICE): bool
54
    {
55
        $colors = [
56 4
            'reset'   => 0,
57
            'black'   => 30,
58
            'red'     => 31,
59
            'green'   => 32,
60
            'yellow'  => 33,
61
            'blue'    => 34,
62
            'magenta' => 35,
63
            'cyan'    => 36,
64
            'white'   => 37,
65
            'default' => 39,
66
        ];
67
68
        $types = [
69 4
            E_USER_NOTICE     => E_USER_NOTICE,
70 4
            E_USER_WARNING    => E_USER_WARNING,
71 4
            E_USER_ERROR      => E_USER_ERROR,
72 4
            E_USER_DEPRECATED => E_USER_DEPRECATED,
73
        ];
74
75 4
        $cli = php_sapi_name() === 'cli' || php_sapi_name() === 'cli-server' || http_response_code() === false;
76
77 4
        $trim = ' \t\0\x0B';
78 4
        $backspace = chr(8);
79 4
        $wrapper = $cli ? "\033[%dm %s\033[0m" : "@COLOR[%d] %s";
80 4
        $color = $colors[$color] ?? 39;
81 4
        $type = $types[$type] ?? 1024;
82 4
        $message = '';
83
84 4
        if (is_array($text)) {
85 2
            foreach ($text as $segmentColor => $string) {
86 2
                $string = trim($string, $trim);
87 2
                if (is_string($segmentColor)) {
88 2
                    $segmentColor = $colors[$segmentColor] ?? $color;
89 2
                    $message .= !strlen($message)
90 2
                        ? sprintf($wrapper, $segmentColor, $backspace . $string)
91 2
                        : sprintf($wrapper, $segmentColor, $string);
92 2
                    continue;
93
                }
94 2
                $message = $message . $string;
95
            }
96 2
        } elseif (is_string($text)) {
97 1
            $string = $backspace . trim($text, $trim);
98 1
            $message = sprintf($wrapper, $color, $string);
99
        } else {
100 1
            $string = $backspace . 'From ' . __METHOD__ . ': No message was specified!';
101 1
            $message = sprintf($wrapper, $color, $string);
102
        }
103
104 4
        $message = $cli ? $message : preg_replace('/@COLOR\[\d+\]/', '', $message);
105
106 4
        return trigger_error($message, $type);
107
    }
108
109
    /**
110
     * Returns the passed key(s) from the backtrace. Note that the backtrace is reversed (last is first).
111
     * @param string|array $pluck The key to to get as a string or an array of strings (keys) from this list [file, line, function, class, type, args].
112
     * @param int $offset [optional] The offset of the backtrace (last executed is index at 0).
113
     * @return string|int|array|null A string or int if a string is passed, an array if an array is passed and null if no match was found.
114
     */
115 9
    public static function backtrace($pluck, int $offset = 0)
116
    {
117 9
        $backtrace = array_reverse(debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT));
118 9
        $plucked = null;
119
120 9
        if (count($backtrace) < $offset + 1) {
121 1
            return null;
122 8
        } elseif (is_string($pluck)) {
123 1
            $plucked = isset($backtrace[$offset][$pluck]) ? $backtrace[$offset][$pluck] : null;
124 7
        } elseif (is_array($pluck)) {
0 ignored issues
show
introduced by
The condition is_array($pluck) is always true.
Loading history...
125 7
            $plucked = [];
126 7
            foreach ($pluck as $key) {
127 7
                !isset($backtrace[$offset][$key]) ?: $plucked[$key] = $backtrace[$offset][$key];
128
            }
129
        }
130
131 8
        return is_string($plucked) || is_array($plucked) && count($plucked, COUNT_RECURSIVE) ? $plucked : null;
132
    }
133
134
    /**
135
     * Executes a CLI command in the specified path synchronously or asynchronous (cross platform).
136
     * @since 2.0.0
137
     * @param string $command The command to execute.
138
     * @param string|null $path [optional] The path where the command should be executed.
139
     * @param bool $asynchronous [optional] Whether the command should be a background process (asynchronous) or not (synchronous).
140
     * @return string|null The command result (as a string if possible) if synchronous otherwise null.
141
     * @throws Exception
142
     */
143 6
    public static function execute(string $command, string $path = null, bool $asynchronous = false): ?string
144
    {
145 6
        if (!strlen($command)) {
146 1
            throw new Exception('No valid command is specified!');
147
        }
148
149 5
        $isWindows = PHP_OS == 'WINNT' || substr(php_uname(), 0, 7) == 'Windows';
150 5
        $apWrapper = $isWindows ? 'start /B %s > NUL' : '/usr/bin/nohup %s >/dev/null 2>&1 &';
151
152 5
        if ($path && strlen($path) && getcwd() !== $path) {
153 5
            chdir(realpath($path));
154
        }
155
156 5
        if ($asynchronous) {
157 5
            $command = sprintf($apWrapper, $command);
158
        }
159
160 5
        if ($isWindows && $asynchronous) {
161
            pclose(popen($command, 'r'));
162
            return null;
163
        }
164
165 5
        return shell_exec($command);
166
    }
167
}
168