Completed
Push — master ( a4261d...fc5e52 )
by John
14s
created

InstallerBase   C

Complexity

Total Complexity 56

Size/Duplication

Total Lines 231
Duplicated Lines 0 %

Importance

Changes 12
Bugs 0 Features 6
Metric Value
eloc 144
c 12
b 0
f 6
dl 0
loc 231
rs 5.5199
wmc 56

7 Methods

Rating   Name   Duplication   Size   Complexity  
F _install() 0 129 30
A applyIcon() 0 10 2
A _uninstall() 0 7 2
B commitCompiler() 0 36 9
A __construct() 0 4 1
A applyCustom() 0 10 3
B delFile() 0 14 9

How to fix   Complexity   

Complex Class

Complex classes like InstallerBase often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use InstallerBase, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace App\Babel\Install;
4
5
use App\Models\OJModel;
6
use App\Models\CompilerModel;
7
use PharIo\Version\Version;
8
use PharIo\Version\VersionConstraintParser;
9
use PharIo\Version\InvalidVersionException;
10
use Illuminate\Support\Facades\DB;
11
use Exception;
12
13
class InstallerBase
14
{
15
    protected $command;
16
    protected $versionParser;
17
    protected $oid=0;
18
19
    protected function _install($ocode)
20
    {
21
        $this->command->line("Installing <fg=green>$ocode</>");
22
23
        $babelConfig=json_decode(file_get_contents(babel_path("Extension/$ocode/babel.json")),true);
24
25
        // support __cur__ variables
26
        if($babelConfig["version"]=="__cur__") $babelConfig["version"]=explode("-",version())[0];
27
        if($babelConfig["require"]["NOJ"]=="__cur__") $babelConfig["require"]["NOJ"]=explode("-",version())[0];
28
29
        // check version info
30
        if(!isset($babelConfig["version"]) || is_null($babelConfig["version"]) || trim($babelConfig["version"])==""){
31
            $this->command->line("\n  <bg=red;fg=white> Lack version info, aborting. </>\n");
32
            return;
33
        }
34
35
        // check require info
36
        if(!isset($babelConfig["require"]["NOJ"]) || is_null($babelConfig["require"]["NOJ"]) || trim($babelConfig["require"]["NOJ"])==""){
37
            $this->command->line("\n  <bg=red;fg=white> Lack NOJ compability info, aborting. </>\n");
38
            return;
39
        }
40
41
        // check requirement
42
        try {
43
            if(!($this->versionParser->parse($babelConfig["require"]["NOJ"])->complies(new Version(explode("-",version())[0])))){
44
                if(!$this->command->option('ignore-platform-reqs')){
45
                    $this->command->line("Your Current NOJ Version <fg=yellow>".version()."</> doesn't support the following extension: ");
46
                    $this->command->line("  - <fg=green>$ocode</> requires NOJ version <fg=yellow>{$babelConfig['require']['NOJ']}</>");
47
                    return;
48
                }
49
            }
50
        } catch(InvalidVersionException $e) {
51
            $this->command->line("\n  <bg=red;fg=white> Illegal Compability Info, aborting. </>\n");
52
            return;
53
        }
54
55
        DB::beginTransaction();
56
57
        // get current installed version info
58
        $info=OJModel::basic(OJModel::oid($ocode));
59
60
        // if there isn't, create one
61
        if(empty($info)){
62
            $this->oid=OJModel::insertOJ([
63
                "ocode"=>$babelConfig["code"],
64
                "name"=>$babelConfig["name"],
65
                "home_page"=>$babelConfig["website"],
66
                "logo"=>"/static/img/oj/default.png",
67
                "status"=>1,
68
                "version"=>"",
69
                "compiler_timestamp"=>"",
70
            ]);
71
        } else {
72
            // check legal version format
73
            try {
74
                $currentVersion=new Version($babelConfig["version"]);
75
            } catch(InvalidVersionException $e) {
76
                DB::rollback();
77
                $this->command->line("\n  <bg=red;fg=white> Illegal Version Info, aborting. </>\n");
78
                return;
79
            }
80
81
            // check there is a not null version
82
            if(isset($info["version"]) && !is_null($info["version"]) && trim($info["version"])!=""){
83
                try {
84
                    $installedVersion=new Version($info["version"]);
85
                } catch(InvalidVersionException $e) {
86
                    DB::rollback();
87
                    $this->command->line("\n  <bg=red;fg=white> Illegal Version Info, aborting. </>\n");
88
                    return;
89
                }
90
91
                if (!($currentVersion->isGreaterThan($installedVersion))) {
92
                    // lower version or even
93
                    DB::rollback();
94
                    $this->command->line("Nothing to install or update");
95
                    return;
96
                }
97
            }
98
99
            $this->oid=$info["oid"];
100
        }
101
102
        // retrieve compiler config and then import it
103
        $installed_timestamp=0;
104
        if(isset($info["compiler_timestamp"]) && !is_null($info["compiler_timestamp"]) && trim($info["compiler_timestamp"])!=""){
105
            $installed_timestamp=intval($info["compiler_timestamp"]);
106
        }
107
        $ConpilerConfig = glob(babel_path("Extension/$ocode/compiler/*.*"));
108
        foreach($ConpilerConfig as $file) {
109
            if(intval(basename($file)) > $installed_timestamp) {
110
                try {
111
                    $this->commitCompiler($file,json_decode(file_get_contents($file), true));
112
                } catch (Exception $e) {
113
                    DB::rollback();
114
                    $this->command->line("<fg=red>Error:     ".$e->getMessage()."</>");
115
                    $this->command->line("\n  <bg=red;fg=white> Compiler info import failure, aborting. </>\n");
116
                    return;
117
                }
118
            }
119
        }
120
121
        // import css
122
        try {
123
            if (isset($babelConfig["custom"]["css"]) && !is_null($babelConfig["custom"]["css"]) && trim($babelConfig["custom"]["css"])!="") {
124
                $cssPath=babel_path("Extension/$ocode/".$babelConfig["custom"]["css"]);
125
            }else{
126
                $cssPath=null;
127
            }
128
            $this->applyCustom($ocode, $cssPath);
129
        }catch(Exception $e){
130
            DB::rollback();
131
            $this->command->line("\n  <bg=red;fg=white> Unable to add an custom css for this extension, aborting. </>\n");
132
            return;
133
        }
134
135
136
        // import icon
137
        try{
138
            $imgPath=babel_path("Extension/$ocode/".$babelConfig["icon"]);
139
            $storePath=$this->applyIcon($ocode, $imgPath);
140
            OJModel::updateOJ($this->oid,["logo"=>$storePath]);
141
        }catch(Exception $e){
142
            DB::rollback();
143
            $this->command->line("\n  <bg=red;fg=white> Unable to add an icon for this extension, aborting. </>\n");
144
            return;
145
        }
146
147
        DB::commit();
148
    }
149
150
    protected function _uninstall($ocode)
151
    {
152
        $this->command->line("<fg=red>Warning: Removing an installed and already-used extension may cause severe consequences, including lossing user submission, problem data and contests regaring or involving the usage of this extension. </>");
153
        if ($this->command->confirm("Are you sure you want to uninstall $ocode?")){
154
            //uninstall
155
            OJModel::removeOJ(["ocode"=>$ocode]);
156
            $this->command->line("Already removed <fg=green>$ocode</>");
157
        }
158
    }
159
160
    public function __construct($class)
161
    {
162
        $this->command=$class;
163
        $this->versionParser = new VersionConstraintParser();
164
    }
165
166
167
    protected function commitCompiler($path,$json)
168
    {
169
        $this->command->line("<fg=yellow>Migrating: </>$path");
170
        $modifications=$json["modifications"];
171
        foreach($modifications as $m){
172
            if($m["method"]=="add"){
173
                CompilerModel::add([
174
                    "oid"=>$this->oid,
175
                    "comp"=>$m["compability"],
176
                    "lang"=>$m["language"],
177
                    "lcode"=>$m["code"],
178
                    "icon"=>$m["icon"],
179
                    "display_name"=>$m["display"],
180
                    "available"=>1,
181
                    "deleted"=>0
182
                ]);
183
            }elseif($m["method"]=="modify"){
184
                $modifyItem=[];
185
                if(isset($m["compability"])) $modifyItem["comp"]=$m["compability"];
186
                if(isset($m["language"])) $modifyItem["lang"]=$m["language"];
187
                if(isset($m["icon"])) $modifyItem["icon"]=$m["icon"];
188
                if(isset($m["display"])) $modifyItem["display_name"]=$m["display"];
189
                CompilerModel::modify([
190
                    "oid"=>$this->oid,
191
                    "lcode"=>$m["code"],
192
                ], $modifyItem);
193
            }elseif($m["method"]=="remove"){
194
                CompilerModel::remove([
195
                    "oid"=>$this->oid,
196
                    "lcode"=>$m["code"],
197
                ]);
198
            }else{
199
                continue;
200
            }
201
        }
202
        $this->command->line("<fg=green>Migrated:  </>$path");
203
    }
204
205
    protected function applyIcon($ocode, $imgPath)
206
    {
207
        $storePath=base_path("public/static/img/oj/$ocode/");
208
        if(is_dir($storePath)) {
209
            $this->delFile($storePath);
210
        }else{
211
            mkdir($storePath);
212
        }
213
        file_put_contents($storePath.basename($imgPath),file_get_contents($imgPath));
214
        return "/static/img/oj/$ocode/".basename($imgPath);
215
    }
216
217
    protected function applyCustom($ocode, $cssPath)
218
    {
219
        $storePath=base_path("public/static/css/oj/");
220
        if(!is_dir($storePath)) {
221
            mkdir($storePath);
222
        }
223
        if (is_null($cssPath)) {
224
            file_put_contents($storePath."$ocode.css", "\/*Silence is Golden*\/");
225
        }else {
226
            file_put_contents($storePath."$ocode.css", file_get_contents($cssPath));
227
        }
228
    }
229
230
    private function delFile($dirName){
231
        if(file_exists($dirName) && $handle=opendir($dirName)){
232
            while(false!==($item = readdir($handle))){
233
                if($item!= "." && $item != ".."){
234
                    if(file_exists($dirName.'/'.$item) && is_dir($dirName.'/'.$item)){
235
                        delFile($dirName.'/'.$item);
0 ignored issues
show
Bug introduced by
The function delFile was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

235
                        /** @scrutinizer ignore-call */ 
236
                        delFile($dirName.'/'.$item);
Loading history...
236
                    }else{
237
                        if(unlink($dirName.'/'.$item)){
238
                            return true;
239
                        }
240
                    }
241
                }
242
            }
243
            closedir( $handle);
244
        }
245
    }
246
}
247