GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — integration ( 45cc9f...98bc42 )
by Brendan
05:52
created

DynamicXMLDatasource::execute()   F

Complexity

Conditions 32
Paths 784

Size

Total Lines 187
Code Lines 104

Duplication

Lines 14
Ratio 7.49 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 32
eloc 104
nc 784
nop 1
dl 14
loc 187
rs 2.1166
c 1
b 0
f 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
/**
4
 * @package data-sources
5
 */
6
/**
7
 * The `DynamicXMLDatasource` allows a user to retrieve XML from an URL.
8
 * This datasource supports namespaces, partial results using XPath and
9
 * caching the result for a number of minutes.
10
 *
11
 * @since Symphony 2.3
12
 *
13
 * @deprecated As of Symphony 2.6.0 this class is deprecated. Please
14
 * use the Remote Datasource extensions since it provides more features and
15
 * is more robust. It should be completely removed in Symphony 3.
16
 *
17
 */
18
19
require_once TOOLKIT . '/class.gateway.php';
20
require_once TOOLKIT . '/class.xsltprocess.php';
21
require_once CORE . '/class.cacheable.php';
22
23
class DynamicXMLDatasource extends Datasource
24
{
25
    public function execute(array &$param_pool = null)
26
    {
27
        $result = new XMLElement($this->dsParamROOTELEMENT);
0 ignored issues
show
Bug introduced by
The property dsParamROOTELEMENT does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
28
29
        $this->dsParamURL = $this->parseParamURL($this->dsParamURL);
0 ignored issues
show
Bug introduced by
The property dsParamURL does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
30
31
        if (isset($this->dsParamXPATH)) {
32
            $this->dsParamXPATH = $this->__processParametersInString($this->dsParamXPATH, $this->_env);
0 ignored issues
show
Bug introduced by
The property dsParamXPATH does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
33
        }
34
35
        $stylesheet = new XMLElement('xsl:stylesheet');
36
        $stylesheet->setAttributeArray(array('version' => '1.0', 'xmlns:xsl' => 'http://www.w3.org/1999/XSL/Transform'));
37
38
        $output = new XMLElement('xsl:output');
39
        $output->setAttributeArray(array('method' => 'xml', 'version' => '1.0', 'encoding' => 'utf-8', 'indent' => 'yes', 'omit-xml-declaration' => 'yes'));
40
        $stylesheet->appendChild($output);
41
42
        $template = new XMLElement('xsl:template');
43
        $template->setAttribute('match', '/');
44
45
        $instruction = new XMLElement('xsl:copy-of');
46
47
        // Namespaces
48
        if (isset($this->dsParamFILTERS) && is_array($this->dsParamFILTERS)) {
49
            foreach ($this->dsParamFILTERS as $name => $uri) {
0 ignored issues
show
Bug introduced by
The property dsParamFILTERS does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
50
                $instruction->setAttribute('xmlns' . ($name ? ":{$name}" : null), $uri);
51
            }
52
        }
53
54
        // XPath
55
        $instruction->setAttribute('select', $this->dsParamXPATH);
56
57
        $template->appendChild($instruction);
58
        $stylesheet->appendChild($template);
59
60
        $stylesheet->setIncludeHeader(true);
61
62
        $xsl = $stylesheet->generate(true);
63
64
        $cache_id = md5($this->dsParamURL . serialize($this->dsParamFILTERS) . $this->dsParamXPATH);
65
66
        $cache = new Cacheable(Symphony::Database());
0 ignored issues
show
Documentation introduced by
\Symphony::Database() is of type object<MySQL>, but the function expects a object<iCache>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
67
68
        $cachedData = $cache->read($cache_id);
69
        $writeToCache = false;
70
        $valid = true;
71
        $creation = DateTimeObj::get('c');
72
        $timeout = (isset($this->dsParamTIMEOUT)) ? (int)max(1, $this->dsParamTIMEOUT) : 6;
0 ignored issues
show
Bug introduced by
The property dsParamTIMEOUT does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
73
74
        // Execute if the cache doesn't exist, or if it is old.
75
        if (
76
            (!is_array($cachedData) || empty($cachedData)) // There's no cache.
77
            || (time() - $cachedData['creation']) > ($this->dsParamCACHE * 60) // The cache is old.
0 ignored issues
show
Bug introduced by
The property dsParamCACHE does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
78
        ) {
79
            if (Mutex::acquire($cache_id, $timeout, TMP)) {
80
                $ch = new Gateway;
81
                $ch->init($this->dsParamURL);
82
                $ch->setopt('TIMEOUT', $timeout);
83
                $ch->setopt('HTTPHEADER', array('Accept: text/xml, */*'));
84
85
                $data = $ch->exec();
86
                $info = $ch->getInfoLast();
87
88
                Mutex::release($cache_id, TMP);
89
90
                $data = trim($data);
91
                $writeToCache = true;
92
93
                // Handle any response that is not a 200, or the content type does not include XML, plain or text
94
                if ((int)$info['http_code'] !== 200 || !preg_match('/(xml|plain|text)/i', $info['content_type'])) {
95
                    $writeToCache = false;
0 ignored issues
show
Unused Code introduced by
$writeToCache 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...
96
97
                    $result->setAttribute('valid', 'false');
98
99
                    // 28 is CURLE_OPERATION_TIMEOUTED
100
                    if ($info['curl_error'] === 28) {
101
                        $result->appendChild(
102
                            new XMLElement('error',
103
                                sprintf('Request timed out. %d second limit reached.', $timeout)
104
                            )
105
                        );
106
                    } else {
107
                        $result->appendChild(
108
                            new XMLElement('error',
109
                                sprintf('Status code %d was returned. Content-type: %s', $info['http_code'], $info['content_type'])
110
                            )
111
                        );
112
                    }
113
114
                    return $result;
115
116
                    // Handle where there is `$data`
117
                } elseif (strlen($data) > 0) {
118
                    // If the XML doesn't validate..
119
                    if (!General::validateXML($data, $errors, false, new XsltProcess)) {
120
                        $writeToCache = false;
121
                    }
122
123
                    // If the `$data` is invalid, return a result explaining why
124
                    if ($writeToCache === false) {
125
                        $element = new XMLElement('errors');
126
127
                        $result->setAttribute('valid', 'false');
128
129
                        $result->appendChild(new XMLElement('error', __('Data returned is invalid.')));
130
131 View Code Duplication
                        foreach ($errors as $e) {
132
                            if (strlen(trim($e['message'])) === 0) {
133
                                continue;
134
                            }
135
136
                            $element->appendChild(new XMLElement('item', General::sanitize($e['message'])));
137
                        }
138
139
                        $result->appendChild($element);
140
141
                        return $result;
142
                    }
143
144
                    // If `$data` is empty, set the `force_empty_result` to true.
145
                } elseif (strlen($data) === 0) {
146
                    $this->_force_empty_result = true;
147
                }
148
149
                // Failed to acquire a lock
150
            } else {
151
                $result->appendChild(
152
                    new XMLElement('error', __('The %s class failed to acquire a lock, check that %s exists and is writable.', array(
153
                        '<code>Mutex</code>',
154
                        '<code>' . TMP . '</code>'
155
                    )))
156
                );
157
            }
158
159
            // The cache is good, use it!
160
        } else {
161
            $data = trim($cachedData['data']);
162
            $creation = DateTimeObj::get('c', $cachedData['creation']);
163
        }
164
165
        // If `$writeToCache` is set to false, invalidate the old cache if it existed.
166
        if (is_array($cachedData) && !empty($cachedData) && $writeToCache === false) {
167
            $data = trim($cachedData['data']);
168
            $valid = false;
169
            $creation = DateTimeObj::get('c', $cachedData['creation']);
170
171
            if (empty($data)) {
172
                $this->_force_empty_result = true;
173
            }
174
        }
175
176
        // If `force_empty_result` is false and `$result` is an instance of
177
        // XMLElement, build the `$result`.
178
        if (!$this->_force_empty_result && is_object($result)) {
179
            $proc = new XsltProcess;
180
            $ret = $proc->process($data, $xsl);
0 ignored issues
show
Bug introduced by
The variable $data does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
181
182
            if ($proc->isErrors()) {
183
                $result->setAttribute('valid', 'false');
184
                $error = new XMLElement('error', __('Transformed XML is invalid.'));
185
                $result->appendChild($error);
186
                $element = new XMLElement('errors');
187
188 View Code Duplication
                foreach ($proc->getError() as $e) {
189
                    if (strlen(trim($e['message'])) === 0) {
190
                        continue;
191
                    }
192
193
                    $element->appendChild(new XMLElement('item', General::sanitize($e['message'])));
194
                }
195
196
                $result->appendChild($element);
197
            } elseif (strlen(trim($ret)) === 0) {
198
                $this->_force_empty_result = true;
199
            } else {
200
                if ($writeToCache) {
201
                    $cache->write($cache_id, $data, $this->dsParamCACHE);
202
                }
203
204
                $result->setValue(PHP_EOL . str_repeat("\t", 2) . preg_replace('/([\r\n]+)/', "$1\t", $ret));
205
                $result->setAttribute('status', ($valid === true ? 'fresh' : 'stale'));
206
                $result->setAttribute('creation', $creation);
0 ignored issues
show
Security Bug introduced by
It seems like $creation can also be of type false; however, XMLElement::setAttribute() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
207
            }
208
        }
209
210
        return $result;
211
    }
212
}
213