Completed
Push — master ( 3a1bf5...e76da6 )
by Aleksandr
01:34
created

Client.php (9 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace carono\rest;
4
5
use function GuzzleHttp\Psr7\build_query;
6
use GuzzleHttp\Client as GuzzleClient;
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\StreamInterface;
9
10
class Client
11
{
12
    public $login;
13
    public $password;
14
    public $proxy;
15
    public $method = 'GET';
16
    public $postDataInBody = false;
17
    public $useAuth = true;
18
19
    /**
20
     * @var ResponseInterface
21
     */
22
    public $request;
23
24
    const TYPE_JSON = 'json';
25
    const TYPE_XML = 'xml';
26
    const TYPE_FORM = 'form';
27
28
    protected $protocol = 'https';
29
    protected $url = '';
30
    protected $type = 'json';
31
    protected $output_type;
32
    protected $_guzzleOptions = [];
33
    protected $_custom_guzzle_options = [];
34
    protected $_guzzle;
35
    protected $_errors;
36
37
    /**
38
     * Client constructor.
39
     *
40
     * @param array $config
41
     */
42
    public function __construct(array $config = [])
43
    {
44
        $this->_guzzle = new GuzzleClient();
45
        foreach ($config as $prop => $value) {
46
            $this->$prop = $value;
47
        }
48
        $this->init();
49
    }
50
51
    public function init()
52
    {
53
        $this->method = strtoupper($this->method);
54
        if (!in_array($this->method, ['GET', 'POST'])) {
55
            $this->method = 'GET';
56
        }
57
    }
58
59
    /**
60
     * @param bool $asString
61
     * @return string
62
     */
63
    public function getError($asString = true)
64
    {
65
        if (!$asString) {
66
            return $this->_errors;
67
        }
68
        $error = ['Ошибка валидации параметров'];
69
        foreach ($this->_errors as $param => $errors) {
70
            $error[] = $param . ' - ' . join('; ', $errors);
71
        }
72
        return join("\n", $error);
73
    }
74
75
    public function validate(array $data)
76
    {
77
        foreach ($data as $param => $value) {
78
            $this->validateParam($param, $value);
0 ignored issues
show
The call to the method carono\rest\Client::validateParam() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
79
        }
80
        return !count($this->_errors);
81
    }
82
83
    /**
84
     * @param array $data
85
     * @return array
86
     */
87
    public function filter(array $data)
88
    {
89
        $result = [];
90
        foreach ($data as $param => $value) {
91
            if (!is_null($filtered = $this->filterParam($param, $value))) {
92
                $result[$param] = $filtered;
93
            }
94
        }
95
        return $result;
96
    }
97
98
    /**
99
     * @param $param
100
     * @param $value
101
     * @return mixed
102
     */
103
    public function filterParam($param, $value)
0 ignored issues
show
The parameter $param is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
104
    {
105
        return $value;
106
    }
107
108
    /**
109
     * @param $param
110
     * @param $value
111
     * @return bool
112
     */
113
    public function validateParam($param, $value)
0 ignored issues
show
The parameter $param is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
114
    {
115
        return true;
116
    }
117
118
    public function setGuzzleOptions($array)
119
    {
120
        $this->_custom_guzzle_options = $array;
121
    }
122
123
    /**
124
     * @param $url
125
     * @return string
126
     */
127
    protected function buildUrl($url)
128
    {
129
        if (strpos($this->url, '://')) {
130
            return $this->url . ($url ? '/' . $url : '');
131
        } else {
132
            return $this->protocol . '://' . $this->url . ($url ? '/' . $url : '');
133
        }
134
    }
135
136
    /**
137
     * @return GuzzleClient
138
     */
139
    public function getGuzzle()
140
    {
141
        return $this->_guzzle;
142
    }
143
144
    /**
145
     * @param $urlRequest
146
     * @param array $data
147
     * @return string|\stdClass|\SimpleXMLElement
148
     */
149
    public function getContent($urlRequest, $data = [])
150
    {
151
        $options = [];
152
        $this->guzzleOptions();
153
        $url = $this->buildUrl($urlRequest);
154
        $client = $this->getGuzzle();
155
        $data = $this->prepareData($data);
156
        if ($this->method == 'GET') {
157
            $url = $url . (strpos($url, '?') ? '&' : '?') . build_query($data);
0 ignored issues
show
It seems like $data defined by $this->prepareData($data) on line 155 can also be of type string; however, GuzzleHttp\Psr7\build_query() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
158
        } elseif ($this->postDataInBody) {
159
            $options = ['body' => $data];
160
        } else {
161
            $options = ['form_params' => $data];
162
        }
163
        $request = $client->request($this->method, $url, array_merge($options, $this->_guzzleOptions));
164
        $this->request = $request;
165
        return $this->unSerialize($request->getBody()->getContents());
166
    }
167
168
    /**
169
     * @param $data
170
     * @return mixed|null|\SimpleXMLElement
171
     */
172
    public function unSerialize($data)
173
    {
174
        $type = $this->output_type ? $this->output_type : $this->type;
175
176
        switch ($type) {
177
            case self::TYPE_JSON:
178
                return \GuzzleHttp\json_decode($data);
179
                break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
180
            case self::TYPE_XML:
181
                return simplexml_load_string($data);
182
                break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
183
        }
184
        return $data;
185
    }
186
187
    /**
188
     * @param $param
189
     * @param $message
190
     */
191
    public function addError($param, $message)
192
    {
193
        $this->_errors[$param][] = $message;
194
    }
195
196
    /**
197
     * @param array $data
198
     * @return array
199
     */
200
    protected function beforePrepareData(array $data)
201
    {
202
        return $data;
203
    }
204
205
    /**
206
     * @param $data
207
     * @return string|array
208
     * @throws \Exception
209
     */
210
    protected function prepareData(array $data)
211
    {
212
        $data = $this->beforePrepareData($data);
213
        $data = $this->filter($data);
214
215
        if (!$this->validate($data)) {
216
            throw new \Exception($this->getError());
217
        }
218
        if ($this->method == 'GET') {
219
            return $data;
220
        }
221
        switch ($this->type) {
222
            case self::TYPE_JSON:
223
                $data = \GuzzleHttp\json_encode($data);
224
                break;
225
            case self::TYPE_XML:
226
                throw new \Exception('Xml type is not implemented yet');
227
                break;
0 ignored issues
show
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
228
            case self::TYPE_FORM:
229
                break;
230
            default:
231
                throw new \Exception('Type is not supported');
232
                break;
0 ignored issues
show
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
233
        }
234
        return $data;
235
    }
236
237
    /**
238
     * @throws \Exception
239
     */
240
    public function guzzleOptions()
241
    {
242
        $options = [
243
            'headers' => []
244
        ];
245
        if ($this->proxy) {
246
            $options['proxy'] = $this->proxy;
247
        }
248
        switch ($this->type) {
249
            case self::TYPE_JSON:
250
                $options['headers']['content-type'] = 'application/json';
251
                break;
252
            case self::TYPE_XML:
253
                $options['headers']['content-type'] = 'application/xml';
254
                break;
255
            case self::TYPE_FORM:
256
                $options['headers']['content-type'] = 'application/x-www-form-urlencoded';
257
                break;
258
259
            default:
260
                throw new \Exception('Type is not supported');
261
        }
262
        if (($this->login || $this->password) && $this->useAuth) {
263
            $options['auth'] = [$this->login, $this->password];
264
        }
265
        $this->_guzzleOptions = array_merge($options, $this->_custom_guzzle_options);
266
    }
267
}