Completed
Push — master ( 57c17f...94cf79 )
by Taha
01:19
created

XdebugToggle::handle()   C

Complexity

Conditions 10
Paths 152

Size

Total Lines 64

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 64
rs 6.5721
c 0
b 0
f 0
cc 10
nc 152
nop 0

How to fix   Long Method    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
namespace Tpaksu\XdebugToggle\Commands;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Support\Str;
7
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
8
use Symfony\Component\Console\Output\OutputInterface;
9
use Symfony\Component\Process\Process;
10
11
class XdebugToggle extends Command
12
{
13
    /**
14
     * The complete line containing "*_extension=*xdebug*"
15
     *
16
     * @var string
17
     */
18
    protected $extensionLine;
19
20
    /**
21
     * Extension active status
22
     *
23
     * @var boolean
24
     */
25
    protected $extensionStatus;
26
27
    /**
28
     * The configuration written in php.ini for XDebug
29
     *
30
     * @var array
31
     */
32
    protected $extensionSettings;
33
34
    /**
35
     * Path of the Loaded INI file
36
     *
37
     * @var string
38
     */
39
    protected $iniPath;
40
41
    /**
42
     * Debug mode active flag
43
     *
44
     * @var boolean
45
     */
46
    protected $debug;
47
48
    /**
49
     * The command signature
50
     *
51
     * @var string
52
     */
53
    protected $signature = 'xdebug {status : "on" or "off" to enable/disable XDebug}';
54
55
    /**
56
     * The command description
57
     *
58
     * @var string
59
     */
60
    protected $description = 'Enables or disables XDebug extension';
61
62
    /**
63
     * Class constructor
64
     */
65
    public function __construct()
66
    {
67
        parent::__construct();
68
        $this->debug = false;
69
    }
70
71
    /**
72
     * The method that handles the command
73
     */
74
    public function handle()
75
    {
76
        // Define custom format for bold text
77
        $style = new OutputFormatterStyle('default', 'default', array('bold'));
78
        $this->output->getFormatter()->setStyle('bold', $style);
79
80
        // Get the verbosity level to set debug mode flag
81
        $verbosityLevel = $this->getOutput()->getVerbosity();
82
        if ($verbosityLevel > OutputInterface::VERBOSITY_DEBUG) {
83
            $this->debug = true;
84
        }
85
86
        // Get XDebug desired status from the command line arguments
87
        $desiredStatusMixed = $this->argument("status") ?? "";
88
        $desiredStatusString = "";
0 ignored issues
show
Unused Code introduced by
$desiredStatusString is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
89
90
        if (is_array($desiredStatusMixed)) {
91
            $desiredStatusString = strval($desiredStatusMixed[0]);
92
        } else {
93
            $desiredStatusString = $desiredStatusMixed;
94
        }
95
96
        if ($this->debug) {
97
            echo "Desired Status: $desiredStatusString\n";
98
        }
99
100
        // validate desired XDebug status
101
        if (!in_array($desiredStatusString, ["on", "off"])) {
102
            $this->line("Status should be \"on\" or \"off\". Other values are not accepted.", "fg=red;bold");
103
            return false;
104
        }
105
106
        $desiredStatus = $desiredStatusString === "on" ? true : false;
107
108
        // Retrieve the INI path to the global variable
109
        $this->getIniPath();
110
111
        // If we can't retrieve the loaded INI path, bail out
112
        if ($this->iniPath === "") {
113
            $this->line("Can't get php.ini file path from phpinfo() output.
114
            Make sure that the function is allowed inside your php.ini configuration.", "bold");
115
            return false;
116
        }
117
118
        // Get the XDebug extension information from the INI file
119
        $this->getXDebugStatus();
120
121
        // prepare variables for comparison and output
122
        $currentStatus = $this->extensionStatus ? "on" : "off";
123
        $styledStatus = $this->extensionStatus ? "<fg=green;bold>on" : "<fg=red;bold>off";
124
125
        // print current status to the user
126
        $this->line("<fg=yellow>Current XDebug Status: $styledStatus</>");
127
128
        // if the desired status and current status are the same, we don't need to alter anything
129
        // inform the user and exit
130
        if ($currentStatus === $desiredStatusString) {
131
            $this->line("<fg=green>Already at the desired state. No action has been taken.</>");
132
            return false;
133
        }
134
135
        // we need to alter the status to the new one. Do it!
136
        $this->setXDebugStatus($desiredStatus);
137
    }
138
139
    /**
140
     * Sets the new XDebug extension status
141
     *
142
     * @param   boolean  $status  Whether the extension should be active or not
143
     *
144
     * @return  void
145
     */
146
    private function setXDebugStatus($status)
147
    {
148
        // inform the user about the current operation
149
        $this->line("<bold>Setting status to $status</bold>");
150
151
        // read the ini file
152
        $contents = file_get_contents($this->iniPath);
153
154
        if ($this->debug) {
155
            echo "status: $status\n";
156
            echo "line: " . $this->extensionLine . "\n";
157
            echo "new: " . trim($this->extensionLine, ";") . "\n";
158
        }
159
160
        // replace the "zend_extension=*xdebug.*" line with the active/passive equivalent
161
        switch ($status) {
162
            case 'on':
163
                $contents = str_replace($this->extensionLine, trim($this->extensionLine, ";"), $contents);
164
                break;
165
166
            default:
167
                $contents = str_replace($this->extensionLine, ";" . $this->extensionLine, $contents);
168
                break;
169
        }
170
171
        // rewrite the php.ini file
172
        file_put_contents($this->iniPath, $contents);
173
174
        // restart the service to put the changes in effect
175
        $this->restartServices();
176
    }
177
178
    /**
179
     * Retrieves the INI path from php.ini file
180
     *
181
     * @return void
182
     */
183
    private function getIniPath()
184
    {
185
        $this->iniPath = php_ini_loaded_file() ?? "";
186
    }
187
188
    /**
189
     * Gets the XDebug status and related configuration from the loaded php.ini file
190
     */
191
    private function getXDebugStatus()
192
    {
193
        // get the extension status
194
        $this->getExtensionStatus();
195
196
        // get extemsion settings
197
        $this->getExtensionSettings();
198
    }
199
200
    /**
201
     * Reads the extension status from PHP ini file
202
     *
203
     * @return void
204
     */
205
    private function getExtensionStatus()
206
    {
207
        // read the extension line from file,
208
        // can't use parse_ini_file here because the keyed array overwrites "extension" lines and keeps the last one
209
        $this->extensionLine = collect(file_get_contents($this->iniPath))
210
            ->explode("\n")
211
            ->filter(function ($line) {
212
                return Str::contains($line, "extension=") && Str::contains($line, "xdebug");
213
            })
214
            ->first();
215
216
        $this->extensionLine = trim($this->extensionLine ?? "");
217
218
        if ($this->debug) {
219
            echo "line: " . $this->extensionLine . "\n";
220
        }
221
222
        if (strlen($this->extensionLine) > 0) {
223
            $this->extensionStatus = $this->extensionLine[0] == ";" ? false : true;
224
        } else {
225
            $this->extensionStatus = false;
226
        }
227
228
        if ($this->debug) {
229
            echo "ext.status: " . $this->extensionStatus . "\n";
230
        }
231
    }
232
233
    /**
234
     * Reads the extension settings from PHP ini file
235
     *
236
     * @return void
237
     */
238
    private function getExtensionSettings()
239
    {
240
        $settings = collect(parse_ini_file($this->iniPath))->filter(function ($setting, $key) {
241
            return Str::startsWith($key, "xdebug.");
242
        });
243
        $this->extensionSettings = $settings->toArray();
244
    }
245
246
    /**
247
     * Restarts the services that takes the modification into effect
248
     *
249
     * @return void
250
     */
251
    private function restartServices()
252
    {
253
        /**
254
         * Define a global outputter to display command output to user
255
         *
256
         * @param   string  $type  The type of the output
257
         * @param   string  $data  The output
258
         *
259
         * @return  void
260
         */
261
        $output = function ($type, $data) {
262
            $this->info($data);
263
        };
264
        // run the command(s) needed to restart the service
265
        (new Process([env("XDEBUG_SERVICE_RESTART_COMMAND", "valet restart nginx")]))->run($output);
266
        // display the new extension status
267
        (new Process(["php --ri xdebug"]))->run($output);
268
    }
269
}
270