Completed
Push — master ( 72206a...a05009 )
by Michael
11:12
created

UpgradeControl::oneButtonContinueForm()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 2
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
class UpgradeControl
4
{
5
    /** @var PatchStatus[] */
6
    public $upgradeQueue = array();
7
8
    /** @var string[] */
9
    public $needWriteFiles = array();
10
11
    /** @var bool  */
12
    public $needUpgrade = false;
13
14
    /**
15
     * @var array support sites pulled from language files -- support.php
16
     */
17
    public $supportSites = array();
18
19
    /**
20
     * @var string language being used in the upgrade process
21
     */
22
    public $upgradeLanguage;
23
24
    /**
25
     * get a list of directories inside a directory
26
     *
27
     * @param string $dirname directory to search
28
     *
29
     * @return string[]
30
     */
31
    public function getDirList($dirname)
32
    {
33
        $dirlist = array();
34
        if (is_dir($dirname) && $handle = opendir($dirname)) {
35
            while (false !== ($file = readdir($handle))) {
36
                if (substr($file, 0, 1) !== '.' && strtolower($file) !== 'cvs') {
37
                    if (is_dir("{$dirname}/{$file}")) {
38
                        $dirlist[] = $file;
39
                    }
40
                }
41
            }
42
            closedir($handle);
43
            asort($dirlist);
44
            reset($dirlist);
45
        }
46
47
        return $dirlist;
48
    }
49
50
    /**
51
     * @return string[]
52
     */
53
    public function availableLanguages()
54
    {
55
        $languages = $this->getDirList('./language/');
56
        return $languages;
57
    }
58
59
60
    public function loadLanguage($domain, $language = null)
61
    {
62
        $supports = null;
63
64
        $language = (null === $language) ? $this->upgradeLanguage : $language;
65
66
        if (file_exists("./language/{$language}/{$domain}.php")) {
67
            include_once "./language/{$language}/{$domain}.php";
68
        } elseif (file_exists("./language/english/{$domain}.php")) {
69
            include_once "./language/english/{$domain}.php";
70
        }
71
72
        if (null !== $supports) {
73
            $this->supportSites = array_merge($this->supportSites, $supports);
74
        }
75
    }
76
77
    /**
78
     * Determine the language to use.
79
     *  - Xoops configuration
80
     *  - stored cookie
81
     *  - lang parameter passed to script
82
     * Save the result in a cookie
83
     *
84
     * @return string the language to use in the upgrade process
85
     */
86
    public function determineLanguage()
87
    {
88
        global $xoopsConfig;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
89
90
        $upgrade_language = null;
91
        if (isset($xoopsConfig['language'])) {
92
            $upgrade_language = $xoopsConfig['language'];
93
        }
94
        $upgrade_language = !empty($_COOKIE['xo_upgrade_lang']) ? $_COOKIE['xo_install_lang'] : $upgrade_language;
95
        $upgrade_language = Xmf\Request::getString('lang', $upgrade_language);
96
        $upgrade_language = (null === $xoopsConfig['language']) ? 'english' : $upgrade_language;
97
        setcookie('xo_upgrade_lang', $upgrade_language, null, null, null);
98
99
        $this->upgradeLanguage = $upgrade_language;
100
        $this->loadLanguage('upgrade');
101
102
        return $this->upgradeLanguage;
103
    }
104
105
    /**
106
     * Examine upgrade directories and determine:
107
     *  - which tasks need to run
108
     *  - which files need to be writable
109
     *
110
     * @return bool true of upgrade is needed
111
     */
112
    public function buildUpgradeQueue()
113
    {
114
        $dirs = $this->getDirList('.');
115
116
        /** @var PatchStatus[] $results */
117
        $results     = array();
118
        $files       = array();
119
        $this->needUpgrade = false;
120
121
        foreach ($dirs as $dir) {
122
            if (strpos($dir, '-to-')) {
123
                $upgrader = include_once "{$dir}/index.php";
124
                if (is_object($upgrader)) {
125
                    $results[$dir] = $upgrader->isApplied();
126
                    if (!($results[$dir]->applied)) {
127
                        $this->needUpgrade = true;
128
                        if (!empty($results[$dir]->files)) {
129
                            $files = array_merge($files, $upgrader->usedFiles);
130
                        }
131
                    }
132
                }
133
            }
134
        }
135
136
        if ($this->needUpgrade && !empty($files)) {
137
            foreach ($files as $k => $file) {
138
                if (is_writable("../{$file}")) {
139
                    unset($files[$k]);
140
                }
141
            }
142
        }
143
144
        $this->upgradeQueue = $results;
0 ignored issues
show
Documentation Bug introduced by
It seems like $results of type array is incompatible with the declared type array<integer,object<PatchStatus>> of property $upgradeQueue.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
145
        $this->needWriteFiles = $files;
146
147
        return $this->needUpgrade;
148
    }
149
150
    /**
151
     * Get count of patch sets that need to be applied.
152
     *
153
     * @return int count of patch sets to apply
154
     */
155
    public function countUpgradeQueue()
156
    {
157
        if (empty($this->upgradeQueue)) {
158
            $this->buildUpgradeQueue();
159
        }
160
        $count = 0;
161
        foreach ($this->upgradeQueue as $patch) {
162
            $count += ($patch->applied) ? 0 : 1;
163
        }
164
        return $count;
165
    }
166
167
    /**
168
     * @return string next unapplied patch directory
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
169
     */
170
    public function getNextPatch()
171
    {
172
        if (empty($this->upgradeQueue)) {
173
            $this->buildUpgradeQueue();
174
        }
175
        $next = false;
176
177
        foreach ($this->upgradeQueue as $directory => $patch) {
178
            if (!$patch->applied) {
179
                $next =  $directory;
180
                break;
181
            }
182
        }
183
        return $next;
184
    }
185
186
    /**
187
     * Return form consisting of a single button.
188
     *
189
     * @param string     $action     URL for form action
190
     * @param array|null $parameters array of parameters
191
     *
192
     * @return string
193
     */
194
    public function oneButtonContinueForm($action = 'index.php', $parameters = array('action' =>'next'))
195
    {
196
        $form  = '<form action="' . $action . '" method="post">';
197
        $form .= '<button class="btn btn-lg btn-success" type="submit">' . _CONTINUE;
198
        $form .= '  <span class="fa fa-caret-right"></span></button>';
199
        foreach ($parameters as $name => $value) {
0 ignored issues
show
Bug introduced by
The expression $parameters of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
200
            $form .= '<input type="hidden" name="' . $name . '" value="' . $value . '">';
201
        }
202
        $form .= '</form>';
203
204
        return $form;
205
    }
206
}
207