Completed
Push — master ( 868567...3a1bf5 )
by Aleksandr
01:27
created

Client::beforePrepareData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
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
    /**
18
     * @var ResponseInterface
19
     */
20
    public $request;
21
22
    const TYPE_JSON = 'json';
23
    const TYPE_XML = 'xml';
24
    const TYPE_FORM = 'form';
25
26
    protected $protocol = 'https';
27
    protected $url = '';
28
    protected $type = 'json';
29
    protected $output_type;
30
    protected $_guzzleOptions = [];
31
    protected $_custom_guzzle_options = [];
32
    protected $_guzzle;
33
    protected $_errors;
34
35
    /**
36
     * Client constructor.
37
     *
38
     * @param array $config
39
     */
40
    public function __construct(array $config = [])
41
    {
42
        $this->_guzzle = new GuzzleClient();
43
        foreach ($config as $prop => $value) {
44
            $this->$prop = $value;
45
        }
46
        $this->init();
47
    }
48
49
    public function init()
50
    {
51
        $this->method = strtoupper($this->method);
52
        if (!in_array($this->method, ['GET', 'POST'])) {
53
            $this->method = 'GET';
54
        }
55
    }
56
57
    /**
58
     * @param bool $asString
59
     * @return string
60
     */
61
    public function getError($asString = true)
62
    {
63
        if (!$asString) {
64
            return $this->_errors;
65
        }
66
        $error = ['Ошибка валидации параметров'];
67
        foreach ($this->_errors as $param => $errors) {
68
            $error[] = $param . ' - ' . join('; ', $errors);
69
        }
70
        return join("\n", $error);
71
    }
72
73
    public function validate(array $data)
74
    {
75
        foreach ($data as $param => $value) {
76
            $this->validateParam($param, $value);
0 ignored issues
show
Unused Code introduced by
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...
77
        }
78
        return !count($this->_errors);
79
    }
80
81
    /**
82
     * @param array $data
83
     * @return array
84
     */
85
    public function filter(array $data)
86
    {
87
        $result = [];
88
        foreach ($data as $param => $value) {
89
            if (!is_null($filtered = $this->filterParam($param, $value))) {
90
                $result[$param] = $filtered;
91
            }
92
        }
93
        return $result;
94
    }
95
96
    /**
97
     * @param $param
98
     * @param $value
99
     * @return mixed
100
     */
101
    public function filterParam($param, $value)
0 ignored issues
show
Unused Code introduced by
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...
102
    {
103
        return $value;
104
    }
105
106
    /**
107
     * @param $param
108
     * @param $value
109
     * @return bool
110
     */
111
    public function validateParam($param, $value)
0 ignored issues
show
Unused Code introduced by
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...
Unused Code introduced by
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...
112
    {
113
        return true;
114
    }
115
116
    public function setGuzzleOptions($array)
117
    {
118
        $this->_custom_guzzle_options = $array;
119
    }
120
121
    /**
122
     * @param $url
123
     * @return string
124
     */
125
    protected function buildUrl($url)
126
    {
127
        if (strpos($this->url, '://')) {
128
            return $this->url . ($url ? '/' . $url : '');
129
        } else {
130
            return $this->protocol . '://' . $this->url . ($url ? '/' . $url : '');
131
        }
132
    }
133
134
    /**
135
     * @return GuzzleClient
136
     */
137
    public function getGuzzle()
138
    {
139
        return $this->_guzzle;
140
    }
141
142
    /**
143
     * @param $urlRequest
144
     * @param array $data
145
     * @return string|\stdClass|\SimpleXMLElement
146
     */
147
    public function getContent($urlRequest, $data = [])
148
    {
149
        $options = [];
150
        $this->guzzleOptions();
151
        $url = $this->buildUrl($urlRequest);
152
        $client = $this->getGuzzle();
153
        $data = $this->prepareData($data);
154
        if ($this->method == 'GET') {
155
            $url = $url . (strpos($url, '?') ? '&' : '?') . build_query($data);
0 ignored issues
show
Bug introduced by
It seems like $data defined by $this->prepareData($data) on line 153 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...
156
        } elseif ($this->postDataInBody) {
157
            $options = ['body' => $data];
158
        } else {
159
            $options = ['form_params' => $data];
160
        }
161
        $request = $client->request($this->method, $url, array_merge($options, $this->_guzzleOptions));
162
        $this->request = $request;
163
        return $this->unSerialize($request->getBody()->getContents());
164
    }
165
166
    /**
167
     * @param $data
168
     * @return mixed|null|\SimpleXMLElement
169
     */
170
    public function unSerialize($data)
171
    {
172
        $type = $this->output_type ? $this->output_type : $this->type;
173
174
        switch ($type) {
175
            case self::TYPE_JSON:
176
                return \GuzzleHttp\json_decode($data);
177
                break;
0 ignored issues
show
Unused Code introduced by
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...
178
            case self::TYPE_XML:
179
                return simplexml_load_string($data);
180
                break;
0 ignored issues
show
Unused Code introduced by
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...
181
        }
182
        return $data;
183
    }
184
185
    /**
186
     * @param $param
187
     * @param $message
188
     */
189
    public function addError($param, $message)
190
    {
191
        $this->_errors[$param][] = $message;
192
    }
193
194
    /**
195
     * @param array $data
196
     * @return array
197
     */
198
    protected function beforePrepareData(array $data)
199
    {
200
        return $data;
201
    }
202
203
    /**
204
     * @param $data
205
     * @return string|array
206
     * @throws \Exception
207
     */
208
    protected function prepareData(array $data)
209
    {
210
        $data = $this->beforePrepareData($data);
211
        $data = $this->filter($data);
212
213
        if (!$this->validate($data)) {
214
            throw new \Exception($this->getError());
215
        }
216
        if ($this->method == 'GET') {
217
            return $data;
218
        }
219
        switch ($this->type) {
220
            case self::TYPE_JSON:
221
                $data = \GuzzleHttp\json_encode($data);
222
                break;
223
            case self::TYPE_XML:
224
                throw new \Exception('Xml type is not implemented yet');
225
                break;
0 ignored issues
show
Unused Code introduced by
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...
226
            case self::TYPE_FORM:
227
                break;
228
            default:
229
                throw new \Exception('Type is not supported');
230
                break;
0 ignored issues
show
Unused Code introduced by
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...
231
        }
232
        return $data;
233
    }
234
235
    /**
236
     * @throws \Exception
237
     */
238
    public function guzzleOptions()
239
    {
240
        $options = [
241
            'headers' => []
242
        ];
243
        if ($this->proxy) {
244
            $options['proxy'] = $this->proxy;
245
        }
246
        switch ($this->type) {
247
            case self::TYPE_JSON:
248
                $options['headers']['content-type'] = 'application/json';
249
                break;
250
            case self::TYPE_XML:
251
                $options['headers']['content-type'] = 'application/xml';
252
                break;
253
            case self::TYPE_FORM:
254
                $options['headers']['content-type'] = 'application/x-www-form-urlencoded';
255
                break;
256
257
            default:
258
                throw new \Exception('Type is not supported');
259
        }
260
        if ($this->login || $this->password) {
261
            $options['auth'] = [$this->login, $this->password];
262
        }
263
        $this->_guzzleOptions = array_merge($options, $this->_custom_guzzle_options);
264
    }
265
}